From 3dfd9cb95ce45f59160d50975210bc55e3fc0709 Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Thu, 16 Jun 2011 09:00:06 +0200 Subject: [PATCH 0001/1170] Flat commit of all changes from package-management branch in svn --- build/jam/AlternativeGCCArchive | 63 ----- build/jam/BuildSetup | 16 -- build/jam/FloppyBootImage | 30 ++- build/jam/HaikuCD | 7 - build/jam/HaikuImage | 199 +++++++-------- build/jam/ImageRules | 174 +++---------- build/jam/NetBootArchive | 21 +- build/jam/OptionalLibPackages | 11 +- build/jam/OptionalPackages | 228 ++++++++---------- build/jam/UserBuildConfig.ReadMe | 8 - build/jam/UserBuildConfig.sample | 3 - build/scripts/build_haiku_image | 8 +- configure | 28 +-- data/system/boot/SetupEnvironment | 22 +- headers/config/HaikuConfig.h | 11 + headers/os/BeBuild.h | 2 + headers/os/storage/FindDirectory.h | 30 +++ headers/private/libroot/directories.h | 68 ++++++ .../screen_saver/ScreenSaverFilter.cpp | 2 +- .../shortcut_catcher/ParseCommandLine.cpp | 24 +- src/add-ons/kernel/debugger/hangman/hangman.c | 3 +- .../kernel/drivers/audio/ac97/auich/Jamfile | 2 +- .../kernel/drivers/audio/ac97/auich/debug.c | 14 +- .../kernel/drivers/audio/ac97/auvia/Jamfile | 2 +- .../kernel/drivers/audio/ac97/auvia/debug.c | 14 +- .../kernel/drivers/audio/ac97/es1370/Jamfile | 2 +- .../kernel/drivers/audio/ac97/es1370/debug.c | 14 +- .../kernel/drivers/audio/ac97/ich/Jamfile | 2 +- .../kernel/drivers/audio/ac97/ich/debug.c | 14 +- .../kernel/drivers/audio/echo/24/Jamfile | 2 +- .../kernel/drivers/audio/echo/3g/Jamfile | 2 +- src/add-ons/kernel/drivers/audio/echo/debug.c | 14 +- .../kernel/drivers/audio/echo/gals/Jamfile | 2 +- .../kernel/drivers/audio/echo/indigo/Jamfile | 2 +- .../kernel/drivers/audio/emuxki/Jamfile | 2 +- .../kernel/drivers/audio/emuxki/debug.c | 14 +- .../drivers/audio/module_driver/Jamfile | 2 +- .../audio/module_driver/audio_module_driver.c | 35 ++- .../kernel/drivers/graphics/matrox/Jamfile | 2 +- .../kernel/drivers/graphics/matrox/driver.c | 3 +- .../kernel/drivers/graphics/neomagic/Jamfile | 2 +- .../kernel/drivers/graphics/neomagic/driver.c | 4 +- .../kernel/drivers/graphics/nvidia/Jamfile | 2 +- .../kernel/drivers/graphics/nvidia/driver.c | 3 +- .../drivers/graphics/nvidia_gpgpu/Jamfile | 2 +- .../drivers/graphics/nvidia_gpgpu/driver.c | 3 +- .../kernel/drivers/graphics/skeleton/Jamfile | 2 +- .../kernel/drivers/graphics/skeleton/driver.c | 4 +- .../kernel/drivers/graphics/via/Jamfile | 2 +- .../kernel/drivers/graphics/via/driver.c | 4 +- .../kernel/drivers/network/sis900/Jamfile | 2 +- .../kernel/drivers/network/sis900/device.c | 4 +- .../network/wimax/usb_beceemwmx/Driver.h | 7 +- .../network/wimax/usb_beceemwmx/Jamfile | 2 +- .../kernel/drivers/ports/pc_serial/Jamfile | 1 + .../drivers/ports/pc_serial/Tracing.cpp | 5 +- .../kernel/drivers/ports/usb_serial/Jamfile | 1 + .../drivers/ports/usb_serial/Tracing.cpp | 3 +- .../kernel/drivers/video/usb_vision/Jamfile | 2 +- .../kernel/drivers/video/usb_vision/tracing.c | 4 +- .../userlandfs/kernel_add_on/Jamfile | 2 +- .../userlandfs/shared/driver_settings.c | 3 +- src/add-ons/kernel/generic/mpu401/Jamfile | 2 + src/add-ons/kernel/generic/mpu401/debug.c | 19 +- .../network/ppp/shared/libkernelppp/Jamfile | 2 +- .../ppp/shared/libkernelppp/headers/PPPDefs.h | 6 +- src/apps/aboutsystem/AboutSystem.cpp | 24 +- src/apps/deskbar/BarApp.cpp | 8 +- src/apps/deskbar/BarMenuBar.cpp | 22 +- src/apps/deskbar/BarMenuBar.h | 2 +- src/apps/deskbar/BarMenuTitle.cpp | 4 +- src/apps/deskbar/BarView.cpp | 26 +- src/apps/deskbar/BarView.h | 6 +- src/apps/deskbar/BarWindow.cpp | 40 +-- src/apps/deskbar/BarWindow.h | 10 +- .../deskbar/{BeMenu.cpp => DeskbarMenu.cpp} | 51 ++-- src/apps/deskbar/{BeMenu.h => DeskbarMenu.h} | 14 +- .../{DeskBarUtils.cpp => DeskbarUtils.cpp} | 4 +- .../{DeskBarUtils.h => DeskbarUtils.h} | 2 +- src/apps/deskbar/ExpandoMenuBar.cpp | 39 +-- src/apps/deskbar/ExpandoMenuBar.h | 8 +- src/apps/deskbar/Jamfile | 6 +- src/apps/deskbar/StatusView.cpp | 2 +- src/apps/deskbar/TeamMenu.cpp | 2 +- src/apps/processcontroller/PCWorld.cpp | 14 +- .../processcontroller/ProcessController.cpp | 34 ++- src/apps/remotedesktop/RemoteDesktop.cpp | 16 +- src/bin/bash/config-top.h | 5 +- src/bin/bash/pathnames.h | 3 +- src/bin/debug/profile/profile.cpp | 10 +- src/bin/finddir.c | 30 +++ src/bin/package/command_list.cpp | 4 +- src/kits/app/Roster.cpp | 14 +- src/kits/locale/MutableLocaleRoster.cpp | 6 +- src/kits/opengl/GLRendererRoster.cpp | 6 +- src/kits/package/PackageInfo.cpp | 199 +++++++++------ src/kits/print/PrintTransport.cpp | 21 +- src/kits/print/Printer.cpp | 13 +- src/kits/print/PrinterDriverAddOn.cpp | 12 +- src/kits/screensaver/ScreenSaverRunner.cpp | 9 +- .../storage/disk_device/DiskDeviceRoster.cpp | 4 +- .../disk_device/DiskSystemAddOnManager.cpp | 13 +- src/kits/tracker/ContainerWindow.cpp | 9 +- src/kits/tracker/DeskWindow.cpp | 4 +- src/kits/translation/TranslatorRoster.cpp | 6 +- src/libs/print/libgutenprint/config.h | 4 +- src/libs/print/libprint/Transport.cpp | 23 +- src/preferences/printers/AddPrinterDialog.cpp | 6 +- .../screensaver/ScreenSaverWindow.cpp | 9 +- src/servers/app/Desktop.cpp | 9 +- .../app/drawing/AccelerantHWInterface.cpp | 6 +- .../app/drawing/DWindowHWInterface.cpp | 6 +- src/servers/debug/DebugServer.cpp | 54 ++++- src/servers/index/IndexServer.cpp | 8 +- src/servers/input/AddOnManager.cpp | 8 +- src/servers/media/AddOnManager.cpp | 8 +- src/servers/media_addon/MediaAddonServer.cpp | 8 +- src/servers/print/PrintServerApp.cpp | 4 +- src/servers/registrar/TRoster.cpp | 11 +- src/servers/registrar/TRoster.h | 3 + src/system/boot/loader/loader.cpp | 13 +- src/system/kernel/fs/vfs_boot.cpp | 11 +- src/system/kernel/main.cpp | 4 +- src/system/kernel/team.cpp | 2 +- src/system/libroot/os/driver_settings.cpp | 5 +- src/system/libroot/os/find_directory.cpp | 121 ++++++++-- src/system/libroot/posix/unistd/conf.cpp | 5 +- src/system/runtime_loader/Jamfile | 2 +- src/system/runtime_loader/runtime_loader.cpp | 43 ++-- src/tests/add-ons/print/transports/main.cpp | 2 + .../kits/translation/TranslationUtilsTest.cpp | 3 +- .../kits/translation/TranslatorRosterTest.cpp | 3 +- .../drawing/AccelerantHWInterface.cpp | 6 +- .../translation/inspector/InspectorApp.cpp | 3 +- 134 files changed, 1284 insertions(+), 1003 deletions(-) delete mode 100644 build/jam/AlternativeGCCArchive create mode 100644 headers/private/libroot/directories.h rename src/apps/deskbar/{BeMenu.cpp => DeskbarMenu.cpp} (93%) rename src/apps/deskbar/{BeMenu.h => DeskbarMenu.h} (93%) rename src/apps/deskbar/{DeskBarUtils.cpp => DeskbarUtils.cpp} (96%) rename src/apps/deskbar/{DeskBarUtils.h => DeskbarUtils.h} (96%) diff --git a/build/jam/AlternativeGCCArchive b/build/jam/AlternativeGCCArchive deleted file mode 100644 index 5a7827f131..0000000000 --- a/build/jam/AlternativeGCCArchive +++ /dev/null @@ -1,63 +0,0 @@ -# This file defines what ends up in the alternative GCC archive and it executes -# the rules building the archive. Included by HaikuImage. - - -#sanity check - make sure the primary gcc is different than the alternative gcc -if $(HAIKU_PRIMARY_GCC) = $(HAIKU_GCC_VERSION[1]) { - Exit "Error: Your alternative gcc is the same as the main gcc!" - "You need to reconfigure your generated directories." ; -} - -#pragma mark - Build The Archive - - -# archive target -HAIKU_ALTERNATIVE_GCC_ARCHIVE = alternative_system_libs.zip ; -MakeLocate $(HAIKU_ALTERNATIVE_GCC_ARCHIVE) : $(HAIKU_OUTPUT_DIR) ; - -# the pseudo target all archive contents is attached to -NotFile $(HAIKU_ALTERNATIVE_GCC_ARCHIVE_CONTAINER_NAME) ; - -# prepare the script that initializes the shell variables -local initVarsScript = haiku-alternative-gcc-init-vars ; -local script = $(initVarsScript) ; -MakeLocate $(script) : $(HAIKU_OUTPUT_DIR) ; -Always $(script) ; - -AddVariableToScript $(script) : tmpDir : $(HAIKU_TMP_DIR) ; -AddVariableToScript $(script) : addBuildCompatibilityLibDir - : $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) ; -AddTargetVariableToScript $(script) : copyattr ; -AddTargetVariableToScript $(script) : zip ; -if $(HOST_RM_ATTRS_TARGET) { - AddTargetVariableToScript $(script) : $(HOST_RM_ATTRS_TARGET) : rmAttrs ; -} else { - AddVariableToScript $(script) : rmAttrs : rm ; -} - -# create the other scripts -local makeDirsScript = haiku-alternative-gcc-make-dirs ; -local copyFilesScript - = haiku-alternative-gcc-copy-files ; -MakeLocate $(makeDirsScript) $(copyFilesScript) : $(HAIKU_OUTPUT_DIR) ; - -CreateAlternativeGCCArchiveMakeDirectoriesScript $(makeDirsScript) ; -CreateAlternativeGCCArchiveCopyFilesScript $(copyFilesScript) ; - -# build the archive - -BuildAlternativeGCCArchive $(HAIKU_ALTERNATIVE_GCC_ARCHIVE) : - $(initVarsScript) - $(makeDirsScript) - $(copyFilesScript) -; - -# remove the scripts we have generated -RmTemps $(HAIKU_ALTERNATIVE_GCC_ARCHIVE) : - $(initVarsScript) - $(makeDirsScript) - $(copyFilesScript) -; - -NotFile haiku-alternative-gcc-archive ; -Depends haiku-alternative-gcc-archive : $(HAIKU_ALTERNATIVE_GCC_ARCHIVE) ; diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index 5099d523c2..59f816336e 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -29,15 +29,6 @@ HAIKU_CONTAINER_GRIST on $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME) HAIKU_INSTALL_TARGETS_VAR on $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME) = HAIKU_NET_BOOT_ARCHIVE_INSTALL_TARGETS ; -# alternative gcc archive -HAIKU_ALTERNATIVE_GCC_ARCHIVE_CONTAINER_NAME - = haiku-alternative-gcc-archive-container ; -HAIKU_CONTAINER_GRIST on $(HAIKU_ALTERNATIVE_GCC_ARCHIVE_CONTAINER_NAME) - = AlternativeGCCArchive ; -# HAIKU_INCLUDE_IN_CONTAINER_VAR -- update only mode not supported -HAIKU_INSTALL_TARGETS_VAR on $(HAIKU_ALTERNATIVE_GCC_ARCHIVE_CONTAINER_NAME) - = HAIKU_ALTERNATIVE_GCC_ARCHIVE_INSTALL_TARGETS ; - # boot floppy HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME = haiku-boot-floppy-container ; HAIKU_CONTAINER_GRIST on $(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME) @@ -151,13 +142,6 @@ if $(HAIKU_GCC_VERSION[1]) = 2 { HAIKU_GCC_HEADERS_DIR = [ FDirName $(HAIKU_TOP) headers build gcc-2.95.3 ] ; } -# the subdirectory into which the alternative GCC libraries are to be installed -if $(HAIKU_GCC_VERSION[1]) = 2 { - HAIKU_ALTERNATIVE_GCC_LIB_SUBDIR = gcc2 ; -} else { - HAIKU_ALTERNATIVE_GCC_LIB_SUBDIR = gcc4 ; -} - # initial state for flags etc. HAIKU_C++ ?= $(HAIKU_CC) ; HAIKU_LINK = $(HAIKU_CC) ; diff --git a/build/jam/FloppyBootImage b/build/jam/FloppyBootImage index ea05ca505b..a0f0c11b00 100644 --- a/build/jam/FloppyBootImage +++ b/build/jam/FloppyBootImage @@ -59,23 +59,28 @@ AddFilesToFloppyBootArchive system add-ons kernel busses ide : generic_ide_pci $(X86_ONLY)ide_isa silicon_image_3112 legacy_sata it8211 ; AddFilesToFloppyBootArchive system add-ons kernel busses scsi : ahci ; -AddFilesToFloppyBootArchive system add-ons kernel console : vga_text ; +AddFilesToFloppyBootArchive system add-ons kernel console + : vga_text ; AddFilesToFloppyBootArchive system add-ons kernel file_systems : $(SYSTEM_ADD_ONS_FILE_SYSTEMS) ; AddFilesToFloppyBootArchive system add-ons kernel generic : $(ATA_ONLY)ata_adapter $(IDE_ONLY)ide_adapter locked_pool scsi_periph ; -AddFilesToFloppyBootArchive system add-ons kernel partitioning_systems +AddFilesToFloppyBootArchive + system add-ons kernel partitioning_systems : intel session ; -AddFilesToFloppyBootArchive system add-ons kernel interrupt_controllers +AddFilesToFloppyBootArchive + system add-ons kernel interrupt_controllers : $(PPC_ONLY)openpic ; if $(USB_BOOT) = 1 { - AddFilesToFloppyBootArchive system add-ons kernel busses usb + AddFilesToFloppyBootArchive + system add-ons kernel busses usb : uhci ohci ehci ; } if $(TARGET_ARCH) = x86 { - AddFilesToFloppyBootArchive system add-ons kernel cpu : generic_x86 ; + AddFilesToFloppyBootArchive system add-ons kernel cpu + : generic_x86 ; } # drivers @@ -89,7 +94,8 @@ if $(NET_BOOT) = 1 { } # kernel -AddFilesToFloppyBootArchive system : kernel_$(TARGET_ARCH) ; +AddFilesToFloppyBootArchive system + : kernel_$(TARGET_ARCH) ; # scripts and data files @@ -103,13 +109,17 @@ if $(NET_BOOT) = 1 { # add-ons AddFilesToFloppyBootArchive system add-ons kernel network : stack socket ; - AddFilesToFloppyBootArchive system add-ons kernel network devices + AddFilesToFloppyBootArchive + system add-ons kernel network devices : $(SYSTEM_NETWORK_DEVICES) ; - AddFilesToFloppyBootArchive system add-ons kernel network datalink_protocols + AddFilesToFloppyBootArchive + system add-ons kernel network datalink_protocols : $(SYSTEM_NETWORK_DATALINK_PROTOCOLS) ; - AddFilesToFloppyBootArchive system add-ons kernel network ppp + AddFilesToFloppyBootArchive + system add-ons kernel network ppp : $(SYSTEM_NETWORK_PPP) ; - AddFilesToFloppyBootArchive system add-ons kernel network protocols + AddFilesToFloppyBootArchive + system add-ons kernel network protocols : $(SYSTEM_NETWORK_PROTOCOLS) ; } diff --git a/build/jam/HaikuCD b/build/jam/HaikuCD index e88ba3bf90..25a49eb59c 100644 --- a/build/jam/HaikuCD +++ b/build/jam/HaikuCD @@ -8,13 +8,6 @@ HAIKU_CD = $(HAIKU_CD_NAME) ; HAIKU_CD_LABEL ?= $(HAIKU_DEFAULT_CD_LABEL) ; MakeLocate $(HAIKU_CD) : $(HAIKU_CD_DIR) ; -# Detect a hybrid GCC2/GCC4 image. -local isHybridBuild ; -if $(HAIKU_ADD_ALTERNATIVE_GCC_LIBS) = 1 - && $(HAIKU_ALTERNATIVE_GCC_OUTPUT_DIR) { - isHybridBuild = 1 ; -} - # prepare the script that initializes the shell variables HAIKU_CD_INIT_VARIABLES_SCRIPT = haiku.cd-init-vars ; local script = $(HAIKU_CD_INIT_VARIABLES_SCRIPT) ; diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index c5a8b0366b..6ab711fe84 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -47,14 +47,14 @@ SYSTEM_BIN = "[" addattr alert arp base64 basename bash bc beep bzip2 mkfifo mkfs mkindex mktemp modifiers mount mount_nfs mountvolume mv netcat netstat nl nohup notify nproc od open - passwd paste patch pathchk pc ping ping6 play playfile playsound playwav - pr prio printenv printf profile ps ptx pwd + package package_repo passwd paste patch pathchk pc ping ping6 pkgman play + playfile playsound playwav pr prio printenv printf profile ps ptx pwd query quit rc readlink ReadOnlyBootPrompt reindex release renice rlog rm rmattr rmindex rmdir roster route safemode screen_blanker screenmode screenshot sdiff setdecor settype - setversion setvolume seq sha1sum shar shred shuf shutdown sleep sort - spamdbm + setversion setvolume seq sha1sum sha256sum shar shred shuf shutdown sleep + sort spamdbm split stat strace stty su sum sync sysinfo tac tail tcpdump tcptester tee telnet telnetd test timeout top touch tput tr traceroute translate trash true truncate tsort tty @@ -89,8 +89,8 @@ SYSTEM_LIBS = liblocale.so libmail.so libmedia.so libmidi.so libmidi2.so libnetwork.so - libpng.so - libroot.so libroot-addon-icu.so + libpackage.so libpng.so + libroot.so libscreensaver.so libtextencoding.so libtiff.so libtracker.so libtranslation.so libz.so @@ -101,6 +101,7 @@ PRIVATE_SYSTEM_LIBS = libfluidsynth.so libilmimf.so liblpsolve55.so + libroot-addon-icu.so ; SYSTEM_SERVERS = app_server cddb_daemon debug_server input_server mail_daemon media_addon_server media_server midi_server mount_server net_server @@ -190,8 +191,8 @@ SYSTEM_ADD_ONS_DRIVERS_NET = $(X86_ONLY)3com $(X86_ONLY)atheros813x SYSTEM_ADD_ONS_BUS_MANAGERS = $(ATA_ONLY)ata pci $(X86_ONLY)ps2 $(X86_ONLY)isa $(IDE_ONLY)ide scsi config_manager agp_gart usb firewire $(X86_ONLY)acpi ; -SYSTEM_ADD_ONS_FILE_SYSTEMS = bfs btrfs cdda exfat ext2 fat iso9660 nfs - attribute_overlay write_overlay ntfs reiserfs udf googlefs ; +SYSTEM_ADD_ONS_FILE_SYSTEMS = bfs bindfs btrfs cdda exfat ext2 fat iso9660 nfs + attribute_overlay write_overlay ntfs packagefs reiserfs udf googlefs ; # wifi firmware for driver in $(SYSTEM_ADD_ONS_DRIVERS_NET) { @@ -232,7 +233,8 @@ AddFilesToHaikuImage system add-ons kernel busses scsi : ahci ; AddFilesToHaikuImage system add-ons kernel busses usb : uhci ohci ehci ; -AddFilesToHaikuImage system add-ons kernel console : vga_text ; +AddFilesToHaikuImage system add-ons kernel console + : vga_text ; AddFilesToHaikuImage system add-ons kernel debugger : demangle $(X86_ONLY)disasm invalidate_on_exit usb_keyboard run_on_exit ; @@ -241,13 +243,16 @@ AddFilesToHaikuImage system add-ons kernel file_systems AddFilesToHaikuImage system add-ons kernel generic : $(ATA_ONLY)ata_adapter dpc $(IDE_ONLY)ide_adapter locked_pool mpu401 scsi_periph tty ; -AddFilesToHaikuImage system add-ons kernel partitioning_systems +AddFilesToHaikuImage + system add-ons kernel partitioning_systems : amiga_rdb apple efi_gpt intel session ; -AddFilesToHaikuImage system add-ons kernel interrupt_controllers +AddFilesToHaikuImage + system add-ons kernel interrupt_controllers : $(PPC_ONLY)openpic ; if $(TARGET_ARCH) = x86 { - AddFilesToHaikuImage system add-ons kernel cpu : generic_x86 ; + AddFilesToHaikuImage system add-ons kernel cpu + : generic_x86 ; } # drivers @@ -276,10 +281,11 @@ AddDriversToHaikuImage ports : usb_serial ; #AddDriversToHaikuImage power : $(SYSTEM_ADD_ONS_DRIVERS_POWER) ; # kernel -AddFilesToHaikuImage system : kernel_$(TARGET_ARCH) ; +AddFilesToHaikuImage system + : kernel_$(TARGET_ARCH) ; # libs -AddLibrariesToHaikuHybridImage system lib +AddLibrariesToHaikuImage system lib : $(SYSTEM_LIBS) $(PRIVATE_SYSTEM_LIBS) ; # libnetwork.so replaces quite a few libraries @@ -289,12 +295,12 @@ SYSTEM_LIBS_LIBNETWORK_ALIASES if $(HAIKU_GCC_VERSION[1]) = 2 { local lib ; for lib in $(SYSTEM_LIBS_LIBNETWORK_ALIASES) { - AddSymlinkToHaikuHybridImage system lib : libnetwork.so : $(lib) - : : true ; + AddSymlinkToHaikuImage system lib + : libnetwork.so : $(lib) ; } - AddSymlinkToHaikuHybridImage system lib : libbnetapi.so : libnetapi.so - : : true ; + AddSymlinkToHaikuImage system lib : libbnetapi.so + : libnetapi.so ; } @@ -305,7 +311,8 @@ SYSTEM_LIBS_LIBGL_ALIASES if $(TARGET_ARCH) = x86 { local lib ; for lib in $(SYSTEM_LIBS_LIBGL_ALIASES) { - AddSymlinkToHaikuHybridImage system lib : libGL.so : $(lib) : : true ; + AddSymlinkToHaikuImage system lib + : libGL.so : $(lib) ; } } @@ -319,10 +326,12 @@ SYSTEM_LIBS_ALIASES = AddFilesToHaikuImage system servers : $(SYSTEM_SERVERS) ; # apps -AddFilesToHaikuImage system : runtime_loader Deskbar Tracker ; +AddFilesToHaikuImage system : runtime_loader ; +AddFilesToHaikuImage system : Deskbar Tracker ; AddFilesToHaikuImage system bin : $(SYSTEM_BIN) consoled ; AddFilesToHaikuImage system apps : $(SYSTEM_APPS) ; -AddFilesToHaikuImage system preferences : $(SYSTEM_PREFERENCES) ; +AddFilesToHaikuImage system preferences + : $(SYSTEM_PREFERENCES) ; AddFilesToHaikuImage system demos : $(SYSTEM_DEMOS) ; SEARCH on which = [ FDirName $(HAIKU_TOP) data bin ] ; @@ -330,15 +339,18 @@ AddFilesToHaikuImage system bin : which ; SEARCH on installoptionalpackage = [ FDirName $(HAIKU_TOP) data bin ] ; AddFilesToHaikuImage system bin : installoptionalpackage ; SEARCH on install-wifi-firmwares.sh = [ FDirName $(HAIKU_TOP) data bin ] ; -AddFilesToHaikuImage system bin : install-wifi-firmwares.sh ; +AddFilesToHaikuImage system bin + : install-wifi-firmwares.sh ; +# TODO: remove! # Add the files to be used by installoptionalpackage. AddDirectoryToHaikuImage common data optional-packages ; local optional-pkg-files = OptionalBuildFeatures OptionalPackageDependencies OptionalPackages OptionalLibPackages ; for name in $(optional-pkg-files) { local file = [ FDirName $(HAIKU_TOP) build jam $(name) ] ; - AddFilesToHaikuImage common data optional-packages : $(file) ; + AddFilesToHaikuImage common data optional-packages + : $(file) ; } AddInstalledPackagesFileToHaikuImage ; @@ -352,8 +364,9 @@ AddDirectoryToHaikuImage home mail draft ; AddDirectoryToHaikuImage home mail in ; AddDirectoryToHaikuImage home mail out ; +AddSymlinkToHaikuImage home config settings : deskbar : be ; # Deskbar Application links -AddDirectoryToHaikuImage home config be Applications ; +AddDirectoryToHaikuImage home config settings deskbar Applications ; DESKBAR_APPLICATIONS = ActivityMonitor CharacterMap CodyCam CDPlayer DeskCalc Devices DiskProbe DriveSetup DiskUsage Expander Icon-O-Matic Installer Magnify Mail MediaConverter MediaPlayer MidiPlayer People PoorMan @@ -361,32 +374,33 @@ DESKBAR_APPLICATIONS = ActivityMonitor CharacterMap CodyCam CDPlayer DeskCalc ; local linkTarget ; for linkTarget in $(DESKBAR_APPLICATIONS) { - AddSymlinkToHaikuImage home config be Applications + AddSymlinkToHaikuImage home config settings deskbar Applications : /boot/system/apps/$(linkTarget) : $(linkTarget) ; } # Deskbar Desktop applets links -AddDirectoryToHaikuImage home config be Desktop\ applets ; +AddDirectoryToHaikuImage home config settings deskbar Desktop\ applets ; DESKBAR_DESKTOP_APPLETS = LaunchBox NetworkStatus PowerStatus ProcessController Workspaces ; for linkTarget in $(DESKBAR_DESKTOP_APPLETS) { - AddSymlinkToHaikuImage home config be Desktop\ applets + AddSymlinkToHaikuImage home config settings deskbar Desktop\ applets : /boot/system/apps/$(linkTarget) : $(linkTarget) ; } # Deskbar Preferences links -AddDirectoryToHaikuImage home config be Preferences ; +AddDirectoryToHaikuImage home config settings deskbar Preferences ; DESKBAR_PREFERENCES = $(SYSTEM_PREFERENCES:B) ; for linkTarget in $(DESKBAR_PREFERENCES) { - AddSymlinkToHaikuImage home config be Preferences - : /boot/system/preferences/$(linkTarget) : $(linkTarget) ; + AddSymlinkToHaikuImage home config settings deskbar Preferences + : /boot/system/preferences/$(linkTarget) + : $(linkTarget) ; } # Deskbar Demo links -AddDirectoryToHaikuImage home config be Demos ; +AddDirectoryToHaikuImage home config settings deskbar Demos ; for linkTarget in $(SYSTEM_DEMOS) { - AddSymlinkToHaikuImage home config be Demos + AddSymlinkToHaikuImage home config settings deskbar Demos : /boot/system/demos/$(linkTarget) : $(linkTarget) ; } @@ -431,14 +445,15 @@ local spellFiles = words geekspeak ; spellFiles = $(spellFiles:G=spell) ; SEARCH on $(spellFiles) = [ FDirName $(HAIKU_TOP) src apps mail ] ; -AddFilesToHaikuImage system data spell_check word_dictionary : $(spellFiles) ; +AddFilesToHaikuImage system data spell_check word_dictionary + : $(spellFiles) ; local etcDir = [ FDirName $(HAIKU_TOP) data etc ] ; local etcFiles = inputrc profile ; etcFiles = $(etcFiles:G=etc) ; SEARCH on $(etcFiles) = [ FDirName $(etcDir) ] ; etcFiles += termcap sysless sysless.in ; -AddFilesToHaikuImage common etc : $(etcFiles) ; +AddFilesToHaikuImage common settings etc : $(etcFiles) ; local profileFiles = [ Glob $(etcDir)/profile.d : *.sh ] ; profileFiles = $(profileFiles:G=profile-d) ; @@ -477,9 +492,11 @@ local cannaDefault = [ Glob $(cannaDir)/default : *.canna *.gz ] ; local cannaDic = [ Glob $(cannaDir)/dic : *.cbp ] ; local cannaDicCanna = [ Glob $(cannaDir)/dic/canna : *.cld *.ctd *.cbd *.dir ] ; -AddFilesToHaikuImage system data Canna default : $(cannaDefault) ; +AddFilesToHaikuImage system data Canna default + : $(cannaDefault) ; AddFilesToHaikuImage system data Canna dic : $(cannaDic) ; -AddFilesToHaikuImage system data Canna dic canna : $(cannaDicCanna) ; +AddFilesToHaikuImage system data Canna dic canna + : $(cannaDicCanna) ; AddDirectoryToHaikuImage system data Canna dic group ; AddDirectoryToHaikuImage system data Canna dic user ; @@ -487,14 +504,18 @@ local keymapFiles = [ Glob [ FDirName $(HAIKU_TOP) src data keymaps ] : *.keymap ] ; keymapFiles = $(keymapFiles:BG=keymap) ; AddFilesToHaikuImage system data Keymaps : $(keymapFiles) ; -AddSymlinkToHaikuImage system data Keymaps : Swedish : Finnish ; -AddSymlinkToHaikuImage system data Keymaps : Slovene : Croatian ; -AddSymlinkToHaikuImage system data Keymaps : US-International : Brazilian ; +AddSymlinkToHaikuImage system data Keymaps : Swedish + : Finnish ; +AddSymlinkToHaikuImage system data Keymaps : Slovene + : Croatian ; +AddSymlinkToHaikuImage system data Keymaps : US-International + : Brazilian ; local keyboardLayoutsDir = [ FDirName $(HAIKU_TOP) data system data KeyboardLayouts ] ; local keyboardLayouts = [ Glob $(keyboardLayoutsDir) : [^.]* ] ; -AddFilesToHaikuImage system data KeyboardLayouts : $(keyboardLayouts) ; +AddFilesToHaikuImage system data KeyboardLayouts + : $(keyboardLayouts) ; local driverSettingsFiles = kernel ; SEARCH on $(driverSettingsFiles) @@ -515,7 +536,8 @@ SEARCH on $(postInstallFiles) = [ FDirName $(HAIKU_TOP) data common boot post_install ] ; SEARCH on fresh_install = [ FDirName $(HAIKU_TOP) data common settings ] ; -AddFilesToHaikuImage common boot post_install : $(postInstallFiles) ; +AddFilesToHaikuImage common boot post_install + : $(postInstallFiles) ; AddFilesToHaikuImage common settings : fresh_install ; # boot loader @@ -538,20 +560,27 @@ AddBootModuleSymlinksToHaikuImage # add-ons AddFilesToHaikuImage system add-ons accelerants : $(SYSTEM_ADD_ONS_ACCELERANTS) ; -AddFilesToHaikuHybridImage system add-ons opengl - : Mesa\ Software\ Renderer : : true ; -AddFilesToHaikuHybridImage system add-ons Translators - : $(SYSTEM_ADD_ONS_TRANSLATORS) : : true ; +AddFilesToHaikuImage system add-ons opengl + : Mesa\ Software\ Renderer ; +AddFilesToHaikuImage system add-ons Translators + : $(SYSTEM_ADD_ONS_TRANSLATORS) ; AddFilesToHaikuImage system add-ons locale catalogs : $(SYSTEM_ADD_ONS_LOCALE_CATALOGS) ; -AddFilesToHaikuHybridImage system add-ons locale catalogs - : $(SYSTEM_ADD_ONS_LOCALE_CATALOGS) : : true ; -AddFilesToHaikuImage system add-ons mail_daemon inbound_protocols : POP3 IMAP ; -AddFilesToHaikuImage system add-ons mail_daemon outbound_protocols : SMTP ; -AddFilesToHaikuImage system add-ons mail_daemon inbound_filters +AddFilesToHaikuImage system add-ons locale catalogs + : $(SYSTEM_ADD_ONS_LOCALE_CATALOGS) ; +AddFilesToHaikuImage + system add-ons mail_daemon inbound_protocols + : POP3 IMAP ; +AddFilesToHaikuImage + system add-ons mail_daemon outbound_protocols : SMTP ; +AddFilesToHaikuImage + system add-ons mail_daemon inbound_filters : MatchHeader SpamFilter NewMailNotification ; -AddFilesToHaikuImage system add-ons mail_daemon outbound_filters : Fortune ; -AddFilesToHaikuImage system add-ons media : $(SYSTEM_ADD_ONS_MEDIA) ; +AddFilesToHaikuImage + system add-ons mail_daemon outbound_filters + : Fortune ; +AddFilesToHaikuImage system add-ons media + : $(SYSTEM_ADD_ONS_MEDIA) ; AddFilesToHaikuImage system add-ons media plugins : $(SYSTEM_ADD_ONS_MEDIA_PLUGINS) ; AddFilesToHaikuImage system add-ons Tracker @@ -571,13 +600,15 @@ AddFilesToHaikuImage system add-ons kernel network : notifications stack ; AddFilesToHaikuImage system add-ons kernel network devices : $(SYSTEM_NETWORK_DEVICES) ; -AddFilesToHaikuImage system add-ons kernel network datalink_protocols +AddFilesToHaikuImage + system add-ons kernel network datalink_protocols : $(SYSTEM_NETWORK_DATALINK_PROTOCOLS) ; AddFilesToHaikuImage system add-ons kernel network ppp : $(SYSTEM_NETWORK_PPP) ; AddFilesToHaikuImage system add-ons kernel network protocols : $(SYSTEM_NETWORK_PROTOCOLS) ; -AddFilesToHaikuImage system add-ons Print : $(SYSTEM_ADD_ONS_PRINT) ; +AddFilesToHaikuImage system add-ons Print + : $(SYSTEM_ADD_ONS_PRINT) ; AddFilesToHaikuImage system add-ons Print transport : $(SYSTEM_ADD_ONS_PRINT_TRANSPORT) ; AddFilesToHaikuImage system add-ons Screen\ Savers @@ -593,15 +624,17 @@ AddFilesToHaikuImage home config add-ons decorators : # create directories that will remain empty AddDirectoryToHaikuImage common bin ; -AddDirectoryToHaikuImage common include ; +AddDirectoryToHaikuImage common cache tmp ; +AddDirectoryToHaikuImage common develop headers ; AddDirectoryToHaikuImage common lib ; +AddDirectoryToHaikuImage common non-packaged ; +AddDirectoryToHaikuImage common var empty ; +AddDirectoryToHaikuImage common var log ; AddDirectoryToHaikuImage home Desktop ; AddDirectoryToHaikuImage home config bin ; AddDirectoryToHaikuImage home config lib ; +AddDirectoryToHaikuImage home config non-packaged ; AddDirectoryToHaikuImage home mail ; -AddDirectoryToHaikuImage common var empty ; -AddDirectoryToHaikuImage common var log ; -AddDirectoryToHaikuImage common cache tmp ; AddDirectoryToHaikuImage home config add-ons kernel drivers bin ; AddDirectoryToHaikuImage home config add-ons kernel drivers dev ; @@ -688,49 +721,6 @@ if $(HAIKU_IMAGE_OPTIONAL_PACKAGE_DESCRIPTIONS) { } -#pragma mark - Alternative GCC Libraries - - -# We build a zip archive containing the libraries built with the alternative -# GCC and unzip onto our image. Building the archive is done by a sub-jam. -include [ FDirName $(HAIKU_BUILD_RULES_DIR) AlternativeGCCArchive ] ; - -if $(HAIKU_ADD_ALTERNATIVE_GCC_LIBS) = 1 - && $(HAIKU_ALTERNATIVE_GCC_OUTPUT_DIR) { - # let another jam build a zip with the system libraries - rule InvokeSubJam target : directory : jamLine - { - DIRECTORY on $(target) = $(directory) ; - COMMAND_LINE on $(target) = $(jamLine) ; - local optionalPackages = $(HAIKU_ADDED_OPTIONAL_PACKAGES:J=/) ; - OPTIONAL_PACKAGES on $(target) = $(optionalPackages:E="") ; - Always $(target) ; - InvokeSubJam1 $(target) ; - } - - actions InvokeSubJam1 - { - cd $(DIRECTORY) - export HAIKU_IGNORE_USER_BUILD_CONFIG=1 - export HAIKU_ADD_OPTIONAL_PACKAGES=$(OPTIONAL_PACKAGES) - export HAIKU_PRIMARY_GCC=$(HAIKU_GCC_VERSION[1]) - $(JAM:E=jam) -q $(COMMAND_LINE) ; - } - - local otherAlternativeSystemLibsZip - = alternative_system_libs.zip ; - MakeLocate $(otherAlternativeSystemLibsZip) - : $(HAIKU_ALTERNATIVE_GCC_OUTPUT_DIR) ; - - InvokeSubJam $(otherAlternativeSystemLibsZip) - : $(HAIKU_ALTERNATIVE_GCC_OUTPUT_DIR) - : "haiku-alternative-gcc-archive" ; - - # install the alternative libs in the right directory - ExtractArchiveToHaikuImage : $(otherAlternativeSystemLibsZip) ; -} - - #pragma mark - User/Group Setup @@ -778,13 +768,6 @@ HAIKU_INSTALL_DIR ?= $(HAIKU_DEFAULT_INSTALL_DIR) ; # the pseudo target all image contents is attached to NotFile $(HAIKU_IMAGE_CONTAINER_NAME) ; -# Detect a hybrid GCC2/GCC4 image. -local isHybridBuild ; -if $(HAIKU_ADD_ALTERNATIVE_GCC_LIBS) = 1 - && $(HAIKU_ALTERNATIVE_GCC_OUTPUT_DIR) { - isHybridBuild = 1 ; -} - # prepare the script that initializes the shell variables HAIKU_IMAGE_INIT_VARIABLES_SCRIPT = haiku.image-init-vars ; local script = $(HAIKU_IMAGE_INIT_VARIABLES_SCRIPT) ; diff --git a/build/jam/ImageRules b/build/jam/ImageRules index b9090353d5..ebbe599f12 100644 --- a/build/jam/ImageRules +++ b/build/jam/ImageRules @@ -195,7 +195,8 @@ rule AddFilesToContainer container : directoryTokens : targets : destName if $(catalogs) { local signature = [ on $(target) return $(HAIKU_CATALOG_SIGNATURE) ] ; - AddFilesToHaikuImage system data locale catalogs $(signature) + AddFilesToHaikuImage + system data locale catalogs $(signature) : $(catalogs) ; } } @@ -302,7 +303,8 @@ rule AddDriversToContainer container : relativeDirectoryTokens : targets local directoryTokens = system add-ons kernel drivers dev $(relativeDirectoryTokens) ; - AddFilesToContainer $(container) : system add-ons kernel drivers bin + AddFilesToContainer $(container) + : system add-ons kernel drivers bin : $(targets) ; # If the image shall only be updated, we don't add any symlinks. @@ -367,7 +369,8 @@ rule AddBootModuleSymlinksToContainer container : targets local name = $(target:BS) ; local linkTarget = [ FDirName /boot $(installDir:G=) $(name) ] ; - AddSymlinkToContainer $(container) : system add-ons kernel boot + AddSymlinkToContainer $(container) + : system add-ons kernel boot : $(linkTarget) : $(name) ; } } @@ -672,6 +675,8 @@ rule AddSymlinkToHaikuImage directoryTokens : linkTarget : linkName { # AddSymlinkToHaikuImage : [ : ] ; + linkTarget = $(linkTarget:J=/) ; + AddSymlinkToContainer $(HAIKU_IMAGE_CONTAINER_NAME) : $(directoryTokens) : $(linkTarget) : $(linkName) ; } @@ -704,7 +709,7 @@ rule AddHeaderDirectoryToHaikuImage dirTokens : dirName : alwaysUpdate # AddHeaderDirectoryToHaikuImage : [ ] # : ; - CopyDirectoryToHaikuImage develop headers + CopyDirectoryToHaikuImage system develop headers : [ FDirName $(HAIKU_TOP) headers $(dirTokens) ] : $(dirName) : -x .svn : $(alwaysUpdate) ; } @@ -822,6 +827,15 @@ rule InstallSourceArchive file : url } } +rule InstallCommonPackage package : url +{ + # download archive file + local archiveFile = [ DownloadFile $(package) : $(url) ] ; + + # copy onto image + ExtractArchiveToHaikuImage common packages : $(archiveFile) ; +} + rule InstallOptionalHaikuImagePackage package : url : dirTokens : isCDPackage { # download archive file @@ -850,7 +864,7 @@ rule AddEntryToHaikuImageUserGroupFile file : entry Always $(file) ; MakeLocate $(file) : $(HAIKU_COMMON_PLATFORM_OBJECT_DIR) ; BuildHaikuImageUserGroupFile $(file) ; - AddFilesToHaikuImage common etc : $(file) ; + AddFilesToHaikuImage common settings etc : $(file) ; } HAIKU_IMAGE_USER_GROUP_ENTRIES on $(file) = $(allEntries) ; @@ -917,7 +931,8 @@ rule AddExpanderRuleToHaikuImage mimetype : extension : list : extract Exit "Invalid expander rule specification passed to AddExpanderRule." ; } - local entry = "\\\"$(mimetype)\\\"\\\t$(extension)\\\t\\\"$(list)\\\"\\\t\\\"$(extract)\\\"" ; + local entry + = "\\\"$(mimetype)\\\"\\\t$(extension)\\\t\\\"$(list)\\\"\\\t\\\"$(extract)\\\"" ; AddEntryToHaikuImageExpanderRuleFile expander.rules : $(entry) ; } @@ -930,7 +945,8 @@ rule AddInstalledPackagesFileToHaikuImage Always $(file) ; MakeLocate $(file) : $(HAIKU_COMMON_PLATFORM_OBJECT_DIR) ; BuildHaikuImageInstalledPackagesFile $(file) ; - AddFilesToHaikuImage common data optional-packages : $(file) ; + AddFilesToHaikuImage common data optional-packages + : $(file) ; } actions BuildHaikuImageInstalledPackagesFile @@ -957,7 +973,8 @@ rule AddLicenseToHaikuImage file : name : searchPath name = ; } - AddFilesToHaikuImage system data licenses : $(file) : $(name) ; + AddFilesToHaikuImage system data licenses : $(file) + : $(name) ; } @@ -1116,138 +1133,9 @@ actions BuildNetBootArchive1 } -#pragma mark - Alternative GCC Archive rules - - -rule AddDirectoryToAlternativeGCCArchive directoryTokens +rule AddLibrariesToHaikuImage directory : libs { - # AddDirectoryToAlternativeGCCArchive - - return [ AddDirectoryToContainer - $(HAIKU_ALTERNATIVE_GCC_ARCHIVE_CONTAINER_NAME) : $(directoryTokens) ] ; -} - -rule AddFilesToAlternativeGCCArchive directory : targets : destName -{ - # AddFilesToAlternativeGCCArchive : [ : dest name ] - - AddFilesToContainer $(HAIKU_ALTERNATIVE_GCC_ARCHIVE_CONTAINER_NAME) - : $(directory) : $(targets) : $(destName) ; -} - -rule AddSymlinkToAlternativeGCCArchive directoryTokens : linkTarget : linkName -{ - # AddSymlinkToAlternativeGCCArchive : - # [ : ] ; - - AddSymlinkToContainer $(HAIKU_ALTERNATIVE_GCC_ARCHIVE_CONTAINER_NAME) - : $(directoryTokens) : $(linkTarget) : $(linkName) ; -} - -rule CopyDirectoryToAlternativeGCCArchive directoryTokens : sourceDirectory - : targetDirectoryName : excludePatterns : alwaysUpdate -{ - CopyDirectoryToContainer $(HAIKU_ALTERNATIVE_GCC_ARCHIVE_CONTAINER_NAME) - : $(directoryTokens) : $(sourceDirectory) : $(targetDirectoryName) - : $(excludePatterns) : $(alwaysUpdate) ; -} - -rule CreateAlternativeGCCArchiveMakeDirectoriesScript script -{ - CreateContainerMakeDirectoriesScript - $(HAIKU_ALTERNATIVE_GCC_ARCHIVE_CONTAINER_NAME) : $(script) ; -} - -rule CreateAlternativeGCCArchiveCopyFilesScript script -{ - CreateContainerCopyFilesScript - $(HAIKU_ALTERNATIVE_GCC_ARCHIVE_CONTAINER_NAME) : $(script) ; -} - -rule BuildAlternativeGCCArchive archive : scripts -{ - # BuildAlternativeGCCArchive : ; - - local mainScript = build_archive ; - SEARCH on $(mainScript) = [ FDirName $(HAIKU_TOP) build scripts ] ; - - Depends $(archive) : $(mainScript) $(scripts) ; - BuildAlternativeGCCArchive1 $(archive) : $(mainScript) $(scripts) ; -} - -actions BuildAlternativeGCCArchive1 -{ - $(2[1]) $(1) $(2[2-]) -} - - -#pragma mark - Haiku Hybrid Image rules - - -rule AddFilesToHaikuHybridImage directory : targets : destName - : useABISubDir -{ - # AddFilesToHaikuHybridImage : : - # : - # - # Convenience rule calling both AddFilesToHaikuImage and - # AddFilesToAlternativeGCCArchive. - # - # - # if non-empty, specifies that an ABI subdirectory shall be appended to - # for the alternative GCC archive. - - local alternativeSubDir ; - if $(useABISubDir) { - alternativeSubDir = gcc$(HAIKU_GCC_VERSION[1]) ; - } - - AddFilesToHaikuImage $(directory) : $(targets) : $(destName) ; - AddFilesToAlternativeGCCArchive $(directory) $(alternativeSubDir) - : $(targets) : $(destName) ; -} - -rule AddSymlinkToHaikuHybridImage directoryTokens : linkTarget : linkName - : useSymlinkTargetABISubDir : useABISubDir -{ - # AddSymlinkToHaikuHybridImage : : - # [ : [ : ] ] - # - # Convenience rule calling both AddSymlinkToHaikuImage and - # AddSymlinkToAlternativeGCCArchive. - # - # - # Can be a list of components that will be joined to path inserting - # "/"s inbetween. - # - # If non-empty, specifies that an ABI subdirectory shall be inserted - # into (between the first and second component) for the - # alternative GCC archive. - # - # If non-empty, specifies that an ABI subdirectory part shall be appended - # to the directory tokens for the alternative GCC archive. - - local alternativeDirTokens = $(directoryTokens) ; - if $(useABISubDir) { - alternativeDirTokens += gcc$(HAIKU_GCC_VERSION[1]) ; - } - - local alternativeLinkTarget = $(linkTarget) ; - if $(useSymlinkTargetABISubDir) { - alternativeLinkTarget = $(linkTarget[1]) gcc$(HAIKU_GCC_VERSION[1]) - $(linkTarget[2-]) ; - } - linkTarget = $(linkTarget:J=/) ; - alternativeLinkTarget = $(alternativeLinkTarget:J=/) ; - - AddSymlinkToHaikuImage $(directoryTokens) : $(linkTarget) : $(linkName) ; - AddSymlinkToAlternativeGCCArchive $(alternativeDirTokens) - : $(alternativeLinkTarget) : $(linkName) ; -} - -rule AddLibrariesToHaikuHybridImage directory : libs -{ - # AddLibraryToHaikuHybridImage : + # AddLibraryToHaikuImage : # # Installs libraries with the appropriate links onto the image. # @@ -1257,12 +1145,10 @@ rule AddLibrariesToHaikuHybridImage directory : libs local abiVersion = [ on $(lib) return $(HAIKU_LIB_ABI_VERSION) ] ; if $(abiVersion) { local abiVersionedLib = $(lib).$(abiVersion) ; - AddFilesToHaikuHybridImage $(directory) - : $(lib) : $(abiVersionedLib) : true ; - AddSymlinkToHaikuHybridImage $(directory) - : $(abiVersionedLib) : $(lib) : : true ; + AddFilesToHaikuImage $(directory) : $(lib) : $(abiVersionedLib) ; + AddSymlinkToHaikuImage $(directory) : $(abiVersionedLib) : $(lib) ; } else { - AddFilesToHaikuHybridImage $(directory) : $(lib) : : true ; + AddFilesToHaikuImage $(directory) : $(lib) ; } } } diff --git a/build/jam/NetBootArchive b/build/jam/NetBootArchive index 449674e4a1..46b3a9b6dc 100644 --- a/build/jam/NetBootArchive +++ b/build/jam/NetBootArchive @@ -50,18 +50,22 @@ AddFilesToNetBootArchive system add-ons kernel busses ide : generic_ide_pci $(X86_ONLY)ide_isa silicon_image_3112 ; AddFilesToNetBootArchive system add-ons kernel busses scsi : ahci ; -AddFilesToNetBootArchive system add-ons kernel console : vga_text ; +AddFilesToNetBootArchive system add-ons kernel console + : vga_text ; AddFilesToNetBootArchive system add-ons kernel file_systems : $(SYSTEM_ADD_ONS_FILE_SYSTEMS) ; AddFilesToNetBootArchive system add-ons kernel generic : $(IDE_ONLY)ide_adapter $(ATA_ONLY)ata_adapter locked_pool scsi_periph ; -AddFilesToNetBootArchive system add-ons kernel partitioning_systems +AddFilesToNetBootArchive + system add-ons kernel partitioning_systems : intel session ; -AddFilesToNetBootArchive system add-ons kernel interrupt_controllers +AddFilesToNetBootArchive + system add-ons kernel interrupt_controllers : $(PPC_ONLY)openpic ; if $(TARGET_ARCH) = x86 { - AddFilesToNetBootArchive system add-ons kernel cpu : generic_x86 ; + AddFilesToNetBootArchive system add-ons kernel cpu + : generic_x86 ; } # drivers @@ -71,7 +75,8 @@ AddDriversToNetBootArchive disk virtual : remote_disk ; AddDriversToNetBootArchive net : $(SYSTEM_ADD_ONS_DRIVERS_NET) ; # kernel -AddFilesToNetBootArchive system : kernel_$(TARGET_ARCH) ; +AddFilesToNetBootArchive system + : kernel_$(TARGET_ARCH) ; # scripts and data files @@ -86,11 +91,13 @@ AddFilesToNetBootArchive system add-ons kernel network : notifications stack ; AddFilesToNetBootArchive system add-ons kernel network devices : $(SYSTEM_NETWORK_DEVICES) ; -AddFilesToNetBootArchive system add-ons kernel network datalink_protocols +AddFilesToNetBootArchive + system add-ons kernel network datalink_protocols : $(SYSTEM_NETWORK_DATALINK_PROTOCOLS) ; AddFilesToNetBootArchive system add-ons kernel network ppp : $(SYSTEM_NETWORK_PPP) ; -AddFilesToNetBootArchive system add-ons kernel network protocols +AddFilesToNetBootArchive + system add-ons kernel network protocols : $(SYSTEM_NETWORK_PROTOCOLS) ; # boot module links diff --git a/build/jam/OptionalLibPackages b/build/jam/OptionalLibPackages index ecaf22544d..a5d063a78b 100644 --- a/build/jam/OptionalLibPackages +++ b/build/jam/OptionalLibPackages @@ -2,15 +2,6 @@ # It is directly included from HaikuImage -- all variables defined there can # be used -# Detect a hybrid GCC2/GCC4 image and disable the checks for unavailable GCC4 -# packages. (It does not matter if a package was built with either compiler, -# the system should have the respective other system libs.) -local isHybridBuild ; -if $(HAIKU_ADD_ALTERNATIVE_GCC_LIBS) = 1 - && $(HAIKU_ALTERNATIVE_GCC_OUTPUT_DIR) { - isHybridBuild = 1 ; -} - # Available Optional Lib Packages: # AllegroLibs @@ -65,7 +56,7 @@ if [ IsOptionalHaikuImagePackageAdded box2d ] { if $(TARGET_ARCH) != x86 { Echo "No optional package box2d available for $(TARGET_ARCH)" ; } else { - if $(HAIKU_GCC_VERSION[1]) >= 4 || $(isHybridBuild) { + if $(HAIKU_GCC_VERSION[1]) >= 4 { InstallOptionalHaikuImagePackage box2d-2.1.2-r1a3-r1a3-x86-gcc4-2011-05-26.zip : $(baseURL)/lib/box2d-2.1.2-r1a3-x86-gcc4-2011-05-26.zip diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 3f190a78e3..2a33a3dd6f 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -2,15 +2,6 @@ # It is directly included from HaikuImage -- all variables defined there can # be used -# Detect a hybrid GCC2/GCC4 image and disable the checks for unavailable GCC4 -# packages. (It does not matter if a package was built with either compiler, -# the system should have the respective other system libs.) -local isHybridBuild ; -if $(HAIKU_ADD_ALTERNATIVE_GCC_LIBS) = 1 - && $(HAIKU_ALTERNATIVE_GCC_OUTPUT_DIR) { - isHybridBuild = 1 ; -} - # Available Optional Packages: # ABI-compliance-checker - tool for checking ABI compatibility between libs @@ -99,7 +90,7 @@ local baseSourceURL = http://haiku-files.org/files/sources ; # ABI-compliance-checker if [ IsOptionalHaikuImagePackageAdded ABI-compliance-checker ] { - if $(HAIKU_GCC_VERSION[1]) < 4 && ! $(isHybridBuild) { + if $(HAIKU_GCC_VERSION[1]) < 4 { Echo "No optional package ABI-compliance-checker for gcc2" ; } else { InstallOptionalHaikuImagePackage @@ -114,12 +105,12 @@ if [ IsOptionalHaikuImagePackageAdded APR ] { if $(TARGET_ARCH) != x86 { Echo "No optional package APR available for $(TARGET_ARCH)" ; } else if $(HAIKU_GCC_VERSION[1]) >= 4 { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage apr-1.4.2-r1a3-x86-gcc4-2011-05-24.zip : $(baseURL)/apr-1.4.2-r1a3-x86-gcc4-2011-05-24.zip : : true ; } else { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage apr-1.4.2-r1a3-x86-gcc2-2011-05-17.zip : $(baseURL)/apr-1.4.2-r1a3-x86-gcc2-2011-05-17.zip : : true ; @@ -132,12 +123,12 @@ if [ IsOptionalHaikuImagePackageAdded APR-util ] { if $(TARGET_ARCH) != x86 { Echo "No optional package APR-util available for $(TARGET_ARCH)" ; } else if $(HAIKU_GCC_VERSION[1]) >= 4 { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage apr-util-1.3.10-r1a3-x86-gcc4-2011-05-24.zip : $(baseURL)/apr-util-1.3.10-r1a3-x86-gcc4-2011-05-24.zip : : true ; } else { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage apr-util-1.3.10-r1a3-x86-gcc2-2011-05-17.zip : $(baseURL)/apr-util-1.3.10-r1a3-x86-gcc2-2011-05-17.zip : : true ; @@ -149,10 +140,10 @@ if [ IsOptionalHaikuImagePackageAdded APR-util ] { if [ IsOptionalHaikuImagePackageAdded ArmyKnife ] { if $(TARGET_ARCH) != x86 { Echo "No optional package ArmyKnife available for $(TARGET_ARCH)" ; - } else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) { + } else if $(HAIKU_GCC_VERSION[1]) >= 4 { Echo "No optional package ArmyKnife for gcc4" ; } else { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage armyknife-63-r1a3-x86-gcc2-2011-06-04.zip : $(baseURL)/armyknife-63-r1a3-x86-gcc2-2011-06-04.zip ; AddSymlinkToHaikuImage home config be Applications @@ -181,7 +172,7 @@ if [ IsOptionalHaikuImagePackageAdded BeAE ] { Echo "No optional package BeAE available for $(TARGET_ARCH)" ; } else { if $(HAIKU_GCC_VERSION[1]) >= 4 { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage beae-22-r1a3-x86-gcc4-2011-05-24.zip : $(baseURL)/beae-22-r1a3-x86-gcc4-2011-05-24.zip ; } else { @@ -199,7 +190,7 @@ if [ IsOptionalHaikuImagePackageAdded BeAE ] { if [ IsOptionalHaikuImagePackageAdded Beam ] { if $(TARGET_ARCH) != x86 { Echo "No optional package Beam available for $(TARGET_ARCH)" ; - } else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) { + } else if $(HAIKU_GCC_VERSION[1]) >= 4 { Echo "No optional package Beam available for gcc4" ; } else { InstallOptionalHaikuImagePackage Beam-1.2alpha-x86-gcc2-2010-04-29.zip @@ -216,7 +207,8 @@ if [ IsOptionalHaikuImagePackageAdded BeBook ] { : $(baseURL)/bebook_20081026.zip : system documentation ; AddSymlinkToHaikuImage home Desktop - : /boot/system/documentation/bebook/index.html : BeBook ; + : /boot/system/documentation/bebook/index.html + : BeBook ; } @@ -224,7 +216,7 @@ if [ IsOptionalHaikuImagePackageAdded BeBook ] { if [ IsOptionalHaikuImagePackageAdded BeHappy ] { if $(TARGET_ARCH) != x86 { Echo "No optional package BeHappy available for $(TARGET_ARCH)" ; - } else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) { + } else if $(HAIKU_GCC_VERSION[1]) >= 4 { Echo "No optional package BeHappy available for gcc4" ; } else { Echo "No optional package BeHappy available for gcc2" ; @@ -236,14 +228,15 @@ if [ IsOptionalHaikuImagePackageAdded BeHappy ] { if [ IsOptionalHaikuImagePackageAdded BeOSCompatibility ] { if $(TARGET_ARCH) != x86 { Echo "No optional package BeOSCompatibility available for $(TARGET_ARCH)" ; - } else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) { + } else if $(HAIKU_GCC_VERSION[1]) >= 4 { Echo "No optional package BeOSCompatibility available for gcc4" ; } else { Echo "Warning: Adding BeOS compatibility symlinks. This will go away. Please fix your apps!" ; AddSymlinkToHaikuImage beos : ../system/apps ; AddSymlinkToHaikuImage beos : ../system/bin ; - AddSymlinkToHaikuImage beos : ../system/documentation ; - AddSymlinkToHaikuImage beos : ../common/etc ; + AddSymlinkToHaikuImage beos + : ../system/documentation ; + AddSymlinkToHaikuImage beos : ../common/settings/etc ; AddSymlinkToHaikuImage beos : ../system/preferences ; AddSymlinkToHaikuImage beos : ../system ; AddDirectoryToHaikuImage var ; @@ -257,7 +250,7 @@ if [ IsOptionalHaikuImagePackageAdded BeOSCompatibility ] { if [ IsOptionalHaikuImagePackageAdded BePDF ] { if $(TARGET_ARCH) != x86 { Echo "No optional package BePDF available for $(TARGET_ARCH)" ; - } else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) { + } else if $(HAIKU_GCC_VERSION[1]) >= 4 { Echo "No optional package BePDF available for gcc4" ; } else { InstallOptionalHaikuImagePackage @@ -297,18 +290,21 @@ if [ IsOptionalHaikuImagePackageAdded Bluetooth ] { AddDriversToHaikuImage bluetooth : $(bluetoothDrivers) ; AddFilesToHaikuImage system servers : bluetooth_server ; AddFilesToHaikuImage system lib : libbluetooth.so ; - AddFilesToHaikuImage system add-ons kernel network protocols : l2cap ; - AddFilesToHaikuImage system add-ons kernel bluetooth : btCoreData hci ; + AddFilesToHaikuImage + system add-ons kernel network protocols : l2cap ; + AddFilesToHaikuImage system add-ons kernel bluetooth + : btCoreData hci ; AddFilesToHaikuImage system preferences : Bluetooth ; - AddFilesToHaikuImage system bin : bt_dev_info bt_discovery ; + AddFilesToHaikuImage system bin + : bt_dev_info bt_discovery ; AddSymlinkToHaikuImage home config be Preferences : /boot/system/preferences/Bluetooth ; if [ IsOptionalHaikuImagePackageAdded DevelopmentMin ] && $(HAIKU_GCC_VERSION[1]) in 2 4 { local arch = $(TARGET_ARCH) ; local abi = gcc$(HAIKU_GCC_VERSION[1]) ; - AddSymlinkToHaikuHybridImage develop abi $(arch) $(abi) lib - : /system/lib libbluetooth.so : : true ; + AddSymlinkToHaikuImage system develop lib + : /system/lib libbluetooth.so ; } } @@ -407,7 +403,7 @@ if [ IsOptionalHaikuImagePackageAdded Clockwerk ] { if [ IsOptionalHaikuImagePackageAdded CLucene ] { if $(TARGET_ARCH) != x86 { Echo "No optional package CLucene available for $(TARGET_ARCH)" ; - } else if $(HAIKU_GCC_VERSION[1]) < 4 && ! $(isHybridBuild) { + } else if $(HAIKU_GCC_VERSION[1]) < 4 { Echo "No optional package CLucene available for GCC2" ; } else { InstallOptionalHaikuImagePackage @@ -517,37 +513,20 @@ if [ IsOptionalHaikuImagePackageAdded Development ] && $(TARGET_ARCH) = x86 { if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ] && $(TARGET_ARCH) = x86 { # gcc and binutils - if $(HAIKU_GCC_VERSION[1]) = 2 || $(isHybridBuild) { - InstallOptionalHaikuImagePackage - gcc-2.95.3-r1a3-x86-gcc2-2010-08-18.zip - : $(baseURL)/gcc-2.95.3-r1a3-x86-gcc2-2010-08-18.zip ; - } - if $(HAIKU_GCC_VERSION[1]) = 2 { - # symlink to the appropriate system/lib[/gcc2] folder - AddSymlinkToHaikuHybridImage - develop abi x86 gcc2 tools gcc-2.95.3-haiku-100818 lib - : /system/lib libstdc++.r4.so : : true ; - } + InstallCommonPackage gcc-2.95.3_110304-1.hpkg + : $(baseURL)/gcc-2.95.3_110304.hpkg ; - if $(HAIKU_GCC_VERSION[1]) = 4 || $(isHybridBuild) { - InstallOptionalHaikuImagePackage - gcc-4.5.3-r1a3-x86-gcc4-2011-06-20.zip - : $(baseURL)/gcc-4.5.3-r1a3-x86-gcc4-2011-06-20.zip ; + # TODO: remove this when we have a mechanism to switch gcc via PATH + AddSymlinkToHaikuImage common settings develop tools + : /boot/common/develop/tools/gcc-2.95.3-110304 + : current ; } if $(HAIKU_GCC_VERSION[1]) = 4 { - # symlink cpp to g++'s headers - AddSymlinkToHaikuHybridImage develop abi x86 gcc4 headers - : ../tools/current/include/g++ : cpp ; - - # symlink to the appropriate system/lib[/gcc4] folder - local libs = libstdc++.so libsupc++.so ; - for lib in $(libs) { - AddSymlinkToHaikuHybridImage - develop abi x86 gcc4 tools gcc-4.5.3-haiku-110620 lib - : /system/lib $(lib) : : true ; - } + InstallOptionalHaikuImagePackage + gcc-4.5.3-r1a3-x86-gcc4-2011-06-20.zip + : $(baseURL)/gcc-4.5.3-r1a3-x86-gcc4-2011-06-20.zip ; } # other commonly used tools @@ -606,7 +585,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentJava ] { InstallOptionalHaikuImagePackage jamvm-1.5.4-r1a3-x86-gcc4-2011-06-08.zip : $(baseURL)/jamvm-1.5.4-r1a3-x86-gcc4-2011-06-08.zip ; - AddSymlinkToHaikuImage common bin : /boot/common/bin/jamvm : java ; + AddSymlinkToHaikuImage common bin + : /boot/common/bin/jamvm : java ; InstallOptionalHaikuImagePackage ecj-3.6.2-haiku-2011-06-08.zip : $(baseURL)/ecj-3.6.2-haiku-2011-06-08.zip ; @@ -622,11 +602,10 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentMin ] && $(TARGET_ARCH) = x86 { } local arch = $(TARGET_ARCH) ; - local abi = gcc$(HAIKU_GCC_VERSION[1]) ; - local abiDirTokens = develop abi $(arch) $(abi) ; + local developDirTokens = system develop ; # glue code - AddFilesToHaikuHybridImage $(abiDirTokens) lib : + AddFilesToHaikuImage $(developDirTokens) lib : crti.o crtn.o init_term_dyn.o @@ -635,44 +614,31 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentMin ] && $(TARGET_ARCH) = x86 { ; # kernel - AddFilesToHaikuHybridImage $(abiDirTokens) lib : kernel.so : _KERNEL_ ; + AddFilesToHaikuImage $(developDirTokens) lib : kernel.so : _KERNEL_ ; # additional libraries local developmentLibs = libroot_debug.so ; - AddFilesToHaikuHybridImage system lib : $(developmentLibs) : : true ; + AddFilesToHaikuImage system lib : $(developmentLibs) ; # library symlinks local lib ; for lib in $(SYSTEM_LIBS) $(SYSTEM_LIBS_LIBGL_ALIASES) $(developmentLibs) { - AddSymlinkToHaikuHybridImage $(abiDirTokens) lib - : /system/lib $(lib:BS) : : true ; + AddSymlinkToHaikuImage $(developDirTokens) lib + : /system/lib $(lib:BS) ; local abiVersion = [ on $(lib) return $(HAIKU_LIB_ABI_VERSION) ] ; if $(abiVersion) { local abiVersionedLib = $(lib:BS).$(abiVersion) ; - AddSymlinkToHaikuHybridImage $(abiDirTokens) lib - : /system/lib $(abiVersionedLib) : : true ; + AddSymlinkToHaikuImage $(developDirTokens) lib + : /system/lib $(abiVersionedLib) ; } } # static libraries - AddFilesToHaikuHybridImage $(abiDirTokens) lib : libncurses.a ; - AddFilesToHaikuHybridImage $(abiDirTokens) lib : liblocalestub.a ; + AddFilesToHaikuImage $(developDirTokens) lib : libncurses.a ; + AddFilesToHaikuImage $(developDirTokens) lib : liblocalestub.a ; # the POSIX error code mapper library - AddFilesToHaikuHybridImage $(abiDirTokens) lib : libposix_error_mapper.a ; - - # symlinks for ABI abstraction - AddSymlinkToHaikuImage develop abi : $(arch)/$(abi) : current ; - AddSymlinkToHaikuImage develop lib : /boot/develop/abi/current/lib - : $(arch) ; - AddSymlinkToHaikuImage develop tools - : /boot/develop/abi/current/tools/current : gnupro ; - AddSymlinkToHaikuImage develop headers - : /boot/develop/abi/current/headers/cpp ; - AddSymlinkToHaikuHybridImage $(abiDirTokens) library-paths - : /boot/common/lib : common : true ; - AddSymlinkToHaikuHybridImage $(abiDirTokens) library-paths - : /boot/home/config/lib : home : true ; + AddFilesToHaikuImage $(developDirTokens) lib : libposix_error_mapper.a ; # ABI independent stuff @@ -688,7 +654,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentMin ] && $(TARGET_ARCH) = x86 { ; SEARCH on $(makefileEngineFiles) = [ FDirName $(HAIKU_TOP) data develop ] ; - AddFilesToHaikuImage develop etc : $(makefileEngineFiles) ; + AddFilesToHaikuImage common develop etc + : $(makefileEngineFiles) ; # headers AddHeaderDirectoryToHaikuImage config ; @@ -697,7 +664,7 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentMin ] && $(TARGET_ARCH) = x86 { AddHeaderDirectoryToHaikuImage posix ; # create be -> os symlink for now - AddSymlinkToHaikuImage develop headers : os : be ; + AddSymlinkToHaikuImage $(developDirTokens) headers : os : be ; # BSD and GNU compatibility headers AddHeaderDirectoryToHaikuImage compatibility bsd : bsd ; @@ -715,10 +682,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentMin ] && $(TARGET_ARCH) = x86 { # cpp headers if $(HAIKU_GCC_VERSION[1]) = 2 { # GCC 2 only -- for GCC 4 they come with the DevelopmentBase package - CopyDirectoryToHaikuImage $(abiDirTokens) headers - : [ FDirName $(HAIKU_TOP) headers cpp ] : : -x .svn ; - CopyDirectoryToAlternativeGCCArchive $(abiDirTokens) headers - : [ FDirName $(HAIKU_TOP) headers cpp ] : : -x .svn ; + CopyDirectoryToHaikuImage $(developDirTokens) headers c++ + : [ FDirName $(HAIKU_TOP) headers cpp ] : 2.95.3 : -x .svn ; } } @@ -783,9 +748,13 @@ if [ IsOptionalHaikuImagePackageAdded Fastdep ] { if [ IsOptionalHaikuImagePackageAdded friss ] { if $(TARGET_ARCH) != x86 { Echo "No optional package friss available for $(TARGET_ARCH)" ; + } else if $(HAIKU_GCC_VERSION[1]) >= 4 { + InstallOptionalHaikuImagePackage friss-0.5pre7-x86-gcc4.zip + : $(baseURL)/friss-0.5pre7-x86-gcc4.zip + : : true ; } else { if $(HAIKU_GCC_VERSION[1]) >= 4 { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage friss-24-r1a3-x86-gcc4-2011-05-31.zip : $(baseURL)/friss-24-r1a3-x86-gcc4-2011-05-31.zip ; } else { @@ -889,26 +858,14 @@ if [ IsOptionalHaikuImagePackageAdded ICU ] { InstallOptionalHaikuImagePackage $(HAIKU_ICU_GCC_2_PACKAGE) : $(baseURL)/$(HAIKU_ICU_GCC_2_PACKAGE) : system lib ; - if $(isHybridBuild) { - # unzip gcc4 to gcc4 subdir - InstallOptionalHaikuImagePackage $(HAIKU_ICU_GCC_4_PACKAGE) - : $(baseURL)/$(HAIKU_ICU_GCC_4_PACKAGE) - : system lib gcc4 ; - } } else { # unzip gcc4 InstallOptionalHaikuImagePackage $(HAIKU_ICU_GCC_4_PACKAGE) : $(baseURL)/$(HAIKU_ICU_GCC_4_PACKAGE) : system lib ; - if $(isHybridBuild) { - # unzip gcc2 to gcc2 subdir - InstallOptionalHaikuImagePackage $(HAIKU_ICU_GCC_2_PACKAGE) - : $(baseURL)/$(HAIKU_ICU_GCC_2_PACKAGE) - : system lib gcc2 ; } } } -} # ICU-devel @@ -921,9 +878,9 @@ if [ IsOptionalHaikuImagePackageAdded ICU-devel ] { for abiVersionedLib in $(HAIKU_ICU_LIBS) { abiVersionedLib = $(abiVersionedLib:G=) ; local lib = $(abiVersionedLib:B) ; - AddSymlinkToHaikuHybridImage develop abi $(arch) $(abi) lib - : /system/lib $(abiVersionedLib) : : true ; - AddSymlinkToHaikuHybridImage develop abi $(arch) $(abi) lib + AddSymlinkToHaikuImage develop abi $(arch) $(abi) lib + : /system/lib $(abiVersionedLib) ; + AddSymlinkToHaikuImage develop abi $(arch) $(abi) lib : $(abiVersionedLib) : $(lib) ; } } @@ -991,7 +948,7 @@ if [ IsOptionalHaikuImagePackageAdded LibIconv ] { if [ IsOptionalHaikuImagePackageAdded LibLayout ] { if $(TARGET_ARCH) != x86 { Echo "No optional package LibLayout available for $(TARGET_ARCH)" ; - } else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) { + } else if $(HAIKU_GCC_VERSION[1]) >= 4 { Echo "No optional package LibLayout available for gcc4" ; } else { InstallOptionalHaikuImagePackage liblayout-1.4.0-gcc2-2009-03-08.zip @@ -1005,11 +962,11 @@ if [ IsOptionalHaikuImagePackageAdded Libmng ] { if $(TARGET_ARCH) != x86 { Echo "No optional package Libmng available for $(TARGET_ARCH)" ; } else if $(HAIKU_GCC_VERSION[1]) >= 4 { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage libmng-1.0.10-r1a3-x86-gcc4-2011-05-24.zip : $(baseURL)/lib/libmng-1.0.10-r1a3-x86-gcc4-2011-05-24.zip ; } else { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage libmng-1.0.10-r1a3-x86-gcc2-2011-05-18.zip : $(baseURL)/lib/libmng-1.0.10-r1a3-x86-gcc2-2011-05-18.zip ; } @@ -1041,7 +998,7 @@ if [ IsOptionalHaikuImagePackageAdded LibXSLT ] { } else if $(HAIKU_GCC_VERSION[1]) >= 4 { InstallOptionalHaikuImagePackage libxslt-1.1.26-r1a3-x86-gcc4-2011-05-24.zip - : $(baseURL)/libxslt-1.1.26-r1a3-x86-gcc4-2011-05-24.zip ; + : $(baseURL)/libxslt-1.1.26-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage libxslt-1.1.26-r1a3-x86-gcc2-2011-05-18.zip @@ -1055,7 +1012,7 @@ if [ IsOptionalHaikuImagePackageAdded LibXSLT ] { if [ IsOptionalHaikuImagePackageAdded Links ] { if $(TARGET_ARCH) != x86 { Echo "No optional package Links available for $(TARGET_ARCH)" ; - } else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) { + } else if $(HAIKU_GCC_VERSION[1]) >= 4 { Echo "No optional package Links available for gcc4" ; } else { InstallOptionalHaikuImagePackage Links.zip @@ -1093,7 +1050,7 @@ if [ IsOptionalHaikuImagePackageAdded Man ] { } else if $(HAIKU_GCC_VERSION[1]) >= 4 { InstallOptionalHaikuImagePackage man-1.6f-r1a3-x86-gcc4-2011-05-24.zip - : $(baseURL)/man-1.6f-r1a3-x86-gcc4-2011-05-24.zip ; + : $(baseURL)/man-1.6f-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage man-1.6f-r1a3-x86-gcc2-2011-05-18.zip @@ -1167,11 +1124,13 @@ if [ IsOptionalHaikuImagePackageAdded Neon ] { # NetFS network file system if [ IsOptionalHaikuImagePackageAdded NetFS ] { # userlandfs module - AddFilesToHaikuImage home config add-ons userlandfs : netfs ; + AddFilesToHaikuImage home config add-ons userlandfs + : netfs ; # servers AddFilesToHaikuImage system servers : netfs_server ; - AddFilesToHaikuImage system servers : authentication_server ; + AddFilesToHaikuImage system servers + : authentication_server ; # tools AddFilesToHaikuImage system bin : netfs_config ; @@ -1197,10 +1156,10 @@ if [ IsOptionalHaikuImagePackageAdded NetFS ] { if [ IsOptionalHaikuImagePackageAdded NetSurf ] { if $(TARGET_ARCH) != x86 { Echo "No optional package NetSurf available for $(TARGET_ARCH)" ; - } else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) { + } else if $(HAIKU_GCC_VERSION[1]) >= 4 { Echo "No optional package NetSurf available for gcc4" ; } else { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage netsurf-2.7-r1a3-x86-gcc2-2011-06-04.zip : $(baseURL)/netsurf-2.7-r1a3-x86-gcc2-2011-06-04.zip ; AddSymlinkToHaikuImage home config be Applications @@ -1213,7 +1172,7 @@ if [ IsOptionalHaikuImagePackageAdded NetSurf ] { if [ IsOptionalHaikuImagePackageAdded OCaml ] { if $(TARGET_ARCH) != x86 { Echo "No optional package OCaml available for $(TARGET_ARCH)" ; - } else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) { + } else if $(HAIKU_GCC_VERSION[1]) >= 4 { Echo "No optional package OCaml available for gcc4" ; } else { InstallOptionalHaikuImagePackage @@ -1309,11 +1268,11 @@ if [ IsOptionalHaikuImagePackageAdded Paladin ] { Echo "No optional package Paladin available for $(TARGET_ARCH)" ; } else { if $(HAIKU_GCC_VERSION[1]) >= 4 { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage paladin-1.3-r1a3-x86-gcc4-2011-05-24.zip : $(baseURL)/paladin-1.3-r1a3-x86-gcc4-2011-05-24.zip ; } else { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage paladin-1.3-r1a3-x86-gcc2-2011-05-18.zip : $(baseURL)/paladin-1.3-r1a3-x86-gcc2-2011-05-18.zip ; } @@ -1332,7 +1291,7 @@ if [ IsOptionalHaikuImagePackageAdded PCRE ] { Echo "No optional package PCRE available for $(TARGET_ARCH)" ; } else { if $(HAIKU_GCC_VERSION[1]) >= 4 { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage libpcre-8.12-r1a3-x86-gcc4-2011-05-24.zip : $(baseURL)/libpcre-8.12-r1a3-x86-gcc4-2011-05-24.zip ; } else { @@ -1503,7 +1462,7 @@ if [ IsOptionalHaikuImagePackageAdded TagLib ] { } else if $(HAIKU_GCC_VERSION[1]) >= 4 { InstallOptionalHaikuImagePackage taglib-1.6.3-r1r3-x86-gcc4-2011-05-24.zip - : $(baseURL)/taglib-1.6.3-r1r3-x86-gcc4-2011-05-24.zip ; + : $(baseURL)/taglib-1.6.3-r1r3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage taglib-1.6.3-r1a3-x86-gcc2-2011-05-20.zip @@ -1572,7 +1531,8 @@ if [ IsOptionalHaikuImagePackageAdded UserlandFS ] { local abi = gcc$(HAIKU_GCC_VERSION[1]) ; # kernel module - AddFilesToHaikuImage system add-ons kernel file_systems : userlandfs ; + AddFilesToHaikuImage system add-ons kernel file_systems + : userlandfs ; # server AddFilesToHaikuImage system servers : userlandfs_server ; @@ -1583,7 +1543,7 @@ if [ IsOptionalHaikuImagePackageAdded UserlandFS ] { libuserlandfs_haiku_kernel.so libuserlandfs_fuse.so ; - AddFilesToHaikuHybridImage system lib : $(userlandfsLibs) : : true ; + AddFilesToHaikuImage system lib : $(userlandfsLibs) ; # development goodies if [ IsOptionalHaikuImagePackageAdded DevelopmentMin ] { @@ -1597,8 +1557,6 @@ if [ IsOptionalHaikuImagePackageAdded UserlandFS ] { for lib in $(userlandfsLibs) { AddSymlinkToHaikuImage develop abi $(arch) $(abi) lib : /system/lib/$(lib:BS) ; - AddSymlinkToAlternativeGCCArchive develop abi $(arch) $(abi) lib - : /system/lib/$(arch)/$(lib:BS) ; } # FUSE headers @@ -1650,7 +1608,7 @@ if [ IsOptionalHaikuImagePackageAdded Vision ] { InstallOptionalHaikuImagePackage vision-908-r1a3-x86-gcc4-2011-06-07.zip : $(baseURL)/vision-908-r1a3-x86-gcc4-2011-06-07.zip ; } else { - InstallOptionalHaikuImagePackage + InstallOptionalHaikuImagePackage vision-908-r1a3-x86-gcc2-2011-06-07.zip : $(baseURL)/vision-908-r1a3-x86-gcc2-2011-06-07.zip ; } @@ -1664,7 +1622,7 @@ if [ IsOptionalHaikuImagePackageAdded Vision ] { if [ IsOptionalHaikuImagePackageAdded WebPositive ] { if $(TARGET_ARCH) != x86 { Echo "No optional package WebPositive available for $(TARGET_ARCH)" ; - } else if $(HAIKU_GCC_VERSION[1]) < 4 && ! $(isHybridBuild) { + } else if $(HAIKU_GCC_VERSION[1]) < 4 { Echo "No optional package WebPositive available for gcc2" ; } else { InstallOptionalHaikuImagePackage @@ -1685,9 +1643,11 @@ if [ IsOptionalHaikuImagePackageAdded Welcome ] { : [ FDirName $(HAIKU_TOP) docs userguide ] : userguide : -x .svn ; AddSymlinkToHaikuImage home Desktop - : /boot/system/documentation/welcome/welcome_en.html : Welcome ; + : /boot/system/documentation/welcome/welcome_en.html + : Welcome ; AddSymlinkToHaikuImage home Desktop - : /boot/system/documentation/userguide/en/contents.html : User\ Guide ; + : /boot/system/documentation/userguide/en/contents.html + : User\ Guide ; } @@ -1707,18 +1667,21 @@ if [ IsOptionalHaikuImagePackageAdded WifiFirmwareScriptData ] { http://bu3sch.de/b43/fwcutter/$(broadcomFWCutterArchive) ; local broadcomFWCutterFile = [ DownloadFile $(broadcomFWCutterArchive) : $(broadcomFWCutterURL) ] ; - AddFilesToHaikuImage system data firmware broadcom43xx b43-fwcutter + AddFilesToHaikuImage + system data firmware broadcom43xx b43-fwcutter : $(broadcomFWCutterFile) ; # headers needed to compile firmware cutter local glibcDir = [ FDirName $(HAIKU_TOP) src system libroot posix glibc ] ; local byteswapHeader = [ FDirName $(glibcDir) string byteswap.h ] ; - AddFilesToHaikuImage system data firmware broadcom43xx b43-fwcutter + AddFilesToHaikuImage + system data firmware broadcom43xx b43-fwcutter : $(byteswapHeader) ; local bitByteswapHeader = [ FDirName $(glibcDir) include arch x86 bits byteswap.h ] ; - AddFilesToHaikuImage system data firmware broadcom43xx b43-fwcutter bits + AddFilesToHaikuImage + system data firmware broadcom43xx b43-fwcutter bits : $(bitByteswapHeader) ; # file containing firmware @@ -1732,7 +1695,8 @@ if [ IsOptionalHaikuImagePackageAdded WifiFirmwareScriptData ] { local marvelArchive = malo-firmware-1.4.tgz ; local marvelURL = http://www.nazgul.ch/malo/$(marvelArchive) ; local marvelFile = [ DownloadFile $(marvelArchive) : $(marvelURL) ] ; - AddFilesToHaikuImage system data firmware marvell88w8335 + AddFilesToHaikuImage + system data firmware marvell88w8335 : $(marvelFile) ; } } @@ -1742,7 +1706,7 @@ if [ IsOptionalHaikuImagePackageAdded WifiFirmwareScriptData ] { if [ IsOptionalHaikuImagePackageAdded WonderBrush ] { if $(TARGET_ARCH) != x86 { Echo "No optional package WonderBrush available for $(TARGET_ARCH)" ; - } else if $(HAIKU_GCC_VERSION[1]) >= 4 && ! $(isHybridBuild) { + } else if $(HAIKU_GCC_VERSION[1]) >= 4 { Echo "No optional package WonderBrush available for gcc4" ; } else { InstallOptionalHaikuImagePackage WonderBrush-2.1.2.zip diff --git a/build/jam/UserBuildConfig.ReadMe b/build/jam/UserBuildConfig.ReadMe index d1c9eb172d..f4032a7a5d 100644 --- a/build/jam/UserBuildConfig.ReadMe +++ b/build/jam/UserBuildConfig.ReadMe @@ -137,14 +137,6 @@ AddOptionalHaikuImagePackages WonderBrush ; AddOptionalHaikuImagePackages WebPositive ; SuppressOptionalHaikuImagePackages SQLite ; -# Don't add the libraries built with the alternative gcc version. -# If the alternative gcc generated directory has been specified via the -# configure option --alternative-gcc-output-dir, the libraries for the -# alternative gcc version are added by default. Unsetting this variable disables -# building and adding the libraries. Ignored, if --alternative-gcc-output-dir -# was not specified. -HAIKU_ADD_ALTERNATIVE_GCC_LIBS = 0 ; - # Specify scripts that shall be run when populating the image/installation # directory. The "early" script is run before anything has been copied onto # the image/into the installation directory. The "late" script is run after diff --git a/build/jam/UserBuildConfig.sample b/build/jam/UserBuildConfig.sample index ba88a5915b..4a164b149c 100644 --- a/build/jam/UserBuildConfig.sample +++ b/build/jam/UserBuildConfig.sample @@ -27,6 +27,3 @@ # Add the optional package WonderBrush to the image. #AddOptionalHaikuImagePackages WonderBrush ; - -# Don't add the libraries built with the alternative gcc version. -#HAIKU_ADD_ALTERNATIVE_GCC_LIBS = 0 ; diff --git a/build/scripts/build_haiku_image b/build/scripts/build_haiku_image index d6001f9d19..1d2aed0647 100755 --- a/build/scripts/build_haiku_image +++ b/build/scripts/build_haiku_image @@ -163,19 +163,23 @@ extractFile() targetExtractedDir=$2 extractedSubDir=$3 - echo "Extracting $archiveFile ..." - extractDir=$tmpDir/extract $rmAttrs -rf "$extractDir" mkdir -p "$extractDir" case "$archiveFile" in *.zip) + echo "Extracting $archiveFile ..." $unzip -q -d "$extractDir" "$archiveFile" ;; *.tgz|*.tar.gz) + echo "Extracting $archiveFile ..." tar -C "$extractDir" -xf "$archiveFile" ;; + *.hpkg) + echo "Adding package $archiveFile ..." + cp "$archiveFile" "$extractDir" + ;; *) echo "Unhandled archive extension in build_haiku_image extractFile()" exit 1 diff --git a/configure b/configure index a93bd04b67..d7b4e188a9 100755 --- a/configure +++ b/configure @@ -12,20 +12,6 @@ usage() Usage: $0 options: - --alternative-gcc-output-dir - Build a Haiku installation that supports running - executables built with a gcc version incompatible - with the primary gcc (e.g. gcc 2 executables under - a gcc 4 Haiku or vice versa). specifies the - output directory of the other gcc. The directory - must already be fully configured. - Note, that a sub-jam will be executed when - building Haiku. When using a jam that is not - simply invoked by "jam", the JAM build variable - needs to be set accordingly. - To disable building the alternative libraries - the variable HAIKU_ADD_ALTERNATIVE_GCC_LIBS can be - unset in the UserBuildConfig file. --build-cross-tools Assume cross compilation. defines the location of the build tools sources. @@ -320,14 +306,12 @@ TARGET_PLATFORM=haiku HAIKU_USE_GCC_PIPE=0 HAIKU_HOST_USE_32BIT=0 HAIKU_HOST_USE_XATTR=0 -HAIKU_ALTERNATIVE_GCC_OUTPUT_DIR= -HAIKU_ADD_ALTERNATIVE_GCC_LIBS=0 HOST_GCC_LD=`gcc -print-prog-name=ld` HOST_GCC_OBJCOPY=`gcc -print-prog-name=objcopy` SFDISK_BINARY=sfdisk HOST_SFDISK=$SFDISK_BINARY -haikuRequiredLegacyGCCVersion="2.95.3-haiku-100818" +haikuRequiredLegacyGCCVersion="2.95.3-110228" export haikuRequiredLegacyGCCVersion # version of legacy gcc required to build haiku @@ -377,14 +361,6 @@ fi # while [ $# -gt 0 ] ; do case "$1" in - --alternative-gcc-output-dir) - assertparam "$1" $# - cd $2 || exit 1 - HAIKU_ALTERNATIVE_GCC_OUTPUT_DIR=`pwd` - HAIKU_ADD_ALTERNATIVE_GCC_LIBS=1 - cd $currentDir - shift 2 - ;; --build-cross-tools) assertparam "$1" $#; buildCrossTools=$2; shift 2;; --build-cross-tools-gcc4) assertparams "$1" 2 $# @@ -558,8 +534,6 @@ HAIKU_DISTRO_COMPATIBILITY ?= "${HAIKU_DISTRO_COMPATIBILITY}" ; HAIKU_USE_GCC_PIPE ?= "${HAIKU_USE_GCC_PIPE}" ; HAIKU_HOST_USE_32BIT ?= "${HAIKU_HOST_USE_32BIT}" ; HAIKU_HOST_USE_XATTR ?= "${HAIKU_HOST_USE_XATTR}" ; -HAIKU_ALTERNATIVE_GCC_OUTPUT_DIR ?= ${HAIKU_ALTERNATIVE_GCC_OUTPUT_DIR} ; -HAIKU_ADD_ALTERNATIVE_GCC_LIBS ?= ${HAIKU_ADD_ALTERNATIVE_GCC_LIBS} ; HAIKU_GCC_RAW_VERSION ?= ${HAIKU_GCC_RAW_VERSION} ; HAIKU_GCC_MACHINE ?= ${HAIKU_GCC_MACHINE} ; diff --git a/data/system/boot/SetupEnvironment b/data/system/boot/SetupEnvironment index 0f3bd51104..ad0a1584a6 100644 --- a/data/system/boot/SetupEnvironment +++ b/data/system/boot/SetupEnvironment @@ -6,8 +6,10 @@ export HOME=/boot/home export LC_CTYPE="en_US.UTF-8" -BUILDHOME=/boot/develop -BETOOLS="$BUILDHOME/tools/gnupro/bin" +BUILDHOME=/boot/system/develop + +#TODO: fix this or drop it! +BETOOLS="/boot/common/settings/develop/tools/current/bin" case `uname -m` in BePC|Intel|unknown) @@ -20,7 +22,9 @@ BeMac|BeBox) BE_HOST_CPU=unknown esac -BELIBRARIES="$BUILDHOME/abi/current/library-paths/common:$BUILDHOME/lib/$BE_HOST_CPU" +BELIBRARIES="/boot/common/non-packaged/lib:/boot/common/lib:$BUILDHOME/lib" + +# not used by Haiku, but probably by legacy applications (BeIDE?) BH=$BUILDHOME/headers BEINCLUDES="$BH;$BH/be;$BH/posix;$BH/glibc;$BH/cpp;$BH/be/app;$BH/be/device;$BH/be/interface;$BH/be/locale;$BH/be/media;$BH/be/midi;$BH/be/midi2;$BH/be/net;$BH/be/kernel;$BH/be/storage;$BH/be/support;$BH/be/game;$BH/be/opengl;$BH/be/drivers;$BH/gnu;$BH/be/mail;$BH/be/translation;$BH/be/devel;$BH/be/add-ons/graphics;$BH/be/be_apps/Deskbar;$BH/be/be_apps/NetPositive;$BH/be/be_apps/Tracker" @@ -40,13 +44,13 @@ export BE_DEFAULT_CPLUS_FLAGS="" if [ "$SAFEMODE" != "yes" ] then - export PATH=.:$HOME/config/bin:/boot/common/bin:/bin:/boot/apps:/boot/preferences:/boot/system/apps:/boot/system/preferences:$BETOOLS - export LIBRARY_PATH="%A/lib:$HOME/config/lib:/boot/common/lib:/boot/system/lib" - export ADDON_PATH="%A/add-ons:$HOME/config/add-ons:/boot/common/add-ons:/boot/system/add-ons" + export PATH=.:$HOME/config/non-packaged/bin:$HOME/config/bin:/boot/common/non-packaged/bin:/boot/common/bin:/bin:/boot/apps:/boot/preferences:/boot/system/apps:/boot/system/preferences:$BETOOLS + export LIBRARY_PATH="%A/lib:$HOME/config/non-packaged/lib:$HOME/config/lib:/boot/common/non-packaged/lib:/boot/common/lib:/boot/system/lib" + export ADDON_PATH="%A/add-ons:$HOME/config/non-packaged/add-ons:$HOME/config/add-ons:/boot/common/non-packaged/add-ons:/boot/common/add-ons:/boot/system/add-ons" else - export PATH=.:/boot/common/bin:/bin:/boot/apps:/boot/preferences:/boot/system/apps:/boot/system/preferences:$BETOOLS - export LIBRARY_PATH="%A/lib:/boot/common/lib:/boot/system/lib" - export ADDON_PATH="%A/add-ons:/boot/common/add-ons:/boot/system/add-ons" + export PATH=.:/bin:/boot/apps:/boot/system/apps:/boot/system/preferences:$BETOOLS + export LIBRARY_PATH="%A/lib:/boot/system/lib" + export ADDON_PATH="%A/add-ons:/boot/system/add-ons" fi # media kit diff --git a/headers/config/HaikuConfig.h b/headers/config/HaikuConfig.h index 7c2b3b992c..ca25ae720b 100644 --- a/headers/config/HaikuConfig.h +++ b/headers/config/HaikuConfig.h @@ -9,6 +9,7 @@ /* Determine the architecture and define macros for some fundamental properties: __HAIKU_ARCH - short name of the architecture (used in paths) + __HAIKU_ARCH_ABI - name of ABI (as in package architecture) __HAIKU_ARCH_ - defined to 1 for the respective architecture __HAIKU_ARCH_BITS - defined to 32/64 on 32/64 bit architectures (defaults to 32) @@ -19,25 +20,35 @@ */ #ifdef __INTEL__ # define __HAIKU_ARCH x86 +# if __GNUC__ == 2 +# define __HAIKU_ARCH_ABI "x86_gcc2" +# else +# define __HAIKU_ARCH_ABI "x86" +# endif # define __HAIKU_ARCH_X86 1 # define __HAIKU_ARCH_PHYSICAL_BITS 64 #elif __x86_64__ # define __HAIKU_ARCH x86_64 +# define __HAIKU_ARCH_ABI "x86_64" # define __HAIKU_ARCH_X86_64 1 # define __HAIKU_ARCH_BITS 64 #elif __POWERPC__ # define __HAIKU_ARCH ppc +# define __HAIKU_ARCH_ABI "ppc" # define __HAIKU_ARCH_PPC 1 # define __HAIKU_BIG_ENDIAN 1 #elif __M68K__ # define __HAIKU_ARCH m68k +# define __HAIKU_ARCH_ABI "m68k" # define __HAIKU_ARCH_M68K 1 # define __HAIKU_BIG_ENDIAN 1 #elif __MIPSEL__ # define __HAIKU_ARCH mipsel +# define __HAIKU_ARCH_ABI "mipsel" # define __HAIKU_ARCH_MIPSEL 1 #elif __ARM__ # define __HAIKU_ARCH arm +# define __HAIKU_ARCH_ABI "arm" # define __HAIKU_ARCH_ARM 1 #else # error Unsupported architecture! diff --git a/headers/os/BeBuild.h b/headers/os/BeBuild.h index 678bf4abad..991ef1983e 100644 --- a/headers/os/BeBuild.h +++ b/headers/os/BeBuild.h @@ -39,6 +39,8 @@ #define B_HAIKU_ABI_GCC_2_BEOS 0x00020001 #define B_HAIKU_ABI_GCC_2_HAIKU 0x00020002 +#define B_HAIKU_ABI_NAME __HAIKU_ARCH_ABI + #if __GNUC__ == 2 # define B_HAIKU_ABI B_HAIKU_ABI_GCC_2_HAIKU #elif __GNUC__ == 4 diff --git a/headers/os/storage/FindDirectory.h b/headers/os/storage/FindDirectory.h index f7814475ec..e5550cfb7e 100644 --- a/headers/os/storage/FindDirectory.h +++ b/headers/os/storage/FindDirectory.h @@ -29,6 +29,9 @@ typedef enum { B_SYSTEM_MEDIA_NODES_DIRECTORY, B_SYSTEM_SOUNDS_DIRECTORY, B_SYSTEM_DATA_DIRECTORY, + B_SYSTEM_DEVELOP_DIRECTORY, + B_SYSTEM_PACKAGES_DIRECTORY, + B_SYSTEM_HEADERS_DIRECTORY, /* Common directories, shared among all users. */ B_COMMON_DIRECTORY = 2000, @@ -52,6 +55,19 @@ typedef enum { B_COMMON_SOUNDS_DIRECTORY, B_COMMON_DATA_DIRECTORY, B_COMMON_CACHE_DIRECTORY, + B_COMMON_PACKAGES_DIRECTORY, + B_COMMON_HEADERS_DIRECTORY, + B_COMMON_NONPACKAGED_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_TRANSLATORS_DIRECTORY, + B_COMMON_NONPACKAGED_MEDIA_NODES_DIRECTORY, + B_COMMON_NONPACKAGED_BIN_DIRECTORY, + B_COMMON_NONPACKAGED_DATA_DIRECTORY, + B_COMMON_NONPACKAGED_FONTS_DIRECTORY, + B_COMMON_NONPACKAGED_SOUNDS_DIRECTORY, + B_COMMON_NONPACKAGED_DOCUMENTATION_DIRECTORY, + B_COMMON_NONPACKAGED_LIB_DIRECTORY, + B_COMMON_NONPACKAGED_HEADERS_DIRECTORY, /* User directories. These are interpreted in the context of the user making the find_directory call. */ @@ -69,11 +85,25 @@ typedef enum { B_USER_SOUNDS_DIRECTORY, B_USER_DATA_DIRECTORY, B_USER_CACHE_DIRECTORY, + B_USER_PACKAGES_DIRECTORY, + B_USER_HEADERS_DIRECTORY, + B_USER_NONPACKAGED_DIRECTORY, + B_USER_NONPACKAGED_ADDONS_DIRECTORY, + B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY, + B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY, + B_USER_NONPACKAGED_BIN_DIRECTORY, + B_USER_NONPACKAGED_DATA_DIRECTORY, + B_USER_NONPACKAGED_FONTS_DIRECTORY, + B_USER_NONPACKAGED_SOUNDS_DIRECTORY, + B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY, + B_USER_NONPACKAGED_LIB_DIRECTORY, + B_USER_NONPACKAGED_HEADERS_DIRECTORY, /* Global directories. */ B_APPS_DIRECTORY = 4000, B_PREFERENCES_DIRECTORY, B_UTILITIES_DIRECTORY, + B_PACKAGE_LINKS_DIRECTORY, /* Obsolete: Legacy BeOS definition to be phased out */ B_BEOS_DIRECTORY = 1000, diff --git a/headers/private/libroot/directories.h b/headers/private/libroot/directories.h new file mode 100644 index 0000000000..e01504bb85 --- /dev/null +++ b/headers/private/libroot/directories.h @@ -0,0 +1,68 @@ +/* + * Copyright 2011, Oliver Tappe + * Distributed under the terms of the MIT License. + */ +#ifndef _LIBROOT_DIRECTORIES_H +#define _LIBROOT_DIRECTORIES_H + + +#define kGlobalBinDirectory "/bin" +#define kGlobalEtcDirectory "/etc" +#define kGlobalPackageLinksDirectory "/package-links" +#define kGlobalSystemDirectory "/system" +#define kGlobalTempDirectory "/tmp" +#define kGlobalVarDirectory "/var" + +#define kAppsDirectory "/boot/apps" +#define kPreferencesDirectory "/boot/preferences" + +#define kAppLocalAddonsDirectory "%A/add-ons" +#define kAppLocalLibDirectory "%A/lib" + +#define kVolumeLocalSystemKernelAddonsDirectory "system/add-ons/kernel" +#define kVolumeLocalCommonNonpackagedKernelAddonsDirectory \ + "common/non-packaged/add-ons/kernel" +#define kVolumeLocalCommonKernelAddonsDirectory "common/add-ons/kernel" +#define kVolumeLocalUserNonpackagedKernelAddonsDirectory \ + "home/config/non-packaged/add-ons/kernel" +#define kVolumeLocalUserKernelAddonsDirectory "home/config/add-ons/kernel" + +#define kSystemDirectory "/boot/system" +#define kSystemAddonsDirectory "/boot/system/add-ons" +#define kSystemAppsDirectory "/boot/system/apps" +#define kSystemBinDirectory "/boot/system/bin" +#define kSystemDataDirectory "/boot/system/data" +#define kSystemDevelopDirectory "/boot/system/develop" +#define kSystemLibDirectory "/boot/system/lib" +#define kSystemPackagesDirectory "/boot/system/packages" +#define kSystemPreferencesDirectory "/boot/system/preferences" +#define kSystemServersDirectory "/boot/system/servers" + +#define kCommonDirectory "/boot/common" +#define kCommonAddonsDirectory "/boot/common/add-ons" +#define kCommonBinDirectory "/boot/common/bin" +#define kCommonDevelopToolsBinDirectory "/boot/common/develop/tools/current/bin" +#define kCommonEtcDirectory "/boot/common/settings/etc" +#define kCommonLibDirectory "/boot/common/lib" +#define kCommonPackagesDirectory "/boot/common/packages" +#define kCommonSettingsDirectory "/boot/common/settings" +#define kCommonTempDirectory "/boot/common/cache/tmp" +#define kCommonVarDirectory "/boot/common/var" +#define kCommonLogDirectory "/boot/common/var/log" +#define kCommonNonpackagedAddonsDirectory "/boot/common/non-packaged/add-ons" +#define kCommonNonpackagedBinDirectory "/boot/common/non-packaged/bin" +#define kCommonNonpackagedLibDirectory "/boot/common/non-packaged/lib" + +#define kUserDirectory "/boot/home" +#define kUserConfigDirectory "/boot/home/config" +#define kUserAddonsDirectory "/boot/home/config/add-ons" +#define kUserBinDirectory "/boot/home/config/bin" +#define kUserLibDirectory "/boot/home/config/lib" +#define kUserPackagesDirectory "/boot/home/config/packages" +#define kUserSettingsDirectory "/boot/home/config/settings" +#define kUserNonpackagedAddonsDirectory "/boot/home/config/non-packaged/add-ons" +#define kUserNonpackagedBinDirectory "/boot/home/config/non-packaged/bin" +#define kUserNonpackagedLibDirectory "/boot/home/config/non-packaged/lib" + + +#endif // _LIBROOT_DIRECTORIES_H diff --git a/src/add-ons/input_server/filters/screen_saver/ScreenSaverFilter.cpp b/src/add-ons/input_server/filters/screen_saver/ScreenSaverFilter.cpp index 90152c0e0a..c7a1c4b37e 100644 --- a/src/add-ons/input_server/filters/screen_saver/ScreenSaverFilter.cpp +++ b/src/add-ons/input_server/filters/screen_saver/ScreenSaverFilter.cpp @@ -191,7 +191,7 @@ ScreenSaverFilter::_Invoke() BPath path; if (find_directory(B_SYSTEM_BIN_DIRECTORY, &path) != B_OK || path.Append("screen_blanker") != B_OK) - path.SetTo("/boot/system/bin/screen_blanker"); + path.SetTo("/bin/screen_blanker"); BEntry entry(path.Path()); entry_ref ref; if (entry.GetRef(&ref) == B_OK diff --git a/src/add-ons/input_server/filters/shortcut_catcher/ParseCommandLine.cpp b/src/add-ons/input_server/filters/shortcut_catcher/ParseCommandLine.cpp index 18048df32b..b7dbde0d69 100644 --- a/src/add-ons/input_server/filters/shortcut_catcher/ParseCommandLine.cpp +++ b/src/add-ons/input_server/filters/shortcut_catcher/ParseCommandLine.cpp @@ -16,16 +16,19 @@ #include -#include -#include -#include #include +#include +#include +#include +#include +#include +#include #include // This char is used to hold words together into single words... #define GUNK_CHAR 0x01 -#define PATHTOTRACKER "/boot/system/Tracker" +#define PATHTOTRACKER "/system/Tracker" // Turn all spaces that are not-to-be-counted-as-spaces into GUNK_CHAR chars. static void @@ -299,11 +302,14 @@ LaunchCommand(char** argv, int32 argc) // Hack way to do this--really I should be able to do this by // sending a BMessage. But how? When I finally get my copy of the // BeOS Bible, maybe then I'll find out. - const char* trackerFile = PATHTOTRACKER; - char* temp = new char[strlen(trackerFile) + strlen(argv[0]) + 10]; - sprintf(temp, "%s '%s'", trackerFile, argv[0]); - system(temp); - delete [] temp; + BPath trackerPath; + if (find_directory(B_SYSTEM_DIRECTORY, &trackerPath) != B_OK + || trackerPath.Append("Tracker") != B_OK) { + return B_ENTRY_NOT_FOUND; + } + BString cmd(trackerPath.Path()); + cmd << " '" << argv[0] << "'"; + system(cmd.String()); return B_NO_ERROR; } else { // It's not a directory. Must be a file. diff --git a/src/add-ons/kernel/debugger/hangman/hangman.c b/src/add-ons/kernel/debugger/hangman/hangman.c index f77a7d60d4..231d004977 100644 --- a/src/add-ons/kernel/debugger/hangman/hangman.c +++ b/src/add-ons/kernel/debugger/hangman/hangman.c @@ -5,6 +5,7 @@ # include #endif +#include #include #include #include @@ -26,7 +27,7 @@ #define MAX_FAILS_BEFORE_BSOD 0 #ifdef __HAIKU__ -# define FORTUNE_FILE "/boot/system/data/fortunes/Fortunes" +# define FORTUNE_FILE kSystemDataDirectory "/fortunes/Fortunes" #else # define FORTUNE_FILE "/etc/fortunes/default" #endif diff --git a/src/add-ons/kernel/drivers/audio/ac97/auich/Jamfile b/src/add-ons/kernel/drivers/audio/ac97/auich/Jamfile index 0b55856d83..26d6af1cca 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/auich/Jamfile +++ b/src/add-ons/kernel/drivers/audio/ac97/auich/Jamfile @@ -1,7 +1,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers audio ac97 auich ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders media ; +UsePrivateHeaders libroot media ; SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) ] ; diff --git a/src/add-ons/kernel/drivers/audio/ac97/auich/debug.c b/src/add-ons/kernel/drivers/audio/ac97/auich/debug.c index 790b2a2d97..b3b4c67858 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/auich/debug.c +++ b/src/add-ons/kernel/drivers/audio/ac97/auich/debug.c @@ -28,23 +28,32 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + + #include + #include #include #include + +#include #include + #include "debug.h" #include "auich.h" + #if DEBUG > 0 -static const char * logfile="/boot/home/auich.log"; +static const char *logfile = kCommonLogDirectory "/auich.log"; static sem_id loglock; #endif + void debug_printf(const char *text,...); void log_printf(const char *text,...); void log_create(void); + void debug_printf(const char *text,...) { char buf[1024]; @@ -57,6 +66,7 @@ void debug_printf(const char *text,...) dprintf(DRIVER_NAME ": %s",buf); } + void log_create() { #if DEBUG > 0 @@ -68,6 +78,7 @@ void log_create() #endif } + void log_printf(const char *text,...) { #if DEBUG > 0 @@ -92,4 +103,3 @@ void log_printf(const char *text,...) #endif #endif } - diff --git a/src/add-ons/kernel/drivers/audio/ac97/auvia/Jamfile b/src/add-ons/kernel/drivers/audio/ac97/auvia/Jamfile index fb4c66c56e..9333f4295b 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/auvia/Jamfile +++ b/src/add-ons/kernel/drivers/audio/ac97/auvia/Jamfile @@ -1,7 +1,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers audio ac97 auvia ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders media ; +UsePrivateHeaders libroot media ; SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ; SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) ] ; diff --git a/src/add-ons/kernel/drivers/audio/ac97/auvia/debug.c b/src/add-ons/kernel/drivers/audio/ac97/auvia/debug.c index 4b67b58631..8bcc694c61 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/auvia/debug.c +++ b/src/add-ons/kernel/drivers/audio/ac97/auvia/debug.c @@ -28,23 +28,32 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + + #include + #include #include #include + +#include #include + #include "debug.h" #include "auvia.h" + #if DEBUG > 0 -static const char * logfile="/boot/home/auvia.log"; +static const char *logfile = kCommonLogDirectory "/auvia.log"; static sem_id loglock; #endif + void debug_printf(const char *text,...); void log_printf(const char *text,...); void log_create(void); + void debug_printf(const char *text,...) { char buf[1024]; @@ -57,6 +66,7 @@ void debug_printf(const char *text,...) dprintf(DRIVER_NAME ": %s",buf); } + void log_create() { #if DEBUG > 0 @@ -68,6 +78,7 @@ void log_create() #endif } + void log_printf(const char *text,...) { #if DEBUG > 0 @@ -92,4 +103,3 @@ void log_printf(const char *text,...) #endif #endif } - diff --git a/src/add-ons/kernel/drivers/audio/ac97/es1370/Jamfile b/src/add-ons/kernel/drivers/audio/ac97/es1370/Jamfile index 54259ce1e0..c3c8889e84 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/es1370/Jamfile +++ b/src/add-ons/kernel/drivers/audio/ac97/es1370/Jamfile @@ -1,7 +1,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers audio ac97 es1370 ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders media ; +UsePrivateHeaders libroot media ; SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ; KernelAddon es1370 : diff --git a/src/add-ons/kernel/drivers/audio/ac97/es1370/debug.c b/src/add-ons/kernel/drivers/audio/ac97/es1370/debug.c index 5fb661ac51..5a52fd12ce 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/es1370/debug.c +++ b/src/add-ons/kernel/drivers/audio/ac97/es1370/debug.c @@ -8,24 +8,33 @@ * Marcus Overhagen, marcus@overhagen.de * Jerome Duval, jerome.duval@free.fr */ + + #include + #include #include #include #include + +#include #include + #include "debug.h" #include "es1370.h" + #if DEBUG > 0 -static const char * logfile="/boot/home/es1370.log"; +static const char *logfile = kCommonLogDirectory "/es1370.log"; static sem_id loglock; #endif + void debug_printf(const char *text,...); void log_printf(const char *text,...); void log_create(void); + void debug_printf(const char *text,...) { char buf[1024]; @@ -38,6 +47,7 @@ void debug_printf(const char *text,...) dprintf(DRIVER_NAME ": %s",buf); } + void log_create() { #if DEBUG > 0 @@ -49,6 +59,7 @@ void log_create() #endif } + void log_printf(const char *text,...) { #if DEBUG > 0 @@ -73,4 +84,3 @@ void log_printf(const char *text,...) #endif #endif } - diff --git a/src/add-ons/kernel/drivers/audio/ac97/ich/Jamfile b/src/add-ons/kernel/drivers/audio/ac97/ich/Jamfile index e4df9219c4..b086402b3b 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/Jamfile +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers audio ac97 ich ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders media ; +UsePrivateHeaders libroot media ; KernelAddon ich_ac97 : ac97_multi.c diff --git a/src/add-ons/kernel/drivers/audio/ac97/ich/debug.c b/src/add-ons/kernel/drivers/audio/ac97/ich/debug.c index 6b9f979e8c..d516f25590 100644 --- a/src/add-ons/kernel/drivers/audio/ac97/ich/debug.c +++ b/src/add-ons/kernel/drivers/audio/ac97/ich/debug.c @@ -25,14 +25,21 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + + #include + #include #include #include + +#include #include + #include "debug.h" #include "ich.h" + void debug_printf(const char *text,...) { char buf[1024]; @@ -45,11 +52,12 @@ void debug_printf(const char *text,...) dprintf(DRIVER_NAME ": %s",buf); } -#if DEBUG > 0 -static const char * logfile="/boot/home/ich_ac97.log"; +#if DEBUG > 0 +static const char *logfile = kCommonLogDirectory "/ich_ac97.log"; static sem_id loglock; + void log_create(void) { int fd = open(logfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); @@ -59,6 +67,7 @@ void log_create(void) close(fd); } + void log_printf(const char *text,...) { int fd; @@ -81,5 +90,4 @@ void log_printf(const char *text,...) snooze(150000); #endif } - #endif diff --git a/src/add-ons/kernel/drivers/audio/echo/24/Jamfile b/src/add-ons/kernel/drivers/audio/echo/24/Jamfile index aa48416310..2f4a938c55 100644 --- a/src/add-ons/kernel/drivers/audio/echo/24/Jamfile +++ b/src/add-ons/kernel/drivers/audio/echo/24/Jamfile @@ -13,7 +13,7 @@ SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers audio echo generic DSP ; SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers audio echo generic ASIC ; UsePrivateHeaders [ FDirName kernel ] # For kernel_cpp.cpp - media ; + libroot media ; # set some additional defines SubDirCcFlags -DECHO_BEOS -DECHO24_FAMILY ; diff --git a/src/add-ons/kernel/drivers/audio/echo/3g/Jamfile b/src/add-ons/kernel/drivers/audio/echo/3g/Jamfile index ec9b38f38b..6a25fd102d 100644 --- a/src/add-ons/kernel/drivers/audio/echo/3g/Jamfile +++ b/src/add-ons/kernel/drivers/audio/echo/3g/Jamfile @@ -13,7 +13,7 @@ SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers audio echo generic DSP ; SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers audio echo generic ASIC ; UsePrivateHeaders [ FDirName kernel ] # For kernel_cpp.cpp - media ; + libroot media ; # set some additional defines SubDirCcFlags -DECHO_BEOS -DECHO3G_FAMILY ; diff --git a/src/add-ons/kernel/drivers/audio/echo/debug.c b/src/add-ons/kernel/drivers/audio/echo/debug.c index 1cb2b4fffc..2c183ebfad 100644 --- a/src/add-ons/kernel/drivers/audio/echo/debug.c +++ b/src/add-ons/kernel/drivers/audio/echo/debug.c @@ -28,21 +28,30 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + + #include + #include #include #include + +#include #include + #include "debug.h" + #if DEBUG > 0 -static const char * logfile="/boot/home/"DRIVER_NAME".log"; +static const char *logfile = kCommonLogDirectory "/" DRIVER_NAME ".log"; static sem_id loglock; #endif + void debug_printf(const char *text,...); void log_printf(const char *text,...); + void debug_printf(const char *text,...) { char buf[1024]; @@ -55,6 +64,7 @@ void debug_printf(const char *text,...) dprintf(DRIVER_NAME ": %s",buf); } + void log_create() { #if DEBUG > 0 @@ -66,6 +76,7 @@ void log_create() #endif } + void log_printf(const char *text,...) { #if DEBUG > 0 @@ -90,4 +101,3 @@ void log_printf(const char *text,...) #endif #endif } - diff --git a/src/add-ons/kernel/drivers/audio/echo/gals/Jamfile b/src/add-ons/kernel/drivers/audio/echo/gals/Jamfile index 5719258c14..bc21b01601 100644 --- a/src/add-ons/kernel/drivers/audio/echo/gals/Jamfile +++ b/src/add-ons/kernel/drivers/audio/echo/gals/Jamfile @@ -13,7 +13,7 @@ SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers audio echo generic DSP ; SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers audio echo generic ASIC ; UsePrivateHeaders [ FDirName kernel ] # For kernel_cpp.cpp - media ; + libroot media ; # set some additional defines SubDirCcFlags -DECHO_BEOS -DECHOGALS_FAMILY ; diff --git a/src/add-ons/kernel/drivers/audio/echo/indigo/Jamfile b/src/add-ons/kernel/drivers/audio/echo/indigo/Jamfile index b797396238..fe661cce66 100644 --- a/src/add-ons/kernel/drivers/audio/echo/indigo/Jamfile +++ b/src/add-ons/kernel/drivers/audio/echo/indigo/Jamfile @@ -13,7 +13,7 @@ SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers audio echo generic DSP ; SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers audio echo generic ASIC ; UsePrivateHeaders [ FDirName kernel ] # For kernel_cpp.cpp - media ; + libroot media ; # set some additional defines SubDirCcFlags -DECHO_BEOS -DINDIGO_FAMILY -DCARDBUS ; diff --git a/src/add-ons/kernel/drivers/audio/emuxki/Jamfile b/src/add-ons/kernel/drivers/audio/emuxki/Jamfile index d7ac8abbc4..f3f71b1e67 100644 --- a/src/add-ons/kernel/drivers/audio/emuxki/Jamfile +++ b/src/add-ons/kernel/drivers/audio/emuxki/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers audio emuxki ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders media ; +UsePrivateHeaders libroot media ; KernelAddon emuxki : ac97.c diff --git a/src/add-ons/kernel/drivers/audio/emuxki/debug.c b/src/add-ons/kernel/drivers/audio/emuxki/debug.c index f3dbc1db23..349dbf0c54 100644 --- a/src/add-ons/kernel/drivers/audio/emuxki/debug.c +++ b/src/add-ons/kernel/drivers/audio/emuxki/debug.c @@ -28,23 +28,32 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + + #include + #include #include #include + +#include #include + #include "debug.h" #include "emuxki.h" + #if DEBUG > 0 -static const char * logfile="/boot/home/emuxki.log"; +static const char *logfile = kCommonLogDirectory "/emuxki.log"; static sem_id loglock; #endif + void debug_printf(const char *text,...); void log_printf(const char *text,...); void log_create(void); + void debug_printf(const char *text,...) { char buf[1024]; @@ -57,6 +66,7 @@ void debug_printf(const char *text,...) dprintf(DRIVER_NAME ": %s",buf); } + void log_create() { #if DEBUG > 0 @@ -68,6 +78,7 @@ void log_create() #endif } + void log_printf(const char *text,...) { #if DEBUG > 0 @@ -92,4 +103,3 @@ void log_printf(const char *text,...) #endif #endif } - diff --git a/src/add-ons/kernel/drivers/audio/module_driver/Jamfile b/src/add-ons/kernel/drivers/audio/module_driver/Jamfile index 860bc2157e..b2351085b8 100644 --- a/src/add-ons/kernel/drivers/audio/module_driver/Jamfile +++ b/src/add-ons/kernel/drivers/audio/module_driver/Jamfile @@ -1,6 +1,6 @@ SubDir HAIKU_TOP src add-ons kernel drivers audio module_driver ; -UsePrivateHeaders media ; +UsePrivateHeaders libroot media ; KernelAddon audio_module_driver : audio_module_driver.c diff --git a/src/add-ons/kernel/drivers/audio/module_driver/audio_module_driver.c b/src/add-ons/kernel/drivers/audio/module_driver/audio_module_driver.c index f8c01011ac..9fea1d7c48 100644 --- a/src/add-ons/kernel/drivers/audio/module_driver/audio_module_driver.c +++ b/src/add-ons/kernel/drivers/audio/module_driver/audio_module_driver.c @@ -8,15 +8,20 @@ * */ + #include +#include #include #include #include + #include #include #include + #include "audio_module.h" + int32 api_version = B_CUR_DRIVER_API_VERSION; #define DRIVER_NAME "audio_module_driver" @@ -29,6 +34,7 @@ void republish_devices(void); extern image_id load_kernel_addon(const char *path); extern status_t unload_kernel_addon(image_id imid); + status_t init_hardware(void) { @@ -36,6 +42,7 @@ init_hardware(void) return B_OK; } + status_t init_driver(void) { @@ -44,8 +51,9 @@ init_driver(void) status_t rv; void (*print_hello_world)(void); - id = load_kernel_addon("/boot/home/config/add-ons/kernel/media/audio/ich"); - get_image_symbol(id, "print_hello_world", B_SYMBOL_TYPE_TEXT, (void **) &print_hello_world); + id = load_kernel_addon(kUserAddonsDirectory "/kernel/media/audio/ich"); + get_image_symbol(id, "print_hello_world", B_SYMBOL_TYPE_TEXT, + (void **) &print_hello_world); print_hello_world(); unload_kernel_addon(id); if (rv != B_OK) @@ -71,12 +79,14 @@ init_driver(void) return B_OK; } + void uninit_driver(void) { dprintf("audio_module_driver: uninit_driver\n"); } + static status_t audio_module_driver_open(const char *name, uint32 flags, void **cookie) { @@ -84,6 +94,7 @@ audio_module_driver_open(const char *name, uint32 flags, void **cookie) return B_OK; } + static status_t audio_module_driver_close(void *cookie) { @@ -91,6 +102,7 @@ audio_module_driver_close(void *cookie) return B_OK; } + static status_t audio_module_driver_free(void *cookie) { @@ -98,6 +110,7 @@ audio_module_driver_free(void *cookie) return B_OK; } + static status_t audio_module_driver_control(void *cookie, uint32 op, void *arg, size_t len) { @@ -108,22 +121,28 @@ audio_module_driver_control(void *cookie, uint32 op, void *arg, size_t len) } } + static status_t -audio_module_driver_read(void *cookie, off_t position, void *buf, size_t *num_bytes) +audio_module_driver_read(void *cookie, off_t position, void *buf, + size_t *num_bytes) { *num_bytes = 0; return B_IO_ERROR; } + static status_t -audio_module_driver_write(void *cookie, off_t position, const void *buffer, size_t *num_bytes) +audio_module_driver_write(void *cookie, off_t position, const void *buffer, + size_t *num_bytes) { static int keep_open_fd = -1; - if (*num_bytes >= 5 && 0 == memcmp("start", buffer, 5) && keep_open_fd == -1) { + if (*num_bytes >= 5 && 0 == memcmp("start", buffer, 5) + && keep_open_fd == -1) { keep_open_fd = open("/dev/audio/audio_module_driver", O_RDWR); return B_OK; } - if (*num_bytes >= 4 && 0 == memcmp("stop", buffer, 4) && keep_open_fd != -1) { + if (*num_bytes >= 4 && 0 == memcmp("stop", buffer, 4) + && keep_open_fd != -1) { close(keep_open_fd); keep_open_fd = -1; return B_OK; @@ -136,6 +155,7 @@ audio_module_driver_write(void *cookie, off_t position, const void *buffer, size return B_IO_ERROR; } + static const char *ich_name[] = { "audio/" DRIVER_NAME, "audio/modules/foobar/1", @@ -145,6 +165,7 @@ static const char *ich_name[] = { NULL }; + device_hooks audio_module_driver_hooks = { audio_module_driver_open, audio_module_driver_close, @@ -158,6 +179,7 @@ device_hooks audio_module_driver_hooks = { NULL }; + const char** publish_devices(void) { @@ -165,6 +187,7 @@ publish_devices(void) return ich_name; } + device_hooks* find_device(const char *name) { diff --git a/src/add-ons/kernel/drivers/graphics/matrox/Jamfile b/src/add-ons/kernel/drivers/graphics/matrox/Jamfile index 1a18f79ef0..fc53de96a5 100644 --- a/src/add-ons/kernel/drivers/graphics/matrox/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/matrox/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers graphics matrox ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders graphics ; +UsePrivateHeaders graphics libroot ; UsePrivateHeaders [ FDirName graphics matrox ] ; KernelAddon matrox : diff --git a/src/add-ons/kernel/drivers/graphics/matrox/driver.c b/src/add-ons/kernel/drivers/graphics/matrox/driver.c index 8a14fe92a1..272413cdd1 100644 --- a/src/add-ons/kernel/drivers/graphics/matrox/driver.c +++ b/src/add-ons/kernel/drivers/graphics/matrox/driver.c @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include // for strtoXX @@ -142,7 +143,7 @@ static void dumprom (void *rom, size_t size, pci_info pcii) char fname[64]; /* determine the romfile name: we need split-up per card in the system */ - sprintf (fname, "/boot/home/" DRIVER_PREFIX "." DEVICE_FORMAT ".rom", + sprintf (fname, kUserDirectory "/" DRIVER_PREFIX "." DEVICE_FORMAT ".rom", pcii.vendor_id, pcii.device_id, pcii.bus, pcii.device, pcii.function); fd = open (fname, O_WRONLY | O_CREAT, 0666); diff --git a/src/add-ons/kernel/drivers/graphics/neomagic/Jamfile b/src/add-ons/kernel/drivers/graphics/neomagic/Jamfile index 60e274cf47..3ea2159453 100644 --- a/src/add-ons/kernel/drivers/graphics/neomagic/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/neomagic/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers graphics neomagic ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders graphics ; +UsePrivateHeaders graphics libroot ; UsePrivateHeaders [ FDirName graphics neomagic ] ; KernelAddon neomagic : diff --git a/src/add-ons/kernel/drivers/graphics/neomagic/driver.c b/src/add-ons/kernel/drivers/graphics/neomagic/driver.c index fad85ad153..0a1618310b 100644 --- a/src/add-ons/kernel/drivers/graphics/neomagic/driver.c +++ b/src/add-ons/kernel/drivers/graphics/neomagic/driver.c @@ -13,6 +13,7 @@ #include #include #include +#include #include #include #include // for strtoXX @@ -138,7 +139,8 @@ static void dumprom (void *rom, uint32 size) int fd; uint32 cnt; - fd = open ("/boot/home/" DRIVER_PREFIX ".rom", O_WRONLY | O_CREAT, 0666); + fd = open (kUserDirectory "/" DRIVER_PREFIX ".rom", + O_WRONLY | O_CREAT, 0666); if (fd < 0) return; /* apparantly max. 32kb may be written at once; diff --git a/src/add-ons/kernel/drivers/graphics/nvidia/Jamfile b/src/add-ons/kernel/drivers/graphics/nvidia/Jamfile index feac1b806f..3ec19127f2 100644 --- a/src/add-ons/kernel/drivers/graphics/nvidia/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/nvidia/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers graphics nvidia ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders graphics ; +UsePrivateHeaders graphics libroot ; UsePrivateHeaders [ FDirName graphics nvidia ] ; UsePrivateHeaders [ FDirName graphics common ] ; diff --git a/src/add-ons/kernel/drivers/graphics/nvidia/driver.c b/src/add-ons/kernel/drivers/graphics/nvidia/driver.c index 7b2e383ef9..6f18ac995f 100644 --- a/src/add-ons/kernel/drivers/graphics/nvidia/driver.c +++ b/src/add-ons/kernel/drivers/graphics/nvidia/driver.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -400,7 +401,7 @@ dumprom(void *rom, uint32 size, pci_info pcii) char fname[64]; /* determine the romfile name: we need split-up per card in the system */ - sprintf (fname, "/boot/home/" DRIVER_PREFIX "." DEVICE_FORMAT ".rom", + sprintf (fname, kUserDirectory "//" DRIVER_PREFIX "." DEVICE_FORMAT ".rom", pcii.vendor_id, pcii.device_id, pcii.bus, pcii.device, pcii.function); fd = open (fname, O_WRONLY | O_CREAT, 0666); diff --git a/src/add-ons/kernel/drivers/graphics/nvidia_gpgpu/Jamfile b/src/add-ons/kernel/drivers/graphics/nvidia_gpgpu/Jamfile index bda9f4854b..2c2b581465 100644 --- a/src/add-ons/kernel/drivers/graphics/nvidia_gpgpu/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/nvidia_gpgpu/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers graphics nvidia_gpgpu ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders graphics ; +UsePrivateHeaders graphics libroot ; UsePrivateHeaders [ FDirName graphics nvidia_gpgpu ] ; KernelAddon nvidia_gpgpu : diff --git a/src/add-ons/kernel/drivers/graphics/nvidia_gpgpu/driver.c b/src/add-ons/kernel/drivers/graphics/nvidia_gpgpu/driver.c index 1eafd322e9..11858429c6 100644 --- a/src/add-ons/kernel/drivers/graphics/nvidia_gpgpu/driver.c +++ b/src/add-ons/kernel/drivers/graphics/nvidia_gpgpu/driver.c @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -160,7 +161,7 @@ dumprom(void *rom, uint32 size, pci_info pcii) char fname[64]; /* determine the romfile name: we need split-up per card in the system */ - sprintf (fname, "/boot/home/" DRIVER_PREFIX "." DEVICE_FORMAT ".rom", + sprintf (fname, kUserDirectory "/" DRIVER_PREFIX "." DEVICE_FORMAT ".rom", pcii.vendor_id, pcii.device_id, pcii.bus, pcii.device, pcii.function); fd = open (fname, O_WRONLY | O_CREAT, 0666); diff --git a/src/add-ons/kernel/drivers/graphics/skeleton/Jamfile b/src/add-ons/kernel/drivers/graphics/skeleton/Jamfile index aade3b646f..914ca86f58 100644 --- a/src/add-ons/kernel/drivers/graphics/skeleton/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/skeleton/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers graphics skeleton ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders graphics ; +UsePrivateHeaders graphics libroot ; UsePrivateHeaders [ FDirName graphics skeleton ] ; KernelAddon skel.driver : diff --git a/src/add-ons/kernel/drivers/graphics/skeleton/driver.c b/src/add-ons/kernel/drivers/graphics/skeleton/driver.c index 26e0f4cdc3..1630070ee7 100644 --- a/src/add-ons/kernel/drivers/graphics/skeleton/driver.c +++ b/src/add-ons/kernel/drivers/graphics/skeleton/driver.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include // for strtoXX @@ -130,7 +131,8 @@ static void dumprom (void *rom, uint32 size) int fd; uint32 cnt; - fd = open ("/boot/home/" DRIVER_PREFIX ".rom", O_WRONLY | O_CREAT, 0666); + fd = open (kUserDirectory "/" DRIVER_PREFIX ".rom", + O_WRONLY | O_CREAT, 0666); if (fd < 0) return; /* apparantly max. 32kb may be written at once; diff --git a/src/add-ons/kernel/drivers/graphics/via/Jamfile b/src/add-ons/kernel/drivers/graphics/via/Jamfile index e988811ad7..5ae8061f0a 100644 --- a/src/add-ons/kernel/drivers/graphics/via/Jamfile +++ b/src/add-ons/kernel/drivers/graphics/via/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers graphics via ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders graphics ; +UsePrivateHeaders graphics libroot ; UsePrivateHeaders [ FDirName graphics via ] ; KernelAddon via : diff --git a/src/add-ons/kernel/drivers/graphics/via/driver.c b/src/add-ons/kernel/drivers/graphics/via/driver.c index 1639712731..5b572647e5 100644 --- a/src/add-ons/kernel/drivers/graphics/via/driver.c +++ b/src/add-ons/kernel/drivers/graphics/via/driver.c @@ -12,6 +12,7 @@ #include #include #include +#include #include #include #include // for strtoXX @@ -135,7 +136,8 @@ static void dumprom (void *rom, uint32 size) int fd; uint32 cnt; - fd = open ("/boot/home/" DRIVER_PREFIX ".rom", O_WRONLY | O_CREAT, 0666); + fd = open (kUserDirectory "/" DRIVER_PREFIX ".rom", + O_WRONLY | O_CREAT, 0666); if (fd < 0) return; /* apparantly max. 32kb may be written at once; diff --git a/src/add-ons/kernel/drivers/network/sis900/Jamfile b/src/add-ons/kernel/drivers/network/sis900/Jamfile index eba437f251..e7e994bd18 100644 --- a/src/add-ons/kernel/drivers/network/sis900/Jamfile +++ b/src/add-ons/kernel/drivers/network/sis900/Jamfile @@ -4,7 +4,7 @@ SetSubDirSupportedPlatformsBeOSCompatible ; # For ether_driver.h -UsePrivateHeaders net ; +UsePrivateHeaders libroot net ; KernelAddon sis900 : driver.c diff --git a/src/add-ons/kernel/drivers/network/sis900/device.c b/src/add-ons/kernel/drivers/network/sis900/device.c index 95e71c0ff7..8af7a80924 100644 --- a/src/add-ons/kernel/drivers/network/sis900/device.c +++ b/src/add-ons/kernel/drivers/network/sis900/device.c @@ -11,6 +11,7 @@ #include "interface.h" #include "sis900.h" +#include #include #include @@ -63,7 +64,8 @@ bug(const char *format, ...) int i; int file; - if ((file = open("/boot/home/sis900-driver.log", O_RDWR | O_APPEND | O_CREAT)) >= 0) { + if ((file = open(kCommonLogDirectory "/sis900-driver.log", + O_RDWR | O_APPEND | O_CREAT)) >= 0) { // time_t timer = time(NULL); // strftime(c, 2048, "%H:%M:S: ", localtime(&timer)); diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Driver.h b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Driver.h index 27de91df57..d7d94dc39f 100644 --- a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Driver.h +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Driver.h @@ -26,15 +26,18 @@ #include #include +#include #include #define DRIVER_NAME "usb_beceemwmx" #define MAX_DEVICES 8 -#define FIRM_BIN "/boot/system/data/firmware/macxvi200/macxvi200.bin" +#define FIRM_BIN \ + kSystemDataDirectory "/firmware/macxvi200/macxvi200.bin" // location on file system of device firmware -#define FIRM_CFG "/boot/system/data/firmware/macxvi200/macxvi.cfg" +#define FIRM_CFG \ + kSystemDataDirectory "/firmware/macxvi200/macxvi.cfg" // location on file system of vendor configuration #define SYS_CFG 0x0F000C00 diff --git a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Jamfile b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Jamfile index 082adfe93c..3ee4269323 100644 --- a/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Jamfile +++ b/src/add-ons/kernel/drivers/network/wimax/usb_beceemwmx/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers network wimax usb_beceemwmx ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders kernel net ; +UsePrivateHeaders kernel libroot net ; KernelAddon usb_beceemwmx : Driver.cpp diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/Jamfile b/src/add-ons/kernel/drivers/ports/pc_serial/Jamfile index cf59644608..c0fb71d9aa 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/Jamfile +++ b/src/add-ons/kernel/drivers/ports/pc_serial/Jamfile @@ -3,6 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers ports pc_serial ; SetSubDirSupportedPlatformsBeOSCompatible ; if $(TARGET_PLATFORM_HAIKU_COMPATIBLE) { + UsePrivateHeaders libroot ; UsePrivateKernelHeaders ; UseHeaders [ FDirName $(HAIKU_TOP) headers os drivers tty ] : true ; } diff --git a/src/add-ons/kernel/drivers/ports/pc_serial/Tracing.cpp b/src/add-ons/kernel/drivers/ports/pc_serial/Tracing.cpp index 1cf8292134..39b82d91d2 100644 --- a/src/add-ons/kernel/drivers/ports/pc_serial/Tracing.cpp +++ b/src/add-ons/kernel/drivers/ports/pc_serial/Tracing.cpp @@ -11,6 +11,7 @@ #include //sprintf #include //posix file i/o - create, write, close #include +#include #include @@ -26,7 +27,7 @@ bool gLogFunctionCalls = false; bool gLogFunctionReturns = false; bool gLogFunctionResults = false; -static const char *sLogFilePath="/boot/home/"DRIVER_NAME".log"; +static const char *sLogFilePath = kCommonLogDirectory "/" DRIVER_NAME ".log"; static sem_id sLogLock; @@ -187,4 +188,4 @@ trace_tty(struct tty *tty) } -#endif /* __BEOS__ */ \ No newline at end of file +#endif /* __BEOS__ */ diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/Jamfile b/src/add-ons/kernel/drivers/ports/usb_serial/Jamfile index 1240a5a24e..706f063af3 100644 --- a/src/add-ons/kernel/drivers/ports/usb_serial/Jamfile +++ b/src/add-ons/kernel/drivers/ports/usb_serial/Jamfile @@ -1,6 +1,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers ports usb_serial ; UsePrivateKernelHeaders ; +UsePrivateHeaders libroot ; UseHeaders [ FDirName $(HAIKU_TOP) headers os drivers tty ] : true ; SubDirC++Flags -fno-rtti ; diff --git a/src/add-ons/kernel/drivers/ports/usb_serial/Tracing.cpp b/src/add-ons/kernel/drivers/ports/usb_serial/Tracing.cpp index e4d36ff1f4..40ad7afe45 100644 --- a/src/add-ons/kernel/drivers/ports/usb_serial/Tracing.cpp +++ b/src/add-ons/kernel/drivers/ports/usb_serial/Tracing.cpp @@ -12,6 +12,7 @@ #include //sprintf #include //posix file i/o - create, write, close #include +#include #include @@ -27,7 +28,7 @@ bool gLogFunctionCalls = true; bool gLogFunctionReturns = true; bool gLogFunctionResults = true; -static const char *sLogFilePath="/boot/home/"DRIVER_NAME".log"; +static const char *sLogFilePath = kCommonLogDirectory "/" DRIVER_NAME ".log"; static sem_id sLogLock; diff --git a/src/add-ons/kernel/drivers/video/usb_vision/Jamfile b/src/add-ons/kernel/drivers/video/usb_vision/Jamfile index 0c1f2e9e34..11a6ebdfb7 100644 --- a/src/add-ons/kernel/drivers/video/usb_vision/Jamfile +++ b/src/add-ons/kernel/drivers/video/usb_vision/Jamfile @@ -2,7 +2,7 @@ SubDir HAIKU_TOP src add-ons kernel drivers video usb_vision ; SetSubDirSupportedPlatformsBeOSCompatible ; -UsePrivateHeaders usb_vision ; +UsePrivateHeaders libroot usb_vision ; #local defines = [ FDefines DB_USB_USE_V2_MODULE ] ; #SubDirCcFlags $(defines) ; diff --git a/src/add-ons/kernel/drivers/video/usb_vision/tracing.c b/src/add-ons/kernel/drivers/video/usb_vision/tracing.c index 70e1e65efb..a77c2f8854 100644 --- a/src/add-ons/kernel/drivers/video/usb_vision/tracing.c +++ b/src/add-ons/kernel/drivers/video/usb_vision/tracing.c @@ -12,6 +12,7 @@ #include //sprintf #include //strcpy #include //posix file i/o - create, write, close +#include #include #include "usb_vision.h" @@ -30,7 +31,8 @@ bool b_log_funcres = false; bool b_log_settings_loaded = false; -static const char *private_log_path="/boot/home/"DRIVER_NAME".log"; +static const char *private_log_path + = kCommonLogDirectory "/" DRIVER_NAME ".log"; static sem_id loglock; void load_setting(void){ diff --git a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Jamfile b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Jamfile index 430390d1fe..153fd267c8 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Jamfile +++ b/src/add-ons/kernel/file_systems/userlandfs/kernel_add_on/Jamfile @@ -4,7 +4,7 @@ local userlandFSTop = [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems userlandfs ] ; local userlandFSIncludes = [ PrivateHeaders userlandfs ] ; -UsePrivateHeaders shared ; +UsePrivateHeaders libroot shared ; UsePrivateKernelHeaders ; SubDirHdrs [ FDirName $(userlandFSIncludes) private ] ; SubDirHdrs [ FDirName $(userlandFSIncludes) shared ] ; diff --git a/src/add-ons/kernel/file_systems/userlandfs/shared/driver_settings.c b/src/add-ons/kernel/file_systems/userlandfs/shared/driver_settings.c index afdc7db3a9..f6adb5400c 100644 --- a/src/add-ons/kernel/file_systems/userlandfs/shared/driver_settings.c +++ b/src/add-ons/kernel/file_systems/userlandfs/shared/driver_settings.c @@ -6,6 +6,7 @@ #include +#include #include #include @@ -37,7 +38,7 @@ strlcat(char *dst, char const *src, size_t s) return j + i + strlen(src + i); } -#define SETTINGS_DIRECTORY "/boot/home/config/settings/kernel/drivers/" +#define SETTINGS_DIRECTORY kUserSettingsDirectory "/kernel/drivers/" #define SETTINGS_MAGIC 'DrvS' // Those maximum values are independent from the implementation - they diff --git a/src/add-ons/kernel/generic/mpu401/Jamfile b/src/add-ons/kernel/generic/mpu401/Jamfile index 9bc3754823..61b9be3883 100644 --- a/src/add-ons/kernel/generic/mpu401/Jamfile +++ b/src/add-ons/kernel/generic/mpu401/Jamfile @@ -1,5 +1,7 @@ SubDir HAIKU_TOP src add-ons kernel generic mpu401 ; +UsePrivateHeaders libroot ; + KernelAddon mpu401 : mpu401.c debug.c diff --git a/src/add-ons/kernel/generic/mpu401/debug.c b/src/add-ons/kernel/generic/mpu401/debug.c index 9d2187d0d9..fb9bbcaa49 100644 --- a/src/add-ons/kernel/generic/mpu401/debug.c +++ b/src/add-ons/kernel/generic/mpu401/debug.c @@ -25,17 +25,25 @@ * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. * */ + + #include +#include + #include #include -#include -#include #include +#include + +#include + #include "debug.h" + #define DRIVER_NAME "mpu401" #define VERSION "0.2" + void debug_printf(const char *text,...) { char buf[1024]; @@ -48,11 +56,12 @@ void debug_printf(const char *text,...) dprintf(DRIVER_NAME ": %s",buf); } -#if DEBUG > 0 -static const char * logfile="/boot/home/mpu401.log"; +#if DEBUG > 0 +static const char *logfile = kCommonLogDirectory "/mpu401.log"; static sem_id loglock; + void log_create(void) { int fd = open(logfile, O_WRONLY | O_CREAT | O_TRUNC, 0666); @@ -62,6 +71,7 @@ void log_create(void) close(fd); } + void log_printf(const char *text,...) { int fd; @@ -84,5 +94,4 @@ void log_printf(const char *text,...) snooze(150000); #endif } - #endif diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/Jamfile b/src/add-ons/kernel/network/ppp/shared/libkernelppp/Jamfile index 4b838d7e96..3b701b50d7 100644 --- a/src/add-ons/kernel/network/ppp/shared/libkernelppp/Jamfile +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/Jamfile @@ -10,7 +10,7 @@ if $(TARGET_PLATFORM) != haiku { # Unfortunately we get more than we want, namely all POSIX headers. } -UsePrivateHeaders net ; +UsePrivateHeaders libroot net ; UsePrivateHeaders [ FDirName kernel ] ; UsePrivateHeaders [ FDirName kernel util ] ; UseHeaders [ FDirName $(HAIKU_TOP) src add-ons kernel network ppp shared diff --git a/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/PPPDefs.h b/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/PPPDefs.h index 6ec06bbefd..afa85d1a43 100644 --- a/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/PPPDefs.h +++ b/src/add-ons/kernel/network/ppp/shared/libkernelppp/headers/PPPDefs.h @@ -8,6 +8,8 @@ #include +#include + #include "net_module.h" @@ -37,10 +39,10 @@ typedef uint32 ppp_interface_id; // path defines #define PPP_MODULES_PATH NETWORK_MODULES_ROOT "ppp" #define PTP_INTERFACE_SETTINGS_PATH \ - "/boot/home/config/settings/kernel/drivers/ptpnet" + kUserSettingsDirectory "/kernel/drivers/ptpnet" // TODO: should be: /etc/ptpnet #define PTP_SETTINGS_PATH \ - "/boot/home/config/settings/kernel/drivers/ptpnet.settings" + kUserSettingsDirectory "/kernel/drivers/ptpnet.settings" // TODO: should be: /etc/ptpnet.settings // built-in protocols diff --git a/src/apps/aboutsystem/AboutSystem.cpp b/src/apps/aboutsystem/AboutSystem.cpp index 6ccfb49c57..25898aff2b 100644 --- a/src/apps/aboutsystem/AboutSystem.cpp +++ b/src/apps/aboutsystem/AboutSystem.cpp @@ -555,28 +555,10 @@ AboutView::AboutView() versionView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_UNSET)); - // GCC version - BEntry gccFourHybrid("/boot/system/lib/gcc2/libstdc++.r4.so"); - BEntry gccTwoHybrid("/boot/system/lib/gcc4/libsupc++.so"); - bool isHybrid = gccFourHybrid.Exists() || gccTwoHybrid.Exists(); - - if (isHybrid) { - snprintf(string, sizeof(string), B_TRANSLATE("GCC %d Hybrid"), - __GNUC__); - } else - snprintf(string, sizeof(string), "GCC %d", __GNUC__); - - BStringView* gccView = new BStringView("gcctext", string); - gccView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, + BStringView* abiView = new BStringView("abitext", B_HAIKU_ABI_NAME); + abiView->SetExplicitAlignment(BAlignment(B_ALIGN_LEFT, B_ALIGN_VERTICAL_UNSET)); -#if __GNUC__ == 2 - if (isHybrid) { - // do now show the GCC version if it's the default - gccView->Hide(); - } -#endif - // CPU count, type and clock speed char processorLabel[256]; if (systemInfo.cpu_count > 1) { @@ -643,7 +625,7 @@ AboutView::AboutView() .AddGroup(B_VERTICAL, 0) .Add(_CreateLabel("oslabel", B_TRANSLATE("Version:"))) .Add(versionView) - .Add(gccView) + .Add(abiView) .AddStrut(offset) .Add(_CreateLabel("cpulabel", processorLabel)) .Add(cpuView) diff --git a/src/apps/deskbar/BarApp.cpp b/src/apps/deskbar/BarApp.cpp index 58664f75a7..bb4ecc4626 100644 --- a/src/apps/deskbar/BarApp.cpp +++ b/src/apps/deskbar/BarApp.cpp @@ -56,7 +56,7 @@ All rights reserved. #include "BarApp.h" #include "BarView.h" #include "BarWindow.h" -#include "DeskBarUtils.h" +#include "DeskbarUtils.h" #include "FSUtils.h" #include "PublicCommands.h" #include "ResourceSet.h" @@ -69,7 +69,7 @@ BList TBarApp::sBarTeamInfoList; BList TBarApp::sSubscribers; -const uint32 kShowBeMenu = 'BeMn'; +const uint32 kShowDeskbarMenu = 'BeMn'; const uint32 kShowTeamMenu = 'TmMn'; @@ -332,9 +332,9 @@ TBarApp::MessageReceived(BMessage* message) fPreferencesWindow->PostMessage(kStateChanged); break; - case kShowBeMenu: + case kShowDeskbarMenu: if (fBarWindow->Lock()) { - fBarWindow->ShowBeMenu(); + fBarWindow->ShowDeskbarMenu(); fBarWindow->Unlock(); } break; diff --git a/src/apps/deskbar/BarMenuBar.cpp b/src/apps/deskbar/BarMenuBar.cpp index c51f6c99ea..b03936e598 100644 --- a/src/apps/deskbar/BarMenuBar.cpp +++ b/src/apps/deskbar/BarMenuBar.cpp @@ -45,8 +45,8 @@ All rights reserved. #include "icons.h" #include "icons_logo.h" #include "BarWindow.h" -#include "BeMenu.h" -#include "DeskBarUtils.h" +#include "DeskbarMenu.h" +#include "DeskbarUtils.h" #include "ResourceSet.h" #include "TeamMenu.h" @@ -58,12 +58,12 @@ TBarMenuBar::TBarMenuBar(TBarView* bar, BRect frame, const char* name) { SetItemMargins(0.0f, 0.0f, 0.0f, 0.0f); - TBeMenu* beMenu = new TBeMenu(bar); - TBarWindow::SetBeMenu(beMenu); + TDeskbarMenu* beMenu = new TDeskbarMenu(bar); + TBarWindow::SetDeskbarMenu(beMenu); - fBeMenuItem = new TBarMenuTitle(frame.Width(), frame.Height(), + fDeskbarMenuItem = new TBarMenuTitle(frame.Width(), frame.Height(), AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_LeafLogoBitmap), beMenu); - AddItem(fBeMenuItem); + AddItem(fDeskbarMenuItem); } @@ -85,8 +85,8 @@ TBarMenuBar::SmartResize(float width, float height) width -= 1; int32 count = CountItems(); - if (fBeMenuItem) - fBeMenuItem->SetWidthHeight(width / count, height); + if (fDeskbarMenuItem) + fDeskbarMenuItem->SetWidthHeight(width / count, height); if (fAppListMenuItem) fAppListMenuItem->SetWidthHeight(width / count, height); @@ -195,10 +195,10 @@ TBarMenuBar::InitTrackingHook(bool (*hookFunction)(BMenu*, void*), uint32 buttons; GetMouse(&loc, &buttons); // set the hook functions for the two menus - // will always have the be menu + // will always have the deskbar menu // may have the app menu as well (mini mode) - if (fBeMenuItem->Frame().Contains(loc) || both) - init_tracking_hook(fBeMenuItem, hookFunction, state); + if (fDeskbarMenuItem->Frame().Contains(loc) || both) + init_tracking_hook(fDeskbarMenuItem, hookFunction, state); if (fAppListMenuItem && (fAppListMenuItem->Frame().Contains(loc) || both)) init_tracking_hook(fAppListMenuItem, hookFunction, state); diff --git a/src/apps/deskbar/BarMenuBar.h b/src/apps/deskbar/BarMenuBar.h index f748882f44..3adaa97967 100644 --- a/src/apps/deskbar/BarMenuBar.h +++ b/src/apps/deskbar/BarMenuBar.h @@ -67,7 +67,7 @@ class TBarMenuBar : public BMenuBar { private: TBarView* fBarView; - TBarMenuTitle* fBeMenuItem; + TBarMenuTitle* fDeskbarMenuItem; TBarMenuTitle* fAppListMenuItem; }; diff --git a/src/apps/deskbar/BarMenuTitle.cpp b/src/apps/deskbar/BarMenuTitle.cpp index 84c2d91d9e..903d81e751 100644 --- a/src/apps/deskbar/BarMenuTitle.cpp +++ b/src/apps/deskbar/BarMenuTitle.cpp @@ -200,8 +200,8 @@ TBarMenuTitle::Invoke(BMessage* message) if (barview) { BLooper* looper = barview->Looper(); if (looper->Lock()) { - // tell barview to add the refs to the be menu - barview->HandleBeMenu(NULL); + // tell barview to add the refs to the deskbar menu + barview->HandleDeskbarMenu(NULL); looper->Unlock(); } } diff --git a/src/apps/deskbar/BarView.cpp b/src/apps/deskbar/BarView.cpp index 6e71956535..0424c44b40 100644 --- a/src/apps/deskbar/BarView.cpp +++ b/src/apps/deskbar/BarView.cpp @@ -53,8 +53,8 @@ All rights reserved. #include "BarApp.h" #include "BarMenuBar.h" #include "BarWindow.h" -#include "BeMenu.h" -#include "DeskBarUtils.h" +#include "DeskbarMenu.h" +#include "DeskbarUtils.h" #include "ExpandoMenuBar.h" #include "FSUtils.h" #include "ResourceSet.h" @@ -157,7 +157,7 @@ TBarView::MessageReceived(BMessage* message) case B_REFS_RECEIVED: // received when an item is selected during DnD // message is targeted here from Be menu - HandleBeMenu(message); + HandleDeskbarMenu(message); break; case B_ARCHIVED_OBJECT: @@ -261,7 +261,7 @@ TBarView::MouseDown(BPoint where) void -TBarView::PlaceBeMenu() +TBarView::PlaceDeskbarMenu() { // top or bottom, full if (!fVertical && fBarMenuBar) { @@ -302,7 +302,7 @@ TBarView::PlaceBeMenu() width = floorf(width) / 2; loc = Bounds().LeftTop(); } else { - // mini mode, BeMenu next to team menu + // mini mode, DeskbarMenu next to team menu fBarMenuBar->AddTeamMenu(); } @@ -525,7 +525,7 @@ TBarView::ChangeState(int32 state, bool vertical, bool left, bool top) BRect screenFrame = (BScreen(Window())).Frame(); - PlaceBeMenu(); + PlaceDeskbarMenu(); PlaceTray(vertSwap, leftSwap, screenFrame); // We need to keep track of what apps are expanded. @@ -773,12 +773,12 @@ TBarView::MenuTrackingHook(BMenu* menu, void* castToThis) // keep tracking endMenu = false; } else { - // see if the mouse is in the team/be menu item + // see if the mouse is in the team/deskbar menu item menu->ConvertToScreen(&location); if (barview->LockLooper()) { TExpandoMenuBar* expando = barview->ExpandoMenuBar(); - TBeMenu* bemenu - = (dynamic_cast(barview->Window()))->BeMenu(); + TDeskbarMenu* bemenu + = (dynamic_cast(barview->Window()))->DeskbarMenu(); if (bemenu && bemenu->LockLooper()) { bemenu->ConvertFromScreen(&location); @@ -939,7 +939,7 @@ TBarView::InvokeItem(const char* signature) void -TBarView::HandleBeMenu(BMessage* messagewithdestination) +TBarView::HandleDeskbarMenu(BMessage* messagewithdestination) { if (!Dragging()) return; @@ -963,13 +963,13 @@ TBarView::HandleBeMenu(BMessage* messagewithdestination) if (entry.IsDirectory()) { // if the ref received (should only be 1) is a directory // then add the drag refs to the directory - AddRefsToBeMenu(DragMessage(), &ref); + AddRefsToDeskbarMenu(DragMessage(), &ref); } else SendDragMessage(NULL, &ref); } } else { - // adds drag refs to top level in be menu - AddRefsToBeMenu(DragMessage(), NULL); + // adds drag refs to top level in deskbar menu + AddRefsToDeskbarMenu(DragMessage(), NULL); } // clean up drag message and types list diff --git a/src/apps/deskbar/BarView.h b/src/apps/deskbar/BarView.h index 9e165cbfe0..470d28e224 100644 --- a/src/apps/deskbar/BarView.h +++ b/src/apps/deskbar/BarView.h @@ -114,7 +114,7 @@ class TBarView : public BView { bool DragOverride(); bool InvokeItem(const char* signature); - void HandleBeMenu(BMessage* targetmessage); + void HandleDeskbarMenu(BMessage* targetmessage); status_t ItemInfo(int32 id, const char** name, DeskbarShelf* shelf); status_t ItemInfo(const char* name, int32* id, DeskbarShelf* shelf); @@ -143,12 +143,12 @@ class TBarView : public BView { TDragRegion* DragRegion() const { return fDragRegion; } private: - friend class TBeMenu; + friend class TDeskbarMenu; friend class PreferencesWindow; status_t SendDragMessage(const char* signature, entry_ref* ref = NULL); - void PlaceBeMenu(); + void PlaceDeskbarMenu(); void PlaceTray(bool vertSwap, bool leftSwap, BRect screenFrame); void PlaceApplicationBar(BRect screenFrame); diff --git a/src/apps/deskbar/BarWindow.cpp b/src/apps/deskbar/BarWindow.cpp index 90c2935a24..1d4ade26f8 100644 --- a/src/apps/deskbar/BarWindow.cpp +++ b/src/apps/deskbar/BarWindow.cpp @@ -52,7 +52,7 @@ All rights reserved. #include "BarApp.h" #include "BarMenuBar.h" #include "BarView.h" -#include "BeMenu.h" +#include "DeskbarMenu.h" #include "PublicCommands.h" #include "StatusView.h" #include "tracker_private.h" @@ -80,7 +80,7 @@ extern "C" void BMenuBar_StartMenuBar_Hack(BMenuBar*, int32, bool, bool, BRect*); -TBeMenu* TBarWindow::sBeMenu = NULL; +TDeskbarMenu* TBarWindow::sDeskbarMenu = NULL; TBarWindow::TBarWindow() @@ -118,18 +118,18 @@ TBarWindow::MenusBeginning() if (entry.InitCheck() == B_OK && entry.IsDirectory()) { // need the entry_ref to the actual item entry.GetRef(&ref); - // set the nav directory to the be folder - sBeMenu->SetNavDir(&ref); + // set the nav directory to the deskbar folder + sDeskbarMenu->SetNavDir(&ref); } else if (!entry.Exists()) { - // the Be folder does not exist + // the deskbar folder does not exist // create one now BDirectory dir; if (entry.GetParent(&dir) == B_OK) { - BDirectory bedir; - dir.CreateDirectory("be", &bedir); - if (bedir.GetEntry(&entry) == B_OK + BDirectory deskbarDir; + dir.CreateDirectory("deskbar", &deskbarDir); + if (deskbarDir.GetEntry(&entry) == B_OK && entry.GetRef(&ref) == B_OK) - sBeMenu->SetNavDir(&ref); + sDeskbarMenu->SetNavDir(&ref); } } else { // this really should never happen @@ -137,8 +137,8 @@ TBarWindow::MenusBeginning() return; } - sBeMenu->NeedsToRebuild(); - sBeMenu->ResetTargets(); + sDeskbarMenu->NeedsToRebuild(); + sDeskbarMenu->ResetTargets(); fBarView->SetEventMask(0); // This works around a BeOS bug - the menu is quit with every @@ -153,10 +153,10 @@ TBarWindow::MenusEnded() { BWindow::MenusEnded(); - if (sBeMenu->LockLooper()) { + if (sDeskbarMenu->LockLooper()) { // TODO: is this ok? - sBeMenu->RemoveItems(0, sBeMenu->CountItems(), true); - sBeMenu->UnlockLooper(); + sDeskbarMenu->RemoveItems(0, sDeskbarMenu->CountItems(), true); + sDeskbarMenu->UnlockLooper(); } fBarView->UpdateEventMask(); @@ -273,21 +273,21 @@ TBarWindow::ScreenChanged(BRect size, color_space depth) void -TBarWindow::SetBeMenu(TBeMenu* menu) +TBarWindow::SetDeskbarMenu(TDeskbarMenu* menu) { - sBeMenu = menu; + sDeskbarMenu = menu; } -TBeMenu* -TBarWindow::BeMenu() +TDeskbarMenu* +TBarWindow::DeskbarMenu() { - return sBeMenu; + return sDeskbarMenu; } void -TBarWindow::ShowBeMenu() +TBarWindow::ShowDeskbarMenu() { BMenuBar* menuBar = fBarView->BarMenuBar(); if (menuBar == NULL) diff --git a/src/apps/deskbar/BarWindow.h b/src/apps/deskbar/BarWindow.h index b8da5ffac5..958bdfa985 100644 --- a/src/apps/deskbar/BarWindow.h +++ b/src/apps/deskbar/BarWindow.h @@ -40,7 +40,7 @@ All rights reserved. #include -class TBeMenu; +class TDeskbarMenu; class TBarView; @@ -59,10 +59,10 @@ public: void SaveSettings(); TBarView* BarView() const { return fBarView; }; - static void SetBeMenu(TBeMenu* menu); - TBeMenu* BeMenu(); + static void SetDeskbarMenu(TDeskbarMenu* menu); + TDeskbarMenu* DeskbarMenu(); - void ShowBeMenu(); + void ShowDeskbarMenu(); void ShowTeamMenu(); void GetLocation(BMessage* message); @@ -88,7 +88,7 @@ private: bool _IsFocusMessage(BMessage* message); private: - static TBeMenu* sBeMenu; + static TDeskbarMenu* sDeskbarMenu; TBarView* fBarView; }; diff --git a/src/apps/deskbar/BeMenu.cpp b/src/apps/deskbar/DeskbarMenu.cpp similarity index 93% rename from src/apps/deskbar/BeMenu.cpp rename to src/apps/deskbar/DeskbarMenu.cpp index 69ab0125a1..a71b6e5653 100644 --- a/src/apps/deskbar/BeMenu.cpp +++ b/src/apps/deskbar/DeskbarMenu.cpp @@ -42,10 +42,14 @@ All rights reserved. #include #include -#include "BeMenu.h" +#include "DeskbarMenu.h" #include "BarApp.h" #include "BarView.h" -#include "DeskBarUtils.h" +#include "DeskbarUtils.h" +#include "IconMenuItem.h" +#include "MountMenu.h" +#include "IconMenuItem.h" +#include "MountMenu.h" #include "IconMenuItem.h" #include "MountMenu.h" #include "PublicCommands.h" @@ -54,7 +58,7 @@ All rights reserved. #include "tracker_private.h" #undef B_TRANSLATE_CONTEXT -#define B_TRANSLATE_CONTEXT "BeMenu" +#define B_TRANSLATE_CONTEXT "DeskbarMenu" #define ROSTER_SIG "application/x-vnd.Be-ROST" @@ -81,8 +85,8 @@ using namespace BPrivate; // #pragma mark - -TBeMenu::TBeMenu(TBarView* barView) - : BNavMenu("BeMenu", B_REFS_RECEIVED, DefaultTarget()), +TDeskbarMenu::TDeskbarMenu(TBarView* barView) + : BNavMenu("DeskbarMenu", B_REFS_RECEIVED, DefaultTarget()), fAddState(kStart), fBarView(barView) { @@ -90,7 +94,7 @@ TBeMenu::TBeMenu(TBarView* barView) void -TBeMenu::AttachedToWindow() +TDeskbarMenu::AttachedToWindow() { if (fBarView && fBarView->LockLooper()) { if (fBarView->Dragging()) { @@ -113,7 +117,7 @@ TBeMenu::AttachedToWindow() void -TBeMenu::DetachedFromWindow() +TDeskbarMenu::DetachedFromWindow() { if (fBarView) { BLooper* looper = fBarView->Looper(); @@ -130,7 +134,7 @@ TBeMenu::DetachedFromWindow() bool -TBeMenu::StartBuildingItemList() +TDeskbarMenu::StartBuildingItemList() { RemoveItems(0, CountItems(), true); fAddState = kStart; @@ -139,11 +143,11 @@ TBeMenu::StartBuildingItemList() void -TBeMenu::DoneBuildingItemList() +TDeskbarMenu::DoneBuildingItemList() { if (fItemList->CountItems() <= 0) { - BMenuItem* item = new BMenuItem(B_TRANSLATE(""), - 0); + BMenuItem* item + = new BMenuItem(B_TRANSLATE(""), 0); item->SetEnabled(false); AddItem(item); } else @@ -152,10 +156,10 @@ TBeMenu::DoneBuildingItemList() bool -TBeMenu::AddNextItem() +TDeskbarMenu::AddNextItem() { if (fAddState == kStart) - return AddStandardBeMenuItems(); + return AddStandardDeskbarMenuItems(); TrackingHookData* data = fBarView->GetTrackingHookData(); if (fAddState == kAddingRecents) { @@ -199,11 +203,11 @@ TBeMenu::AddNextItem() } AddSeparatorItem(); - fAddState = kAddingBeMenu; + fAddState = kAddingDeskbarMenu; return true; } - if (fAddState == kAddingBeMenu) { + if (fAddState == kAddingDeskbarMenu) { // keep reentering and adding items // until this returns false bool done = BNavMenu::AddNextItem(); @@ -229,7 +233,7 @@ TBeMenu::AddNextItem() bool -TBeMenu::AddStandardBeMenuItems() +TDeskbarMenu::AddStandardDeskbarMenuItems() { bool dragging = false; if (fBarView) @@ -245,8 +249,7 @@ TBeMenu::AddStandardBeMenuItems() } #ifdef HAIKU_DISTRO_COMPATIBILITY_OFFICIAL - static const char* kAboutHaikuMenuItemStr = B_TRANSLATE_MARK( - "About Haiku"); + static const char* kAboutHaikuMenuItemStr = B_TRANSLATE_MARK("About Haiku"); #else static const char* kAboutThisSystemMenuItemStr = B_TRANSLATE_MARK( "About this system"); @@ -334,7 +337,7 @@ TBeMenu::AddStandardBeMenuItems() void -TBeMenu::ClearMenuBuildingState() +TDeskbarMenu::ClearMenuBuildingState() { fAddState = kDone; fMenuBuilt = false; @@ -344,7 +347,7 @@ TBeMenu::ClearMenuBuildingState() void -TBeMenu::ResetTargets() +TDeskbarMenu::ResetTargets() { // This method does not recurse into submenus // and does not affect menu items in submenus. @@ -389,7 +392,7 @@ TBeMenu::ResetTargets() BPoint -TBeMenu::ScreenLocation() +TDeskbarMenu::ScreenLocation() { bool vertical = fBarView->Vertical(); int32 expando = (fBarView->State() == kExpandoState); @@ -413,7 +416,7 @@ TBeMenu::ScreenLocation() /*static*/ BMessenger -TBeMenu::DefaultTarget() +TDeskbarMenu::DefaultTarget() { // if Tracker is not available we target the BarApp BMessenger target(kTrackerSignature); @@ -429,7 +432,7 @@ TBeMenu::DefaultTarget() TRecentsMenu::TRecentsMenu(const char* name, TBarView* bar, int32 which, const char* signature, entry_ref* appRef) - : BNavMenu(name, B_REFS_RECEIVED, TBeMenu::DefaultTarget()), + : BNavMenu(name, B_REFS_RECEIVED, TDeskbarMenu::DefaultTarget()), fWhich(which), fAppRef(NULL), fSignature(NULL), @@ -633,7 +636,7 @@ TRecentsMenu::ResetTargets() // if we are dragging, set the target to whatever was set // else set it to the default (Tracker) if (!fBarView->Dragging()) - SetTarget(TBeMenu::DefaultTarget()); + SetTarget(TDeskbarMenu::DefaultTarget()); // now set the target for the menuitems to the currently // set target, which may or may not be tracker diff --git a/src/apps/deskbar/BeMenu.h b/src/apps/deskbar/DeskbarMenu.h similarity index 93% rename from src/apps/deskbar/BeMenu.h rename to src/apps/deskbar/DeskbarMenu.h index 70abe610b3..c845402290 100644 --- a/src/apps/deskbar/BeMenu.h +++ b/src/apps/deskbar/DeskbarMenu.h @@ -33,8 +33,8 @@ holders. All rights reserved. */ -#ifndef _BE_MENU_H_ -#define _BE_MENU_H_ +#ifndef _DESKBAR_MENU_H_ +#define _DESKBAR_MENU_H_ #include "NavMenu.h" @@ -96,9 +96,9 @@ TRecentsMenu::RecentsEnabled() } -class TBeMenu : public BNavMenu { +class TDeskbarMenu : public BNavMenu { public: - TBeMenu(TBarView* bar); + TDeskbarMenu(TBarView* bar); void AttachedToWindow(); void DetachedFromWindow(); @@ -111,13 +111,13 @@ class TBeMenu : public BNavMenu { enum State { kStart, kAddingRecents, - kAddingBeMenu, + kAddingDeskbarMenu, kDone }; protected: BPoint ScreenLocation(); - bool AddStandardBeMenuItems(); + bool AddStandardDeskbarMenuItems(); private: virtual bool StartBuildingItemList(); @@ -130,5 +130,5 @@ class TBeMenu : public BNavMenu { TBarView* fBarView; }; -#endif /* _BE_MENU_H_ */ +#endif /* _DESKBAR_MENU_H_ */ diff --git a/src/apps/deskbar/DeskBarUtils.cpp b/src/apps/deskbar/DeskbarUtils.cpp similarity index 96% rename from src/apps/deskbar/DeskBarUtils.cpp rename to src/apps/deskbar/DeskbarUtils.cpp index 791a809842..c0c0e59917 100644 --- a/src/apps/deskbar/DeskBarUtils.cpp +++ b/src/apps/deskbar/DeskbarUtils.cpp @@ -51,11 +51,11 @@ All rights reserved. #include #include "BarMenuBar.h" -#include "DeskBarUtils.h" +#include "DeskbarUtils.h" #include "ExpandoMenuBar.h" void -AddRefsToBeMenu(const BMessage* m, entry_ref* subdirectory) +AddRefsToDeskbarMenu(const BMessage* m, entry_ref* subdirectory) { if (m) { int32 count = 0; diff --git a/src/apps/deskbar/DeskBarUtils.h b/src/apps/deskbar/DeskbarUtils.h similarity index 96% rename from src/apps/deskbar/DeskBarUtils.h rename to src/apps/deskbar/DeskbarUtils.h index b35ad567a6..33d9908b3a 100644 --- a/src/apps/deskbar/DeskBarUtils.h +++ b/src/apps/deskbar/DeskbarUtils.h @@ -39,7 +39,7 @@ All rights reserved. #include "tracker_private.h" -void AddRefsToBeMenu(const BMessage* m, entry_ref* subdirectory); +void AddRefsToDeskbarMenu(const BMessage* m, entry_ref* subdirectory); #endif /* DB_UTILS_H */ diff --git a/src/apps/deskbar/ExpandoMenuBar.cpp b/src/apps/deskbar/ExpandoMenuBar.cpp index 739f0761bd..d10600749b 100644 --- a/src/apps/deskbar/ExpandoMenuBar.cpp +++ b/src/apps/deskbar/ExpandoMenuBar.cpp @@ -49,8 +49,8 @@ All rights reserved. #include "BarApp.h" #include "BarMenuTitle.h" #include "BarView.h" -#include "BeMenu.h" -#include "DeskBarUtils.h" +#include "DeskbarMenu.h" +#include "DeskbarUtils.h" #include "ExpandoMenuBar.h" #include "ResourceSet.h" #include "ShowHideMenuItem.h" @@ -59,7 +59,7 @@ All rights reserved. #include "WindowMenu.h" #include "WindowMenuItem.h" -const float kDefaultBeMenuWidth = 50.0f; +const float kDefaultDeskbarMenuWidth = 50.0f; const float kSepItemWidth = 5.0f; const uint32 kMinimizeTeam = 'mntm'; @@ -82,7 +82,7 @@ TExpandoMenuBar::TExpandoMenuBar(TBarView* bar, BRect frame, const char* name, fIsScrolling(false), fShowTeamExpander(static_cast(be_app)->Settings()->superExpando), fExpandNewTeams(static_cast(be_app)->Settings()->expandNewTeams), - fBeMenuWidth(kDefaultBeMenuWidth), + fDeskbarMenuWidth(kDefaultDeskbarMenuWidth), fBarView(bar), fFirstApp(0), fPreviousDragTargetItem(NULL), @@ -111,24 +111,25 @@ TExpandoMenuBar::AttachedToWindow() float width = fVertical ? Frame().Width() : sMinimumWindowWidth; float height = -1.0f; - // top or bottom mode, add be menu and sep for menubar tracking consistency + // top or bottom mode, add deskbar menu and sep for menubar tracking + // consistency if (!fVertical) { - TBeMenu* beMenu = new TBeMenu(fBarView); - TBarWindow::SetBeMenu(beMenu); + TDeskbarMenu* beMenu = new TDeskbarMenu(fBarView); + TBarWindow::SetDeskbarMenu(beMenu); const BBitmap* logoBitmap = AppResSet()->FindBitmap(B_MESSAGE_TYPE, R_LeafLogoBitmap); if (logoBitmap != NULL) - fBeMenuWidth = logoBitmap->Bounds().Width() + 16; - fBeMenuItem = new TBarMenuTitle(fBeMenuWidth, Frame().Height(), + fDeskbarMenuWidth = logoBitmap->Bounds().Width() + 16; + fDeskbarMenuItem = new TBarMenuTitle(fDeskbarMenuWidth, Frame().Height(), logoBitmap, beMenu, true); - AddItem(fBeMenuItem); + AddItem(fDeskbarMenuItem); fSeparatorItem = new TTeamMenuItem(kSepItemWidth, height, fVertical); AddItem(fSeparatorItem); fSeparatorItem->SetEnabled(false); fFirstApp = 2; } else { - fBeMenuItem = NULL; + fDeskbarMenuItem = NULL; fSeparatorItem = NULL; } @@ -438,21 +439,21 @@ TExpandoMenuBar::MouseUp(BPoint where) bool -TExpandoMenuBar::InBeMenu(BPoint loc) const +TExpandoMenuBar::InDeskbarMenu(BPoint loc) const { if (!fVertical) { - if (fBeMenuItem && fBeMenuItem->Frame().Contains(loc)) + if (fDeskbarMenuItem && fDeskbarMenuItem->Frame().Contains(loc)) return true; } else { TBarWindow* window = dynamic_cast(Window()); if (window) { - if (TBeMenu* bemenu = window->BeMenu()) { - bool inBeMenu = false; + if (TDeskbarMenu* bemenu = window->DeskbarMenu()) { + bool inDeskbarMenu = false; if (bemenu->LockLooper()) { - inBeMenu = bemenu->Frame().Contains(loc); + inDeskbarMenu = bemenu->Frame().Contains(loc); bemenu->UnlockLooper(); } - return inBeMenu; + return inDeskbarMenu; } } } @@ -617,8 +618,8 @@ TExpandoMenuBar::CheckItemSizes(int32 delta) // - The Be Menu // - The little separator item fullWidth = fullWidth - (sMinimumWindowWidth * 2) - + (fBeMenuWidth + kSepItemWidth); - width -= (fBeMenuWidth + kSepItemWidth); + + (fDeskbarMenuWidth + kSepItemWidth); + width -= (fDeskbarMenuWidth + kSepItemWidth); count -= 2; } diff --git a/src/apps/deskbar/ExpandoMenuBar.h b/src/apps/deskbar/ExpandoMenuBar.h index 6a96559e02..107ff9670f 100644 --- a/src/apps/deskbar/ExpandoMenuBar.h +++ b/src/apps/deskbar/ExpandoMenuBar.h @@ -52,7 +52,7 @@ class TTeamMenuItem; enum drag_and_drop_selection { kNoSelection, - kBeMenuSelection, + kDeskbarMenuSelection, kAppMenuSelection, kAnyMenuSelection }; @@ -74,7 +74,7 @@ class TExpandoMenuBar : public BMenuBar { TTeamMenuItem* TeamItemAtPoint(BPoint location, BMenuItem** _item = NULL); - bool InBeMenu(BPoint) const; + bool InDeskbarMenu(BPoint) const; void CheckItemSizes(int32 delta); @@ -100,12 +100,12 @@ class TExpandoMenuBar : public BMenuBar { bool fShowTeamExpander : 1; bool fExpandNewTeams : 1; - float fBeMenuWidth; + float fDeskbarMenuWidth; TBarView* fBarView; int32 fFirstApp; - TBarMenuTitle* fBeMenuItem; + TBarMenuTitle* fDeskbarMenuItem; TTeamMenuItem* fSeparatorItem; TTeamMenuItem* fPreviousDragTargetItem; diff --git a/src/apps/deskbar/Jamfile b/src/apps/deskbar/Jamfile index 7788b40026..91523b8823 100644 --- a/src/apps/deskbar/Jamfile +++ b/src/apps/deskbar/Jamfile @@ -24,8 +24,8 @@ Application Deskbar : BarMenuTitle.cpp BarView.cpp BarWindow.cpp - BeMenu.cpp - DeskBarUtils.cpp + DeskbarMenu.cpp + DeskbarUtils.cpp ExpandoMenuBar.cpp PreferencesWindow.cpp ShowHideMenuItem.cpp @@ -46,7 +46,7 @@ DoCatalogs Deskbar : x-vnd.Be-TSKB : BarWindow.cpp - BeMenu.cpp + DeskbarMenu.cpp LocalizedFolders.h PreferencesWindow.cpp StatusView.cpp diff --git a/src/apps/deskbar/StatusView.cpp b/src/apps/deskbar/StatusView.cpp index 620e84aeac..7c997450ac 100644 --- a/src/apps/deskbar/StatusView.cpp +++ b/src/apps/deskbar/StatusView.cpp @@ -66,7 +66,7 @@ All rights reserved. #include "icons_logo.h" #include "BarApp.h" -#include "DeskBarUtils.h" +#include "DeskbarUtils.h" #include "ResourceSet.h" #include "StatusView.h" #include "StatusViewShelf.h" diff --git a/src/apps/deskbar/TeamMenu.cpp b/src/apps/deskbar/TeamMenu.cpp index 3053969821..6fdfa20ddf 100644 --- a/src/apps/deskbar/TeamMenu.cpp +++ b/src/apps/deskbar/TeamMenu.cpp @@ -40,7 +40,7 @@ All rights reserved. #include "BarApp.h" #include "BarMenuBar.h" -#include "DeskBarUtils.h" +#include "DeskbarUtils.h" #include "TeamMenuItem.h" #include "TeamMenu.h" diff --git a/src/apps/processcontroller/PCWorld.cpp b/src/apps/processcontroller/PCWorld.cpp index 71ecee1874..836867f47b 100644 --- a/src/apps/processcontroller/PCWorld.cpp +++ b/src/apps/processcontroller/PCWorld.cpp @@ -30,6 +30,8 @@ #include #include #include +#include +#include #include #include @@ -139,8 +141,16 @@ PCApplication::ArgvReceived(int32 argc, char **argv) snooze(10000); } while (be_roster->IsRunning(kTrackerSig) && k-- > 0); } - remove("/boot/home/config/settings/Tracker/tracker_shelf"); - launch(kTrackerSig, "/boot/system/Tracker"); + BPath shelfPath; + if (find_directory(B_USER_SETTINGS_DIRECTORY, &shelfPath) == B_OK + && shelfPath.Append("Tracker/tracker_shelf") == B_OK) { + remove(shelfPath.Path()); + } + BPath trackerPath; + if (find_directory(B_SYSTEM_DIRECTORY, &trackerPath) == B_OK + && trackerPath.Append("Tracker") == B_OK) { + launch(kTrackerSig, trackerPath.Path()); + } } else if (argc == 2 && strcmp(argv[1], "-deskbar") == 0) { BDeskbar deskbar; if (!gInDeskbar && !deskbar.HasItem(kDeskbarItemName)) diff --git a/src/apps/processcontroller/ProcessController.cpp b/src/apps/processcontroller/ProcessController.cpp index 552b618ea9..3d1c225b53 100644 --- a/src/apps/processcontroller/ProcessController.cpp +++ b/src/apps/processcontroller/ProcessController.cpp @@ -345,21 +345,45 @@ ProcessController::MessageReceived(BMessage *message) break; case 'Trac': - launch(kTrackerSig, "/boot/system/Tracker"); + { + BPath trackerPath; + if (find_directory(B_SYSTEM_DIRECTORY, &trackerPath) == B_OK + && trackerPath.Append("Tracker") == B_OK) { + launch(kTrackerSig, trackerPath.Path()); + } break; + } case 'Dbar': - launch(kDeskbarSig, "/boot/system/Deskbar"); + { + BPath deskbarPath; + if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK + && deskbarPath.Append("Deskbar") == B_OK) { + launch(kDeskbarSig, deskbarPath.Path()); + } break; + } case 'Term': - launch(kTerminalSig, "/boot/system/apps/Terminal"); + { + BPath terminalPath; + if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath) == B_OK + && terminalPath.Append("Deskbar") == B_OK) { + launch(kTerminalSig, terminalPath.Path()); + } + launch(kTerminalSig, terminalPath.Path()); break; + } case 'AlDb': { - if (!be_roster->IsRunning(kDeskbarSig)) - launch(kDeskbarSig, "/boot/system/Deskbar"); + if (!be_roster->IsRunning(kDeskbarSig)) { + BPath deskbarPath; + if (find_directory(B_SYSTEM_DIRECTORY, &deskbarPath) == B_OK + && deskbarPath.Append("Deskbar") == B_OK) { + launch(kDeskbarSig, deskbarPath.Path()); + } + } BDeskbar deskbar; if (gInDeskbar || deskbar.HasItem (kDeskbarItemName)) deskbar.RemoveItem (kDeskbarItemName); diff --git a/src/apps/remotedesktop/RemoteDesktop.cpp b/src/apps/remotedesktop/RemoteDesktop.cpp index c30612d0c6..75a92e91da 100644 --- a/src/apps/remotedesktop/RemoteDesktop.cpp +++ b/src/apps/remotedesktop/RemoteDesktop.cpp @@ -7,6 +7,8 @@ */ #include +#include +#include #include #include @@ -40,7 +42,6 @@ main(int argc, char *argv[]) bool listenOnly = false; uint32 listenPort = 10900; uint32 sshPort = 22; - const char *command = "/system/apps/Terminal"; for (int32 i = 2; i < argc; i++) { if (strcmp(argv[i], "-p") == 0) { @@ -85,10 +86,21 @@ main(int argc, char *argv[]) pid_t sshPID = -1; if (!listenOnly) { + + BPath terminalPath; + if (find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath) != B_OK) { + printf("failed to determine system-apps directory\n"); + return 3; + } + if (terminalPath.Append("Terminal") != B_OK) { + printf("failed to append to system-apps path\n"); + return 3; + } + char shellCommand[4096]; snprintf(shellCommand, sizeof(shellCommand), "echo connected; export TARGET_SCREEN=localhost:%lu; %s\n", - listenPort, command); + listenPort, terminalPath.Path()); int pipes[4]; if (pipe(&pipes[0]) != 0 || pipe(&pipes[2]) != 0) { diff --git a/src/bin/bash/config-top.h b/src/bin/bash/config-top.h index 906128e91b..9b7d17e905 100644 --- a/src/bin/bash/config-top.h +++ b/src/bin/bash/config-top.h @@ -54,7 +54,10 @@ /* The default value of the PATH variable. */ #ifndef DEFAULT_PATH_VALUE #define DEFAULT_PATH_VALUE \ - ".:/boot/home/config/bin:/bin:/boot/apps:/boot/preferences:/boot/system/apps:/boot/system/preferences:/boot/develop/bin" + ".:/boot/home/config/bin:/bin:/boot/apps:/boot/preferences" \ + ":/boot/system/apps" \ + ":/boot/system/preferences" \ + ":/boot/common/settings/develop/tools/current/bin" #endif /* The value for PATH when invoking `command -p'. This is only used when diff --git a/src/bin/bash/pathnames.h b/src/bin/bash/pathnames.h index 4df7c143e5..42288f5c18 100644 --- a/src/bin/bash/pathnames.h +++ b/src/bin/bash/pathnames.h @@ -28,6 +28,7 @@ #define SYS_PROFILE "/etc/profile" /* The default location of the bash debugger initialization/startup file. */ -#define DEBUGGER_START_FILE "/boot/common/share/bashdb/bashdb-main.inc" +#define DEBUGGER_START_FILE \ + "/boot/common/share/bashdb/bashdb-main.inc" #endif /* _PATHNAMES_H */ diff --git a/src/bin/debug/profile/profile.cpp b/src/bin/debug/profile/profile.cpp index 1d2ddfcca9..dbe0d8f20a 100644 --- a/src/bin/debug/profile/profile.cpp +++ b/src/bin/debug/profile/profile.cpp @@ -17,7 +17,9 @@ #include #include +#include #include +#include #include #include @@ -454,7 +456,13 @@ private: BString name = imageInfo.name; if (name.FindFirst('/') == -1) { // modules without a path are likely to be boot modules - name.Prepend("/system/add-ons/kernel/boot/"); + BPath bootAddonPath; + if (find_directory(B_SYSTEM_ADDONS_DIRECTORY, + &bootAddonPath) == B_OK + && bootAddonPath.Append("kernel") == B_OK + && bootAddonPath.Append("boot") == B_OK) { + name = BString(bootAddonPath.Path()) << "/" << name; + } } error = sharedImage->Init(name.String()); diff --git a/src/bin/finddir.c b/src/bin/finddir.c index 33ab4084fa..1f659d7d84 100644 --- a/src/bin/finddir.c +++ b/src/bin/finddir.c @@ -28,6 +28,7 @@ directoryType directoryTypes[] = { KEYVALUE_PAIR(B_DESKTOP_DIRECTORY), KEYVALUE_PAIR(B_TRASH_DIRECTORY), KEYVALUE_PAIR(B_APPS_DIRECTORY), + KEYVALUE_PAIR(B_PACKAGE_LINKS_DIRECTORY), KEYVALUE_PAIR(B_PREFERENCES_DIRECTORY), KEYVALUE_PAIR(B_UTILITIES_DIRECTORY), @@ -46,6 +47,9 @@ directoryType directoryTypes[] = { KEYVALUE_PAIR(B_SYSTEM_MEDIA_NODES_DIRECTORY), KEYVALUE_PAIR(B_SYSTEM_SOUNDS_DIRECTORY), KEYVALUE_PAIR(B_SYSTEM_DATA_DIRECTORY), + KEYVALUE_PAIR(B_SYSTEM_DEVELOP_DIRECTORY), + KEYVALUE_PAIR(B_SYSTEM_PACKAGES_DIRECTORY), + KEYVALUE_PAIR(B_SYSTEM_HEADERS_DIRECTORY), // Common directories KEYVALUE_PAIR(B_COMMON_DIRECTORY), @@ -69,6 +73,19 @@ directoryType directoryTypes[] = { KEYVALUE_PAIR(B_COMMON_SOUNDS_DIRECTORY), KEYVALUE_PAIR(B_COMMON_DATA_DIRECTORY), KEYVALUE_PAIR(B_COMMON_CACHE_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_PACKAGES_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_HEADERS_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_NONPACKAGED_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_NONPACKAGED_ADDONS_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_NONPACKAGED_TRANSLATORS_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_NONPACKAGED_MEDIA_NODES_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_NONPACKAGED_BIN_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_NONPACKAGED_DATA_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_NONPACKAGED_FONTS_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_NONPACKAGED_SOUNDS_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_NONPACKAGED_DOCUMENTATION_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_NONPACKAGED_LIB_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_NONPACKAGED_HEADERS_DIRECTORY), // User directories KEYVALUE_PAIR(B_USER_DIRECTORY), @@ -85,6 +102,19 @@ directoryType directoryTypes[] = { KEYVALUE_PAIR(B_USER_SOUNDS_DIRECTORY), KEYVALUE_PAIR(B_USER_DATA_DIRECTORY), KEYVALUE_PAIR(B_USER_CACHE_DIRECTORY), + KEYVALUE_PAIR(B_USER_PACKAGES_DIRECTORY), + KEYVALUE_PAIR(B_USER_HEADERS_DIRECTORY), + KEYVALUE_PAIR(B_USER_NONPACKAGED_DIRECTORY), + KEYVALUE_PAIR(B_USER_NONPACKAGED_ADDONS_DIRECTORY), + KEYVALUE_PAIR(B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY), + KEYVALUE_PAIR(B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY), + KEYVALUE_PAIR(B_USER_NONPACKAGED_BIN_DIRECTORY), + KEYVALUE_PAIR(B_USER_NONPACKAGED_DATA_DIRECTORY), + KEYVALUE_PAIR(B_USER_NONPACKAGED_FONTS_DIRECTORY), + KEYVALUE_PAIR(B_USER_NONPACKAGED_SOUNDS_DIRECTORY), + KEYVALUE_PAIR(B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY), + KEYVALUE_PAIR(B_USER_NONPACKAGED_LIB_DIRECTORY), + KEYVALUE_PAIR(B_USER_NONPACKAGED_HEADERS_DIRECTORY), // Legacy system directories KEYVALUE_PAIR(B_BEOS_DIRECTORY), diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp index ba84332c08..0c2671d43a 100644 --- a/src/bin/package/command_list.cpp +++ b/src/bin/package/command_list.cpp @@ -149,9 +149,7 @@ struct PackageContentListHandler : BPackageContentHandler { break; case B_PACKAGE_INFO_VERSION: - printf("\tversion: %s.%s.%s-%d\n", value.version.major, - value.version.minor, value.version.micro, - value.version.release); + _PrintPackageVersion(value.version); break; case B_PACKAGE_INFO_COPYRIGHTS: diff --git a/src/kits/app/Roster.cpp b/src/kits/app/Roster.cpp index c807b7fa32..953f700e05 100644 --- a/src/kits/app/Roster.cpp +++ b/src/kits/app/Roster.cpp @@ -244,13 +244,15 @@ compare_queried_apps(const entry_ref* app1, const entry_ref* app2) } } - // Check system folder + // Check system servers folder + BPath path; + find_directory(B_SYSTEM_SERVERS_DIRECTORY, &path); + BString serverPath(path.Path()); + serverPath << '/'; + size_t length = serverPath.Length(); - static const char* kSystemPath = "/boot/system/servers/"; - size_t length = strlen(kSystemPath); - - bool inSystem1 = !strncmp(kSystemPath, path1.Path(), length); - bool inSystem2 = !strncmp(kSystemPath, path2.Path(), length); + bool inSystem1 = !strncmp(serverPath.String(), path1.Path(), length); + bool inSystem2 = !strncmp(serverPath.String(), path2.Path(), length); if (inSystem1 != inSystem2) return inSystem1 ? 1 : -1; diff --git a/src/kits/locale/MutableLocaleRoster.cpp b/src/kits/locale/MutableLocaleRoster.cpp index 0ea31b1a2a..e5893d99f0 100644 --- a/src/kits/locale/MutableLocaleRoster.cpp +++ b/src/kits/locale/MutableLocaleRoster.cpp @@ -366,15 +366,17 @@ RosterData::_InitializeCatalogAddOns() fCatalogAddOnInfos.AddItem((void*)defaultCatalogAddOnInfo); directory_which folders[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, + B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, B_SYSTEM_ADDONS_DIRECTORY, - static_cast(-1) }; BPath addOnPath; BDirectory addOnFolder; char buf[4096]; status_t err; - for (int f = 0; folders[f]>=0; ++f) { + for (uint32 f = 0; f < sizeof(folders) / sizeof(directory_which); ++f) { find_directory(folders[f], &addOnPath); BString addOnFolderName(addOnPath.Path()); addOnFolderName << "/locale/catalogs"; diff --git a/src/kits/opengl/GLRendererRoster.cpp b/src/kits/opengl/GLRendererRoster.cpp index d4778c71aa..971272297a 100644 --- a/src/kits/opengl/GLRendererRoster.cpp +++ b/src/kits/opengl/GLRendererRoster.cpp @@ -107,12 +107,14 @@ GLRendererRoster::AddDefaultPaths() { // add user directories first, so that they can override system renderers const directory_which paths[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, - B_BEOS_ADDONS_DIRECTORY, + B_SYSTEM_ADDONS_DIRECTORY, }; - for (uint32 i = fSafeMode ? 2 : 0; i < sizeof(paths) / sizeof(paths[0]); i++) { + for (uint32 i = fSafeMode ? 4 : 0; i < sizeof(paths) / sizeof(paths[0]); i++) { BPath path; status_t status = find_directory(paths[i], &path, true); if (status == B_OK && path.Append("opengl") == B_OK) diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp index 117ada8066..4c42ad6f8c 100644 --- a/src/kits/package/PackageInfo.cpp +++ b/src/kits/package/PackageInfo.cpp @@ -67,6 +67,8 @@ public: private: struct Token; + struct ListElementParser; + friend struct ListElementParser; Token _NextToken(); void _RewindTo(const Token& token); @@ -77,6 +79,7 @@ private: BPackageArchitecture* value); void _ParseVersionValue(BPackageVersion* value, bool releaseIsOptional); + void _ParseList(ListElementParser& elementParser); void _ParseStringList(BObjectList* value, bool allowQuotedStrings = true); void _ParseResolvableList( @@ -139,6 +142,11 @@ struct BPackageInfo::Parser::Token { }; +struct BPackageInfo::Parser::ListElementParser { + virtual void operator()(const Token& token) = 0; +}; + + BPackageInfo::ParseErrorListener::~ParseErrorListener() { } @@ -277,7 +285,7 @@ BPackageInfo::Parser::_NextToken() { const char* start = fPos; while (isalnum(*fPos) || *fPos == '.' || *fPos == '-' - || *fPos == '_' || *fPos == ':') { + || *fPos == '_' || *fPos == ':' || *fPos == '+') { fPos++; } if (fPos == start) @@ -384,8 +392,7 @@ BPackageInfo::Parser::_ParseVersionValue(BPackageVersion* value, void -BPackageInfo::Parser::_ParseStringList(BObjectList* value, bool - allowQuotedStrings) +BPackageInfo::Parser::_ParseList(ListElementParser& elementParser) { Token openBracket = _NextToken(); if (openBracket.type != TOKEN_OPEN_BRACKET) @@ -401,12 +408,41 @@ BPackageInfo::Parser::_ParseStringList(BObjectList* value, bool if (token.type != TOKEN_COMMA) throw ParseError("expected comma", token.pos); token = _NextToken(); + if (token.type == TOKEN_CLOSE_BRACKET) { + // silently skip trailing comma at end of list + return; + } } else needComma = true; + elementParser(token); + } +} + + +void +BPackageInfo::Parser::_ParseStringList(BObjectList* value, + bool allowQuotedStrings) +{ + struct StringParser : public ListElementParser { + BObjectList* value; + bool allowQuotedStrings; + + StringParser(BObjectList* value_, bool allowQuotedStrings_) + : + value(value_), + allowQuotedStrings(allowQuotedStrings_) + { + } + + virtual void operator()(const Token& token) + { if (allowQuotedStrings) { - if (token.type != TOKEN_QUOTED_STRING && token.type != TOKEN_WORD) - throw ParseError("expected quoted-string or word", token.pos); + if (token.type != TOKEN_QUOTED_STRING + && token.type != TOKEN_WORD) { + throw ParseError("expected quoted-string or word", + token.pos); + } } else { if (token.type != TOKEN_WORD) throw ParseError("expected word", token.pos); @@ -414,31 +450,26 @@ BPackageInfo::Parser::_ParseStringList(BObjectList* value, bool value->AddItem(new BString(token.text)); } + } stringParser(value, allowQuotedStrings); + + _ParseList(stringParser); } uint32 BPackageInfo::Parser::_ParseFlags() { - uint32 flags = 0; + struct FlagParser : public ListElementParser { + uint32 flags; - Token openBracket = _NextToken(); - if (openBracket.type != TOKEN_OPEN_BRACKET) - throw ParseError("expected start of list ('[')", openBracket.pos); - - bool needComma = false; - while (true) { - Token token = _NextToken(); - if (token.type == TOKEN_CLOSE_BRACKET) - break; - - if (needComma) { - if (token.type != TOKEN_COMMA) - throw ParseError("expected comma", token.pos); - token = _NextToken(); - } else - needComma = true; + FlagParser() + : + flags(0) + { + } + virtual void operator()(const Token& token) + { if (token.type != TOKEN_WORD) throw ParseError("expected word (a flag)", token.pos); @@ -447,12 +478,16 @@ BPackageInfo::Parser::_ParseFlags() else if (token.text.ICompare("system_package") == 0) flags |= B_PACKAGE_FLAG_SYSTEM_PACKAGE; else { - throw ParseError("expected 'approve_license' or 'system_package'", + throw ParseError( + "expected 'approve_license' or 'system_package'", token.pos); } } + } flagParser; - return flags; + _ParseList(flagParser); + + return flagParser.flags; } @@ -460,60 +495,63 @@ void BPackageInfo::Parser::_ParseResolvableList( BObjectList* value) { - Token openBracket = _NextToken(); - if (openBracket.type != TOKEN_OPEN_BRACKET) - throw ParseError("expected start of list ('[')", openBracket.pos); + struct ResolvableParser : public ListElementParser { + Parser& parser; + BObjectList* value; - bool needComma = false; - while (true) { - BPackageResolvableType type = B_PACKAGE_RESOLVABLE_TYPE_DEFAULT; + ResolvableParser(Parser& parser_, + BObjectList* value_) + : + parser(parser_), + value(value_) + { + } - Token word = _NextToken(); - if (word.type == TOKEN_CLOSE_BRACKET) - return; + virtual void operator()(const Token& token) + { + if (token.type != TOKEN_WORD) { + throw ParseError("expected word (a resolvable name)", + token.pos); + } - if (needComma) { - if (word.type != TOKEN_COMMA) - throw ParseError("expected comma", word.pos); - word = _NextToken(); - } else - needComma = true; - - if (word.type != TOKEN_WORD) - throw ParseError("expected word (a resolvable name)", word.pos); - - int32 colonPos = word.text.FindFirst(':'); + BPackageResolvableType type = B_PACKAGE_RESOLVABLE_TYPE_DEFAULT; + int32 colonPos = token.text.FindFirst(':'); if (colonPos >= 0) { - BString typeName(word.text, colonPos); + BString typeName(token.text, colonPos); for (int i = 0; i < B_PACKAGE_RESOLVABLE_TYPE_ENUM_COUNT; ++i) { - if (typeName.ICompare(BPackageResolvable::kTypeNames[i]) == 0) { + if (typeName.ICompare(BPackageResolvable::kTypeNames[i]) + == 0) { type = (BPackageResolvableType)i; break; } } if (type == B_PACKAGE_RESOLVABLE_TYPE_DEFAULT) { BString error("resolvable type (:) must be one of ["); - for (int i = 1; i < B_PACKAGE_RESOLVABLE_TYPE_ENUM_COUNT; ++i) { + for (int i = 1; i < B_PACKAGE_RESOLVABLE_TYPE_ENUM_COUNT; + ++i) { if (i > 1) error << ","; error << BPackageResolvable::kTypeNames[i]; } error << "]"; - throw ParseError(error, word.pos); + throw ParseError(error, token.pos); } } BPackageVersion version; - Token op = _NextToken(); + Token op = parser._NextToken(); if (op.type == TOKEN_OPERATOR_ASSIGN) - _ParseVersionValue(&version, true); + parser._ParseVersionValue(&version, true); else if (op.type == TOKEN_COMMA || op.type == TOKEN_CLOSE_BRACKET) - _RewindTo(op); + parser._RewindTo(op); else throw ParseError("expected '=', comma or ']'", op.pos); - value->AddItem(new BPackageResolvable(word.text, type, version)); + value->AddItem(new BPackageResolvable(token.text, type, version)); } + } resolvableParser(*this, value); + + _ParseList(resolvableParser); } @@ -521,37 +559,36 @@ void BPackageInfo::Parser::_ParseResolvableExprList( BObjectList* value) { - Token openBracket = _NextToken(); - if (openBracket.type != TOKEN_OPEN_BRACKET) - throw ParseError("expected start of list ('[')", openBracket.pos); + struct ResolvableExpressionParser : public ListElementParser { + Parser& parser; + BObjectList* value; - bool needComma = false; - while (true) { - Token name = _NextToken(); - if (name.type == TOKEN_CLOSE_BRACKET) - return; + ResolvableExpressionParser(Parser& parser_, + BObjectList* value_) + : + parser(parser_), + value(value_) + { + } - if (needComma) { - if (name.type != TOKEN_COMMA) - throw ParseError("expected comma", name.pos); - name = _NextToken(); - } else - needComma = true; - - if (name.type != TOKEN_WORD) - throw ParseError("expected word (a resolvable name)", name.pos); + virtual void operator()(const Token& token) + { + if (token.type != TOKEN_WORD) { + throw ParseError("expected word (a resolvable name)", + token.pos); + } BPackageVersion version; - Token op = _NextToken(); + Token op = parser._NextToken(); if (op.type == TOKEN_OPERATOR_LESS || op.type == TOKEN_OPERATOR_LESS_EQUAL || op.type == TOKEN_OPERATOR_EQUAL || op.type == TOKEN_OPERATOR_NOT_EQUAL || op.type == TOKEN_OPERATOR_GREATER_EQUAL || op.type == TOKEN_OPERATOR_GREATER) - _ParseVersionValue(&version, true); + parser._ParseVersionValue(&version, true); else if (op.type == TOKEN_COMMA || op.type == TOKEN_CLOSE_BRACKET) - _RewindTo(op); + parser._RewindTo(op); else { throw ParseError( "expected '<', '<=', '==', '!=', '>=', '>', comma or ']'", @@ -561,9 +598,12 @@ BPackageInfo::Parser::_ParseResolvableExprList( BPackageResolvableOperator resolvableOperator = (BPackageResolvableOperator)(op.type - TOKEN_OPERATOR_LESS); - value->AddItem(new BPackageResolvableExpression(name.text, + value->AddItem(new BPackageResolvableExpression(token.text, resolvableOperator, version)); } + } resolvableExpressionParser(*this, value); + + _ParseList(resolvableExpressionParser); } @@ -665,6 +705,11 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo) _ParseVersionValue(&version, false); packageInfo->SetVersion(version); seen[B_PACKAGE_INFO_VERSION] = true; + } else if (t.text.ICompare("copyright") == 0) { + BString copyright; + _ParseStringValue(©right); + packageInfo->AddCopyright(copyright); + seen[B_PACKAGE_INFO_COPYRIGHTS] = true; } else if (t.text.ICompare(names[B_PACKAGE_INFO_COPYRIGHTS]) == 0) { if (seen[B_PACKAGE_INFO_COPYRIGHTS]) { BString error = BString(names[B_PACKAGE_INFO_COPYRIGHTS]) @@ -678,6 +723,11 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo) for (int i = 0; i < count; ++i) packageInfo->AddCopyright(*(copyrightList.ItemAt(i))); seen[B_PACKAGE_INFO_COPYRIGHTS] = true; + } else if (t.text.ICompare("license") == 0) { + BString license; + _ParseStringValue(&license); + packageInfo->AddLicense(license); + seen[B_PACKAGE_INFO_LICENSES] = true; } else if (t.text.ICompare(names[B_PACKAGE_INFO_LICENSES]) == 0) { if (seen[B_PACKAGE_INFO_LICENSES]) { BString error = BString(names[B_PACKAGE_INFO_LICENSES]) @@ -769,8 +819,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo) for (int i = 0; i < count; ++i) packageInfo->AddReplaces(*(replacesList.ItemAt(i))); seen[B_PACKAGE_INFO_REPLACES] = true; - } else if (t.text.ICompare(names[B_PACKAGE_INFO_FLAGS]) - == 0) { + } else if (t.text.ICompare(names[B_PACKAGE_INFO_FLAGS]) == 0) { if (seen[B_PACKAGE_INFO_FLAGS]) { BString error = BString(names[B_PACKAGE_INFO_FLAGS]) << " already seen!"; diff --git a/src/kits/print/PrintTransport.cpp b/src/kits/print/PrintTransport.cpp index fbaf87e036..6f7a9e65a5 100644 --- a/src/kits/print/PrintTransport.cpp +++ b/src/kits/print/PrintTransport.cpp @@ -70,19 +70,22 @@ status_t PrintTransport::Open(BNode* printerFolder) return B_ERROR; } - // try first in user add-ons directory + const directory_which paths[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, + B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_SYSTEM_ADDONS_DIRECTORY, + }; BPath path; - find_directory(B_USER_ADDONS_DIRECTORY, &path); + for (uint32 i = 0; i < sizeof(paths) / sizeof(paths[0]); ++i) { + if (find_directory(paths[i], &path) != B_OK) + continue; path.Append("Print/transport"); path.Append(transportName.String()); fAddOnID = load_add_on(path.Path()); - - if (fAddOnID < 0) { - // on failure try in system add-ons directory - find_directory(B_BEOS_ADDONS_DIRECTORY, &path); - path.Append("Print/transport"); - path.Append(transportName.String()); - fAddOnID = load_add_on(path.Path()); + if (fAddOnID >= 0) + break; } if (fAddOnID < 0) { diff --git a/src/kits/print/Printer.cpp b/src/kits/print/Printer.cpp index bd1953623d..c589befc48 100644 --- a/src/kits/print/Printer.cpp +++ b/src/kits/print/Printer.cpp @@ -403,13 +403,18 @@ BPrinter::_DriverPath() const if (driverName.Length() <= 0) return BPath(); - directory_which directorys[] = { B_USER_ADDONS_DIRECTORY, - B_COMMON_ADDONS_DIRECTORY, B_BEOS_ADDONS_DIRECTORY }; + directory_which directories[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, + B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_SYSTEM_ADDONS_DIRECTORY + }; BPath path; driverName.Prepend("Print/"); - for (int32 i = 0; i < 3; ++i) { - if (find_directory(directorys[i], &path) == B_OK) { + for (int32 i = 0; i < sizeof(directories) / sizeof(directories[0]); ++i) { + if (find_directory(directories[i], &path) == B_OK) { path.Append(driverName.String()); BEntry driver(path.Path()); diff --git a/src/kits/print/PrinterDriverAddOn.cpp b/src/kits/print/PrinterDriverAddOn.cpp index 93c7b09d82..0fd57ec565 100644 --- a/src/kits/print/PrinterDriverAddOn.cpp +++ b/src/kits/print/PrinterDriverAddOn.cpp @@ -159,17 +159,27 @@ status_t PrinterDriverAddOn::FindPathToDriver(const char* driver, BPath* path) { status_t result; + result = ::TestForAddonExistence(driver, + B_USER_NONPACKAGED_ADDONS_DIRECTORY, kPrinterDriverFolderName, *path); + if (result == B_OK) + return B_OK; + result = ::TestForAddonExistence(driver, B_USER_ADDONS_DIRECTORY, kPrinterDriverFolderName, *path); if (result == B_OK) return B_OK; + result = ::TestForAddonExistence(driver, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, kPrinterDriverFolderName, *path); + if (result == B_OK) + return B_OK; + result = ::TestForAddonExistence(driver, B_COMMON_ADDONS_DIRECTORY, kPrinterDriverFolderName, *path); if (result == B_OK) return B_OK; - result = ::TestForAddonExistence(driver, B_BEOS_ADDONS_DIRECTORY, + result = ::TestForAddonExistence(driver, B_SYSTEM_ADDONS_DIRECTORY, kPrinterDriverFolderName, *path); return result; } diff --git a/src/kits/screensaver/ScreenSaverRunner.cpp b/src/kits/screensaver/ScreenSaverRunner.cpp index a7855ad89f..c5c4018698 100644 --- a/src/kits/screensaver/ScreenSaverRunner.cpp +++ b/src/kits/screensaver/ScreenSaverRunner.cpp @@ -117,8 +117,13 @@ ScreenSaverRunner::_LoadAddOn() // try all directories until the first one succeeds - directory_which which[] = {B_BEOS_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, - B_USER_ADDONS_DIRECTORY}; + directory_which which[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, + B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_SYSTEM_ADDONS_DIRECTORY, + }; BPath path; for (uint32 i = 0; i < sizeof(which) / sizeof(which[0]); i++) { diff --git a/src/kits/storage/disk_device/DiskDeviceRoster.cpp b/src/kits/storage/disk_device/DiskDeviceRoster.cpp index 9c0e6697a2..59bdf2cba8 100644 --- a/src/kits/storage/disk_device/DiskDeviceRoster.cpp +++ b/src/kits/storage/disk_device/DiskDeviceRoster.cpp @@ -36,9 +36,11 @@ /*! \brief find_directory constants of the add-on dirs to be searched. */ static const directory_which kAddOnDirs[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, - B_BEOS_ADDONS_DIRECTORY + B_SYSTEM_ADDONS_DIRECTORY, }; /*! \brief Size of the kAddOnDirs array. */ static const int32 kAddOnDirCount diff --git a/src/kits/storage/disk_device/DiskSystemAddOnManager.cpp b/src/kits/storage/disk_device/DiskSystemAddOnManager.cpp index 4d00afe3ef..abecb65d55 100644 --- a/src/kits/storage/disk_device/DiskSystemAddOnManager.cpp +++ b/src/kits/storage/disk_device/DiskSystemAddOnManager.cpp @@ -110,13 +110,22 @@ DiskSystemAddOnManager::LoadDiskSystems() return B_OK; StringSet alreadyLoaded; - status_t error = _LoadAddOns(alreadyLoaded, B_USER_ADDONS_DIRECTORY); + status_t error + = _LoadAddOns(alreadyLoaded, B_USER_NONPACKAGED_ADDONS_DIRECTORY); + + if (error == B_OK) + error = _LoadAddOns(alreadyLoaded, B_USER_ADDONS_DIRECTORY); + + if (error == B_OK) { + error + = _LoadAddOns(alreadyLoaded, B_COMMON_NONPACKAGED_ADDONS_DIRECTORY); + } if (error == B_OK) error = _LoadAddOns(alreadyLoaded, B_COMMON_ADDONS_DIRECTORY); if (error == B_OK) - error = _LoadAddOns(alreadyLoaded, B_BEOS_ADDONS_DIRECTORY); + error = _LoadAddOns(alreadyLoaded, B_SYSTEM_ADDONS_DIRECTORY); if (error != B_OK) UnloadDiskSystems(); diff --git a/src/kits/tracker/ContainerWindow.cpp b/src/kits/tracker/ContainerWindow.cpp index f6a5d289ea..22e58479cc 100644 --- a/src/kits/tracker/ContainerWindow.cpp +++ b/src/kits/tracker/ContainerWindow.cpp @@ -2810,14 +2810,21 @@ BContainerWindow::EachAddon(bool (*eachAddon)(const Model *, const char *, BObjectList uniqueList(10, true); BPath path; bool bail = false; - if (find_directory(B_BEOS_ADDONS_DIRECTORY, &path) == B_OK) + if (find_directory(B_USER_NONPACKAGED_ADDONS_DIRECTORY, &path) == B_OK) bail = EachAddon(path, eachAddon, &uniqueList, passThru); if (!bail && find_directory(B_USER_ADDONS_DIRECTORY, &path) == B_OK) bail = EachAddon(path, eachAddon, &uniqueList, passThru); + if (!bail + && find_directory(B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, &path) == B_OK) + EachAddon(path, eachAddon, &uniqueList, passThru); + if (!bail && find_directory(B_COMMON_ADDONS_DIRECTORY, &path) == B_OK) EachAddon(path, eachAddon, &uniqueList, passThru); + + if (!bail && find_directory(B_SYSTEM_ADDONS_DIRECTORY, &path) == B_OK) + bail = EachAddon(path, eachAddon, &uniqueList, passThru); } diff --git a/src/kits/tracker/DeskWindow.cpp b/src/kits/tracker/DeskWindow.cpp index 9ec3db40b2..9c4a0d4acd 100644 --- a/src/kits/tracker/DeskWindow.cpp +++ b/src/kits/tracker/DeskWindow.cpp @@ -175,9 +175,11 @@ BDeskWindow::Init(const BMessage *) // watch add-on directories so that we can track the addons with // corresponding shortcuts - WatchAddOnDir(B_BEOS_ADDONS_DIRECTORY, this); + WatchAddOnDir(B_USER_NONPACKAGED_ADDONS_DIRECTORY, this); WatchAddOnDir(B_USER_ADDONS_DIRECTORY, this); + WatchAddOnDir(B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, this); WatchAddOnDir(B_COMMON_ADDONS_DIRECTORY, this); + WatchAddOnDir(B_SYSTEM_ADDONS_DIRECTORY, this); _inherited::Init(); } diff --git a/src/kits/translation/TranslatorRoster.cpp b/src/kits/translation/TranslatorRoster.cpp index da7f78be8a..a681db7629 100644 --- a/src/kits/translation/TranslatorRoster.cpp +++ b/src/kits/translation/TranslatorRoster.cpp @@ -330,12 +330,14 @@ BTranslatorRoster::Private::AddDefaultPaths() { // add user directories first, so that they can override system translators const directory_which paths[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, - B_BEOS_ADDONS_DIRECTORY, + B_SYSTEM_ADDONS_DIRECTORY, }; - for (uint32 i = fSafeMode ? 1 : 0; i < sizeof(paths) / sizeof(paths[0]); + for (uint32 i = fSafeMode ? 4 : 0; i < sizeof(paths) / sizeof(paths[0]); i++) { BPath path; status_t status = find_directory(paths[i], &path, true); diff --git a/src/libs/print/libgutenprint/config.h b/src/libs/print/libgutenprint/config.h index 278514b3f0..3c59527c90 100644 --- a/src/libs/print/libgutenprint/config.h +++ b/src/libs/print/libgutenprint/config.h @@ -150,7 +150,7 @@ #define PACKAGE_BUGREPORT "gimp-print-devel@lists.sourceforge.net" /* */ -#define PACKAGE_DATA_DIR "/boot/common/data/gutenprint" +#define PACKAGE_DATA_DIR "/system/data/gutenprint" /* */ #define PACKAGE_LIB_DIR "/boot/common/lib/gutenprint" @@ -174,7 +174,7 @@ #define PKGMODULEDIR "/boot/common/lib/gutenprint/5.2/modules" /* */ -#define PKGXMLDATADIR "/boot/common/data/gutenprint" +#define PKGXMLDATADIR "/system/data/gutenprint" /* Package release date. */ #define RELEASE_DATE "01 May 2011" diff --git a/src/libs/print/libprint/Transport.cpp b/src/libs/print/libprint/Transport.cpp index 6a6b967ea1..59f37dc75f 100644 --- a/src/libs/print/libprint/Transport.cpp +++ b/src/libs/print/libprint/Transport.cpp @@ -41,22 +41,23 @@ Transport::Transport(const PrinterData *printerData) fDataStream(0), fAbort(false) { + const directory_which paths[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, + B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_BEOS_ADDONS_DIRECTORY, + }; BPath path; - - if (B_OK == find_directory(B_USER_ADDONS_DIRECTORY, &path)) { + for (uint32 i = 0; i < sizeof(paths) / sizeof(paths[0]); ++i) { + if (find_directory(paths[i], &path) != B_OK) + continue; path.Append("Print/transport"); path.Append(printerData->GetTransport().c_str()); DBGMSG(("load_add_on: %s\n", path.Path())); fImage = load_add_on(path.Path()); - } - - if (fImage < 0) { - if (B_OK == find_directory(B_BEOS_ADDONS_DIRECTORY, &path)) { - path.Append("Print/transport"); - path.Append(printerData->GetTransport().c_str()); - DBGMSG(("load_add_on: %s\n", path.Path())); - fImage = load_add_on(path.Path()); - } + if (fImage >= 0) + break; } if (fImage < 0) { diff --git a/src/preferences/printers/AddPrinterDialog.cpp b/src/preferences/printers/AddPrinterDialog.cpp index e1da4c4014..138798c2eb 100644 --- a/src/preferences/printers/AddPrinterDialog.cpp +++ b/src/preferences/printers/AddPrinterDialog.cpp @@ -285,9 +285,11 @@ AddPrinterDialog::_BuildGUI(int stage) static directory_which gAddonDirs[] = { - B_BEOS_ADDONS_DIRECTORY, + B_USER_NONPACKAGED_ADDONS_DIRECTORY, + B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, - B_USER_ADDONS_DIRECTORY + B_SYSTEM_ADDONS_DIRECTORY, }; diff --git a/src/preferences/screensaver/ScreenSaverWindow.cpp b/src/preferences/screensaver/ScreenSaverWindow.cpp index 5c9382dd94..07d7e91b2e 100644 --- a/src/preferences/screensaver/ScreenSaverWindow.cpp +++ b/src/preferences/screensaver/ScreenSaverWindow.cpp @@ -383,7 +383,7 @@ ModulesView::MessageReceived(BMessage* message) BPath path; if (find_directory(B_SYSTEM_BIN_DIRECTORY, &path) != B_OK || path.Append("screen_blanker") != B_OK) - path.SetTo("/boot/system/bin/screen_blanker"); + path.SetTo("/bin/screen_blanker"); BEntry entry(path.Path()); entry_ref ref; @@ -442,7 +442,12 @@ ModulesView::PopulateScreenSaverList() // Iterate over add-on directories, and add their files to the list view directory_which which[] = { - B_BEOS_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY}; + B_USER_NONPACKAGED_ADDONS_DIRECTORY, + B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, + B_COMMON_ADDONS_DIRECTORY, + B_SYSTEM_ADDONS_DIRECTORY, + }; ScreenSaverItem* selectItem = NULL; for (uint32 i = 0; i < sizeof(which) / sizeof(which[0]); i++) { diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index 6845e1d327..f0b4b040b6 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -25,8 +25,10 @@ #include #include #include +#include #include #include +#include #include #include @@ -2348,7 +2350,12 @@ Desktop::_LaunchInputServer() // Could not load input_server by signature, try well-known location - BEntry entry("/system/servers/input_server"); + BEntry entry; + BPath systemServersDir; + if (find_directory(B_SYSTEM_SERVERS_DIRECTORY, &systemServersDir) == B_OK) + entry.SetTo(systemServersDir.Path()); + else + entry.SetTo("/system/servers/input_server"); entry_ref ref; status_t entryStatus = entry.GetRef(&ref); if (entryStatus == B_OK) diff --git a/src/servers/app/drawing/AccelerantHWInterface.cpp b/src/servers/app/drawing/AccelerantHWInterface.cpp index d4ffb4a794..da81a4e344 100644 --- a/src/servers/app/drawing/AccelerantHWInterface.cpp +++ b/src/servers/app/drawing/AccelerantHWInterface.cpp @@ -272,14 +272,16 @@ AccelerantHWInterface::_OpenAccelerant(int device) struct stat accelerant_stat; const static directory_which dirs[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, - B_BEOS_ADDONS_DIRECTORY + B_SYSTEM_ADDONS_DIRECTORY }; fAccelerantImage = -1; - for (int32 i = 0; i < 3; i++) { + for (uint32 i = 0; i < sizeof(dirs) / sizeof(directory_which); i++) { char path[PATH_MAX]; if (find_directory(dirs[i], -1, false, path, PATH_MAX) != B_OK) continue; diff --git a/src/servers/app/drawing/DWindowHWInterface.cpp b/src/servers/app/drawing/DWindowHWInterface.cpp index 3c87701eee..17c792879f 100644 --- a/src/servers/app/drawing/DWindowHWInterface.cpp +++ b/src/servers/app/drawing/DWindowHWInterface.cpp @@ -465,14 +465,16 @@ DWindowHWInterface::_OpenAccelerant(int device) struct stat accelerant_stat; const static directory_which dirs[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, - B_BEOS_ADDONS_DIRECTORY + B_SYSTEM_ADDONS_DIRECTORY }; fAccelerantImage = -1; - for (int32 i = 0; i < 3; i++) { + for (uint32 i = 0; i < sizeof(dirs) / sizeof(directory_which); i++) { char path[PATH_MAX]; if (find_directory(dirs[i], -1, false, path, PATH_MAX) != B_OK) continue; diff --git a/src/servers/debug/DebugServer.cpp b/src/servers/debug/DebugServer.cpp index ffdb480491..d0517339a0 100644 --- a/src/servers/debug/DebugServer.cpp +++ b/src/servers/debug/DebugServer.cpp @@ -18,7 +18,9 @@ #include #include #include +#include #include +#include #include #include @@ -44,11 +46,6 @@ using std::nothrow; static const char *kSignature = "application/x-vnd.Haiku-debug_server"; -// paths to the apps used for debugging -static const char *kConsoledPath = "/bin/consoled"; -static const char *kTerminalPath = "/boot/system/apps/Terminal"; -static const char *kGDBPath = "/bin/gdb"; - static void KillTeam(team_id team, const char *appName = NULL) @@ -452,12 +449,39 @@ TeamDebugHandler::_EnterDebugger() char teamString[32]; snprintf(teamString, sizeof(teamString), "--pid=%ld", fTeam); - const char *terminal = (debugInConsoled ? kConsoledPath : kTerminalPath); + BPath terminalPath; + if (debugInConsoled) { + error = find_directory(B_SYSTEM_BIN_DIRECTORY, &terminalPath); + if (error != B_OK) { + debug_printf("debug_server: can't find system-bin directory: %s\n", + strerror(error)); + return error; + } + error = terminalPath.Append("consoled"); + if (error != B_OK) { + debug_printf("debug_server: can't append to system-bin path: %s\n", + strerror(error)); + return error; + } + } else { + error = find_directory(B_SYSTEM_APPS_DIRECTORY, &terminalPath); + if (error != B_OK) { + debug_printf("debug_server: can't find system-apps directory: %s\n", + strerror(error)); + return error; + } + error = terminalPath.Append("Terminal"); + if (error != B_OK) { + debug_printf("debug_server: can't append to system-apps path: %s\n", + strerror(error)); + return error; + } + } const char *argv[16]; int argc = 0; - argv[argc++] = terminal; + argv[argc++] = terminalPath.Path(); if (!debugInConsoled) { char windowTitle[64]; @@ -467,7 +491,21 @@ TeamDebugHandler::_EnterDebugger() argv[argc++] = windowTitle; } - argv[argc++] = kGDBPath; + BPath gdbPath; + error = find_directory(B_SYSTEM_BIN_DIRECTORY, &gdbPath); + if (error != B_OK) { + debug_printf("debug_server: can't find system-bin directory: %s\n", + strerror(error)); + return error; + } + error = gdbPath.Append("gdb"); + if (error != B_OK) { + debug_printf("debug_server: can't append to system-bin path: %s\n", + strerror(error)); + return error; + } + + argv[argc++] = gdbPath.Path(); argv[argc++] = teamString; if (strlen(fExecutablePath) > 0) argv[argc++] = fExecutablePath; diff --git a/src/servers/index/IndexServer.cpp b/src/servers/index/IndexServer.cpp index a4c7a925bd..06e0ebde54 100644 --- a/src/servers/index/IndexServer.cpp +++ b/src/servers/index/IndexServer.cpp @@ -332,13 +332,15 @@ IndexServer::_StartWatchingAddOns() // load dormant media nodes const directory_which directories[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, - B_BEOS_ADDONS_DIRECTORY + B_SYSTEM_ADDONS_DIRECTORY }; - // when safemode, only B_BEOS_ADDONS_DIRECTORY is used - for (uint32 i = safeMode ? 2 : 0; + // when safemode, only B_SYSTEM_ADDONS_DIRECTORY is used + for (uint32 i = safeMode ? 4 : 0; i < sizeof(directories) / sizeof(directory_which); i++) { BDirectory directory; node_ref nodeRef; diff --git a/src/servers/input/AddOnManager.cpp b/src/servers/input/AddOnManager.cpp index 4c21212be3..528860f951 100644 --- a/src/servers/input/AddOnManager.cpp +++ b/src/servers/input/AddOnManager.cpp @@ -261,9 +261,11 @@ AddOnManager::_RegisterAddOns() BAutolock locker(this); const directory_which directories[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, - B_BEOS_ADDONS_DIRECTORY + B_SYSTEM_ADDONS_DIRECTORY }; const char* subDirectories[] = { "input_server/devices", @@ -275,8 +277,8 @@ AddOnManager::_RegisterAddOns() node_ref nref; BDirectory directory; BPath path; - // when safemode, only B_BEOS_ADDONS_DIRECTORY is used - for (uint32 i = fSafeMode ? 2 : 0; + // when safemode, only B_SYSTEM_ADDONS_DIRECTORY is used + for (uint32 i = fSafeMode ? 4 : 0; i < sizeof(directories) / sizeof(directory_which); i++) { for (int32 j = 0; j < subDirectoryCount; j++) { if (find_directory(directories[i], &path) == B_OK diff --git a/src/servers/media/AddOnManager.cpp b/src/servers/media/AddOnManager.cpp index 7f293a2c72..19a814e92c 100644 --- a/src/servers/media/AddOnManager.cpp +++ b/src/servers/media/AddOnManager.cpp @@ -58,9 +58,11 @@ private: static const directory_which sDirectories[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, - B_BEOS_ADDONS_DIRECTORY, + B_SYSTEM_ADDONS_DIRECTORY }; @@ -120,8 +122,8 @@ AddOnManager::GetDecoderForFormat(xfer_entry_ref* _decoderRef, "%ld\n", format.Encoding()); // Since the list of decoders is unsorted, we need to search for - // an decoder by add-on directory, in order to maintain the shadowing - // of system add-ons by user add-ons, in case they offer decorders + // a decoder by add-on directory, in order to maintain the shadowing + // of system add-ons by user add-ons, in case they offer decoders // for the same format. BPath path; diff --git a/src/servers/media_addon/MediaAddonServer.cpp b/src/servers/media_addon/MediaAddonServer.cpp index c7f7c38b19..36f386d5bf 100644 --- a/src/servers/media_addon/MediaAddonServer.cpp +++ b/src/servers/media_addon/MediaAddonServer.cpp @@ -294,13 +294,15 @@ MediaAddonServer::ReadyToRun() // load dormant media nodes const directory_which directories[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, - B_BEOS_ADDONS_DIRECTORY + B_SYSTEM_ADDONS_DIRECTORY }; - // when safemode, only B_BEOS_ADDONS_DIRECTORY is used - for (uint32 i = safeMode ? 2 : 0; + // when safemode, only B_SYSTEM_ADDONS_DIRECTORY is used + for (uint32 i = safeMode ? 4 : 0; i < sizeof(directories) / sizeof(directory_which); i++) { BDirectory directory; node_ref nodeRef; diff --git a/src/servers/print/PrintServerApp.cpp b/src/servers/print/PrintServerApp.cpp index e88989048f..5c21c3c6f8 100644 --- a/src/servers/print/PrintServerApp.cpp +++ b/src/servers/print/PrintServerApp.cpp @@ -107,9 +107,11 @@ PrintServerApp::PrintServerApp(status_t* err) fHasReferences = create_sem(1, "has_references"); // Build list of transport addons + Transport::Scan(B_USER_NONPACKAGED_ADDONS_DIRECTORY); Transport::Scan(B_USER_ADDONS_DIRECTORY); + Transport::Scan(B_COMMON_NONPACKAGED_ADDONS_DIRECTORY); Transport::Scan(B_COMMON_ADDONS_DIRECTORY); - Transport::Scan(B_BEOS_ADDONS_DIRECTORY); + Transport::Scan(B_SYSTEM_ADDONS_DIRECTORY); SetupPrinterList(); RetrieveDefaultPrinter(); diff --git a/src/servers/registrar/TRoster.cpp b/src/servers/registrar/TRoster.cpp index 279b192334..adeb02adbf 100644 --- a/src/servers/registrar/TRoster.cpp +++ b/src/servers/registrar/TRoster.cpp @@ -70,11 +70,6 @@ using namespace BPrivate; //! The maximal period of time an app may be early pre-registered (60 s). const bigtime_t kMaximalEarlyPreRegistrationPeriod = 60000000LL; -//! Applications living in these directory are considered "system apps". -// TODO: move those into a common shared system header -static const char* const kSystemAppPath = "/boot/system"; -static const char* const kSystemServerPath = "/boot/system/servers"; - // #pragma mark - Private local functions @@ -141,6 +136,8 @@ TRoster::TRoster() fLastToken(0), fShuttingDown(false) { + find_directory(B_SYSTEM_DIRECTORY, &fSystemAppPath); + find_directory(B_SYSTEM_SERVERS_DIRECTORY, &fSystemServerPath); } @@ -1815,8 +1812,8 @@ TRoster::_IsSystemApp(RosterAppInfo* info) const if (path.SetTo(&info->ref) != B_OK || path.GetParent(&path) != B_OK) return false; - return !strcmp(path.Path(), kSystemAppPath) - || !strcmp(path.Path(), kSystemServerPath); + return !strcmp(path.Path(), fSystemAppPath.Path()) + || !strcmp(path.Path(), fSystemServerPath.Path()); } diff --git a/src/servers/registrar/TRoster.h b/src/servers/registrar/TRoster.h index 7401fcf78b..29c726a453 100644 --- a/src/servers/registrar/TRoster.h +++ b/src/servers/registrar/TRoster.h @@ -13,6 +13,7 @@ #include #include +#include #include #include @@ -123,6 +124,8 @@ private: RecentEntries fRecentFolders; uint32 fLastToken; bool fShuttingDown; + BPath fSystemAppPath; + BPath fSystemServerPath; }; #endif // T_ROSTER_H diff --git a/src/system/boot/loader/loader.cpp b/src/system/boot/loader/loader.cpp index e30cf49587..1137285a16 100644 --- a/src/system/boot/loader/loader.cpp +++ b/src/system/boot/loader/loader.cpp @@ -8,6 +8,7 @@ #include "elf.h" #include "RootFileSystem.h" +#include #include #include #include @@ -28,8 +29,11 @@ static const char *sPaths[] = { - "system/add-ons/kernel", - "home/config/add-ons/kernel", + kVolumeLocalSystemKernelAddonsDirectory, + kVolumeLocalCommonNonpackagedKernelAddonsDirectory, + kVolumeLocalCommonKernelAddonsDirectory, + kVolumeLocalUserNonpackagedKernelAddonsDirectory, + kVolumeLocalUserKernelAddonsDirectory, NULL }; @@ -176,7 +180,8 @@ load_modules(stage2_args *args, Directory *volume) // ToDo: this should be mostly replaced by a hardware oriented detection mechanism - for (int32 i = 0; sPaths[i]; i++) { + int32 i = 0; + for (; sPaths[i]; i++) { char path[B_FILE_NAME_LENGTH]; snprintf(path, sizeof(path), "%s/boot", sPaths[i]); @@ -184,7 +189,7 @@ load_modules(stage2_args *args, Directory *volume) failed++; } - if (failed > 1) { + if (failed == i) { // couldn't load any boot modules // fall back to load all modules (currently needed by the boot floppy) const char *paths[] = { "bus_managers", "busses/ide", "busses/scsi", diff --git a/src/system/kernel/fs/vfs_boot.cpp b/src/system/kernel/fs/vfs_boot.cpp index 8ac02a3656..677be1e11e 100644 --- a/src/system/kernel/fs/vfs_boot.cpp +++ b/src/system/kernel/fs/vfs_boot.cpp @@ -12,6 +12,7 @@ #include +#include #include #include @@ -45,11 +46,11 @@ static struct { const char *path; const char *target; } sPredefinedLinks[] = { - {"/system", "/boot/system"}, - {"/bin", "/boot/system/bin"}, - {"/etc", "/boot/common/etc"}, - {"/var", "/boot/common/var"}, - {"/tmp", "/boot/common/cache/tmp"}, + { kGlobalSystemDirectory, kSystemDirectory }, + { kGlobalBinDirectory, kSystemBinDirectory }, + { kGlobalEtcDirectory, kCommonEtcDirectory }, + { kGlobalTempDirectory, kCommonTempDirectory }, + { kGlobalVarDirectory, kCommonVarDirectory }, {NULL} }; diff --git a/src/system/kernel/main.cpp b/src/system/kernel/main.cpp index a45a947c83..a5797d8940 100644 --- a/src/system/kernel/main.cpp +++ b/src/system/kernel/main.cpp @@ -341,12 +341,12 @@ main2(void *unused) // start the init process { KPath bootScriptPath; - status_t status = find_directory(B_BEOS_SYSTEM_DIRECTORY, gBootDevice, + status_t status = find_directory(B_SYSTEM_BOOT_DIRECTORY, gBootDevice, false, bootScriptPath.LockBuffer(), bootScriptPath.BufferSize()); if (status != B_OK) dprintf("main2: find_directory() failed: %s\n", strerror(status)); bootScriptPath.UnlockBuffer(); - status = bootScriptPath.Append("boot/Bootscript"); + status = bootScriptPath.Append("/Bootscript"); if (status != B_OK) { dprintf("main2: constructing path to Bootscript failed: " "%s\n", strerror(status)); diff --git a/src/system/kernel/team.cpp b/src/system/kernel/team.cpp index 9f6e287b63..3d693e4a8d 100644 --- a/src/system/kernel/team.cpp +++ b/src/system/kernel/team.cpp @@ -1541,7 +1541,7 @@ team_create_thread_start_internal(void* args) { // find runtime_loader path KPath runtimeLoaderPath; - err = find_directory(B_BEOS_SYSTEM_DIRECTORY, gBootDevice, false, + err = find_directory(B_SYSTEM_DIRECTORY, gBootDevice, false, runtimeLoaderPath.LockBuffer(), runtimeLoaderPath.BufferSize()); if (err < B_OK) { TRACE(("team_create_thread_start: find_directory() failed: %s\n", diff --git a/src/system/libroot/os/driver_settings.cpp b/src/system/libroot/os/driver_settings.cpp index 0b2b874317..bb6f6adfb7 100644 --- a/src/system/libroot/os/driver_settings.cpp +++ b/src/system/libroot/os/driver_settings.cpp @@ -28,6 +28,7 @@ # undef _KERNEL_MODE #endif +#include #include #include #include @@ -763,9 +764,7 @@ load_driver_settings(const char *driverName) char path[B_FILE_NAME_LENGTH + 64]; #ifdef _BOOT_MODE - // TODO: for now the boot loader does not support find_directory() - // (it might get a simplified version of it) - strcpy(path, "/boot/home/config/settings"); + strcpy(path, kUserSettingsDirectory); #else // TODO: use B_COMMON_SETTINGS_DIRECTORY instead! if (find_directory(B_USER_SETTINGS_DIRECTORY, -1, false, path, diff --git a/src/system/libroot/os/find_directory.cpp b/src/system/libroot/os/find_directory.cpp index a324dc8df2..4cc257c53c 100644 --- a/src/system/libroot/os/find_directory.cpp +++ b/src/system/libroot/os/find_directory.cpp @@ -1,6 +1,7 @@ /* * Copyright 2004, François Revol. * Copyright 2007-2010, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2011, Oliver Tappe * * Distributed under the terms of the MIT license. */ @@ -14,6 +15,7 @@ # include #endif +#include #include #include @@ -30,9 +32,17 @@ #define USE_PWENTS -/* Haiku system directories */ +/* + * If you change any of the directories below, please have a look at + * headers/private/libroot/directories.h and adjust that accordingly! + */ #define SYSTEM "system" +#define COMMON "common" +#define NON_PACKAGED "/non-packaged" + + +/* Haiku system directories */ static const char *kSystemDirectories[] = { SYSTEM, // B_SYSTEM_DIRECTORY @@ -44,34 +54,33 @@ static const char *kSystemDirectories[] = { SYSTEM "/servers", SYSTEM "/apps", SYSTEM "/bin", - "common/etc", + COMMON "/settings/etc", SYSTEM "/documentation", SYSTEM "/preferences", SYSTEM "/add-ons/Translators", SYSTEM "/add-ons/media", SYSTEM "/data/sounds", SYSTEM "/data", + SYSTEM "/develop", + SYSTEM "/packages", + SYSTEM "/develop/headers", }; /* Common directories, shared among users */ -#define COMMON "common" - // ToDo: this is for now and might be changed back to "home" - // (or even something else) later - static const char *kCommonDirectories[] = { - COMMON "", // B_COMMON_DIRECTORY - COMMON "", // B_COMMON_SYSTEM_DIRECTORY + COMMON, // B_COMMON_DIRECTORY + COMMON, // B_COMMON_SYSTEM_DIRECTORY COMMON "/add-ons", COMMON "/boot", COMMON "/data/fonts", COMMON "/lib", COMMON "/servers", COMMON "/bin", - COMMON "/etc", + COMMON "/settings/etc", COMMON "/documentation", COMMON "/settings", - "develop", // B_COMMON_DEVELOP_DIRECTORY + COMMON "/develop", // B_COMMON_DEVELOP_DIRECTORY COMMON "/var/log", // B_COMMON_LOG_DIRECTORY COMMON "/var/spool", // B_COMMON_SPOOL_DIRECTORY COMMON "/cache/tmp", // B_COMMON_TEMP_DIRECTORY @@ -81,27 +90,54 @@ static const char *kCommonDirectories[] = { COMMON "/data/sounds", COMMON "/data", COMMON "/cache", // B_COMMON_CACHE_DIRECTORY + COMMON "/packages", + COMMON "/develop/headers", + COMMON NON_PACKAGED, + COMMON NON_PACKAGED "/add-ons", + COMMON NON_PACKAGED "/add-ons/Translators", + COMMON NON_PACKAGED "/add-ons/media", + COMMON NON_PACKAGED "/bin", + COMMON NON_PACKAGED "/data", + COMMON NON_PACKAGED "/data/fonts", + COMMON NON_PACKAGED "/data/sounds", + COMMON NON_PACKAGED "/documentation", + COMMON NON_PACKAGED "/lib", + COMMON NON_PACKAGED "/develop/headers", }; /* User directories */ #define HOME "$h" +#define CONFIG "/config" static const char *kUserDirectories[] = { - HOME "", // B_USER_DIRECTORY - HOME "/config", // B_USER_CONFIG_DIRECTORY - HOME "/config/add-ons", - HOME "/config/boot", - HOME "/config/data/fonts", - HOME "/config/lib", - HOME "/config/settings", - HOME "/config/be", - HOME "/config/settings/printers", - HOME "/config/add-ons/Translators", - HOME "/config/add-ons/media", - HOME "/config/data/sounds", - HOME "/config/data", - HOME "/config/cache", + HOME, // B_USER_DIRECTORY + HOME CONFIG, // B_USER_CONFIG_DIRECTORY + HOME CONFIG "/add-ons", + HOME CONFIG "/boot", + HOME CONFIG "/data/fonts", + HOME CONFIG "/lib", + HOME CONFIG "/settings", + HOME CONFIG "/settings/deskbar", + HOME CONFIG "/settings/printers", + HOME CONFIG "/add-ons/Translators", + HOME CONFIG "/add-ons/media", + HOME CONFIG "/data/sounds", + HOME CONFIG "/data", + HOME CONFIG "/cache", + HOME CONFIG "/packages", + HOME CONFIG "/develop/headers", + HOME CONFIG NON_PACKAGED, + HOME CONFIG NON_PACKAGED "/add-ons", + HOME CONFIG NON_PACKAGED "/add-ons/Translators", + HOME CONFIG NON_PACKAGED "/add-ons/media", + HOME CONFIG NON_PACKAGED "/bin", + HOME CONFIG NON_PACKAGED "/data", + HOME CONFIG NON_PACKAGED "/data/fonts", + HOME CONFIG NON_PACKAGED "/data/sounds", + HOME CONFIG NON_PACKAGED "/documentation", + HOME CONFIG NON_PACKAGED "/lib", + HOME CONFIG NON_PACKAGED "/develop/headers", }; @@ -183,6 +219,9 @@ find_directory(directory_which which, dev_t device, bool createIt, strlcat(buffer, "/boot", pathLength); } break; + case B_PACKAGE_LINKS_DIRECTORY: + // this is a directory living in rootfs + break; default: strlcat(buffer, "/boot", pathLength); break; @@ -224,6 +263,9 @@ find_directory(directory_which which, dev_t device, bool createIt, case B_SYSTEM_MEDIA_NODES_DIRECTORY: case B_SYSTEM_SOUNDS_DIRECTORY: case B_SYSTEM_DATA_DIRECTORY: + case B_SYSTEM_DEVELOP_DIRECTORY: + case B_SYSTEM_PACKAGES_DIRECTORY: + case B_SYSTEM_HEADERS_DIRECTORY: templatePath = kSystemDirectories[which - B_SYSTEM_DIRECTORY]; break; @@ -249,6 +291,19 @@ find_directory(directory_which which, dev_t device, bool createIt, case B_COMMON_SOUNDS_DIRECTORY: case B_COMMON_DATA_DIRECTORY: case B_COMMON_CACHE_DIRECTORY: + case B_COMMON_PACKAGES_DIRECTORY: + case B_COMMON_HEADERS_DIRECTORY: + case B_COMMON_NONPACKAGED_DIRECTORY: + case B_COMMON_NONPACKAGED_ADDONS_DIRECTORY: + case B_COMMON_NONPACKAGED_TRANSLATORS_DIRECTORY: + case B_COMMON_NONPACKAGED_MEDIA_NODES_DIRECTORY: + case B_COMMON_NONPACKAGED_BIN_DIRECTORY: + case B_COMMON_NONPACKAGED_DATA_DIRECTORY: + case B_COMMON_NONPACKAGED_FONTS_DIRECTORY: + case B_COMMON_NONPACKAGED_SOUNDS_DIRECTORY: + case B_COMMON_NONPACKAGED_DOCUMENTATION_DIRECTORY: + case B_COMMON_NONPACKAGED_LIB_DIRECTORY: + case B_COMMON_NONPACKAGED_HEADERS_DIRECTORY: templatePath = kCommonDirectories[which - B_COMMON_DIRECTORY]; break; @@ -267,6 +322,19 @@ find_directory(directory_which which, dev_t device, bool createIt, case B_USER_SOUNDS_DIRECTORY: case B_USER_DATA_DIRECTORY: case B_USER_CACHE_DIRECTORY: + case B_USER_PACKAGES_DIRECTORY: + case B_USER_HEADERS_DIRECTORY: + case B_USER_NONPACKAGED_DIRECTORY: + case B_USER_NONPACKAGED_ADDONS_DIRECTORY: + case B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY: + case B_USER_NONPACKAGED_MEDIA_NODES_DIRECTORY: + case B_USER_NONPACKAGED_BIN_DIRECTORY: + case B_USER_NONPACKAGED_DATA_DIRECTORY: + case B_USER_NONPACKAGED_FONTS_DIRECTORY: + case B_USER_NONPACKAGED_SOUNDS_DIRECTORY: + case B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY: + case B_USER_NONPACKAGED_LIB_DIRECTORY: + case B_USER_NONPACKAGED_HEADERS_DIRECTORY: templatePath = kUserDirectories[which - B_USER_DIRECTORY]; break; @@ -280,6 +348,9 @@ find_directory(directory_which which, dev_t device, bool createIt, case B_UTILITIES_DIRECTORY: templatePath = "utilities"; break; + case B_PACKAGE_LINKS_DIRECTORY: + templatePath = "package-links"; + break; default: free(buffer); @@ -311,7 +382,7 @@ find_directory(directory_which which, dev_t device, bool createIt, } #endif // !_KERNEL_MODE if (!home) - home = "/boot/home"; + home = kUserDirectory; strncpy(buffer, home, pathLength); } templatePath += 2; diff --git a/src/system/libroot/posix/unistd/conf.cpp b/src/system/libroot/posix/unistd/conf.cpp index c54ecf1baa..51d398e4dd 100644 --- a/src/system/libroot/posix/unistd/conf.cpp +++ b/src/system/libroot/posix/unistd/conf.cpp @@ -15,6 +15,7 @@ #include +#include #include #include #include @@ -385,8 +386,8 @@ confstr(int name, char *buffer, size_t length) switch (name) { case _CS_PATH: - string = "/bin:/boot/system/apps:" \ - "/boot/common/bin:/boot/develop/bin"; + string = kGlobalBinDirectory ":" kSystemAppsDirectory ":" + kCommonBinDirectory ":" kCommonDevelopToolsBinDirectory; break; default: errno = EINVAL; diff --git a/src/system/runtime_loader/Jamfile b/src/system/runtime_loader/Jamfile index cfb8fc0e66..d687912673 100644 --- a/src/system/runtime_loader/Jamfile +++ b/src/system/runtime_loader/Jamfile @@ -1,6 +1,6 @@ SubDir HAIKU_TOP src system runtime_loader ; -UsePrivateHeaders runtime_loader shared ; +UsePrivateHeaders libroot runtime_loader shared ; UsePrivateHeaders kernel ; # for UsePrivateSystemHeaders ; diff --git a/src/system/runtime_loader/runtime_loader.cpp b/src/system/runtime_loader/runtime_loader.cpp index f253c64266..549195b085 100644 --- a/src/system/runtime_loader/runtime_loader.cpp +++ b/src/system/runtime_loader/runtime_loader.cpp @@ -13,6 +13,8 @@ #include #include +#include + #include #include #include @@ -53,28 +55,32 @@ search_path_for_type(image_type type) switch (type) { case B_APP_IMAGE: - return "/boot/home/config/bin" + return kUserBinDirectory // TODO: Remove! - ":/boot/common/bin" - ":/bin" - ":/boot/apps" - ":/boot/preferences" - ":/boot/system/apps" - ":/boot/system/preferences" - ":/boot/develop/tools/gnupro/bin"; + ":" kCommonBinDirectory + ":" kGlobalBinDirectory + ":" kAppsDirectory + ":" kPreferencesDirectory + ":" kSystemAppsDirectory + ":" kSystemPreferencesDirectory + ":" kCommonDevelopToolsBinDirectory; case B_LIBRARY_IMAGE: - return "%A/lib" - ":/boot/home/config/lib" + return kAppLocalLibDirectory + ":" kUserNonpackagedLibDirectory + ":" kUserLibDirectory // TODO: Remove! - ":/boot/common/lib:/boot/system/lib"; + ":" kCommonNonpackagedLibDirectory + ":" kCommonLibDirectory + ":" kSystemLibDirectory; case B_ADD_ON_IMAGE: - return "%A/add-ons" - ":/boot/home/config/add-ons" + return kAppLocalAddonsDirectory + ":" kUserNonpackagedAddonsDirectory + ":" kUserAddonsDirectory // TODO: Remove! - ":/boot/common/add-ons" - ":/boot/system/add-ons"; + ":" kCommonNonpackagedAddonsDirectory + ":" kSystemAddonsDirectory; default: return NULL; @@ -399,13 +405,6 @@ runtime_loader(void *_args) gProgramArgs->env[i] += relocationOffset; } - if (!strcmp(gProgramArgs->program_path, "/boot/system/runtime_loader")) { - // TODO: this is a (temporary) work-around for bug #2273 which causes - // the cache's mutex to be locked twice when starting the runtime_loader - // itself. - return 1; - } - #if DEBUG_RLD close(0); open("/dev/console", 0); /* stdin */ close(1); open("/dev/console", 0); /* stdout */ diff --git a/src/tests/add-ons/print/transports/main.cpp b/src/tests/add-ons/print/transports/main.cpp index b5df84542f..2966a185dd 100644 --- a/src/tests/add-ons/print/transports/main.cpp +++ b/src/tests/add-ons/print/transports/main.cpp @@ -69,7 +69,9 @@ int main (int argc, char *argv[]) printf("Looking for %s transport addon:\n", transport); directory_which which[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, B_SYSTEM_ADDONS_DIRECTORY }; diff --git a/src/tests/kits/translation/TranslationUtilsTest.cpp b/src/tests/kits/translation/TranslationUtilsTest.cpp index b72a8ed3bd..4eff435c40 100644 --- a/src/tests/kits/translation/TranslationUtilsTest.cpp +++ b/src/tests/kits/translation/TranslationUtilsTest.cpp @@ -357,7 +357,8 @@ TranslationUtilsTest::AddTranslationItemsTest() BTranslatorRoster *proster = new BTranslatorRoster(); CPPUNIT_ASSERT(proster); CPPUNIT_ASSERT(proster->AddTranslators( - "/boot/beos/system/add-ons/Translators/PPMTranslator") == B_OK); + "/boot/beos/system/add-ons/Translators/PPMTranslator" + ) == B_OK); CPPUNIT_ASSERT(BTranslationUtils::AddTranslationItems(pmenu, B_TRANSLATOR_BITMAP, NULL, NULL, NULL, proster) == B_OK); CPPUNIT_ASSERT(pmenu->CountItems() == 1); diff --git a/src/tests/kits/translation/TranslatorRosterTest.cpp b/src/tests/kits/translation/TranslatorRosterTest.cpp index 66347bb3ac..52dc5045dd 100644 --- a/src/tests/kits/translation/TranslatorRosterTest.cpp +++ b/src/tests/kits/translation/TranslatorRosterTest.cpp @@ -446,7 +446,8 @@ TranslatorRosterTest::AddTranslatorsTest() BTranslatorRoster* proster = new BTranslatorRoster(); CPPUNIT_ASSERT(proster); CPPUNIT_ASSERT(proster->AddTranslators( - "/boot/home/config/add-ons/Translators/:/system/add-ons/Translators/") == B_OK); + "/boot/home/config/add-ons/Translators/:" + "/system/add-ons/Translators/") == B_OK); NextSubTest(); int32 instcount = 0; diff --git a/src/tests/servers/app/newerClipping/drawing/AccelerantHWInterface.cpp b/src/tests/servers/app/newerClipping/drawing/AccelerantHWInterface.cpp index 4425179977..70d7727a1c 100644 --- a/src/tests/servers/app/newerClipping/drawing/AccelerantHWInterface.cpp +++ b/src/tests/servers/app/newerClipping/drawing/AccelerantHWInterface.cpp @@ -199,14 +199,16 @@ AccelerantHWInterface::_OpenAccelerant(int device) struct stat accelerant_stat; const static directory_which dirs[] = { + B_USER_NONPACKAGED_ADDONS_DIRECTORY, B_USER_ADDONS_DIRECTORY, + B_COMMON_NONPACKAGED_ADDONS_DIRECTORY, B_COMMON_ADDONS_DIRECTORY, - B_BEOS_ADDONS_DIRECTORY + B_SYSTEM_ADDONS_DIRECTORY }; fAccelerantImage = -1; - for (int32 i = 0; i < 3; i++) { + for (int32 i = 0; i < sizeof(dirs) / sizeof(directory_which); i++) { char path[PATH_MAX]; if (find_directory(dirs[i], -1, false, path, PATH_MAX) != B_OK) continue; diff --git a/src/tools/translation/inspector/InspectorApp.cpp b/src/tools/translation/inspector/InspectorApp.cpp index 9373bd0636..41641d71e7 100644 --- a/src/tools/translation/inspector/InspectorApp.cpp +++ b/src/tools/translation/inspector/InspectorApp.cpp @@ -52,7 +52,8 @@ InspectorApp::InspectorApp() AddToTranslatorsList("/system/add-ons/Translators", SYSTEM_TRANSLATOR); - AddToTranslatorsList("/boot/home/config/add-ons/Translators", + AddToTranslatorsList( + "/boot/home/config/add-ons/Translators", USER_TRANSLATOR); // Show application window From bc93eff874d5240b252c388381dac84cb34f5821 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 18:56:46 +0200 Subject: [PATCH 0002/1170] Added BuildPlatformStaticLibraryPIC rule. It works like BuildPlatformStaticLibrary, but generates position independent code. --- build/jam/MainBuildRules | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/build/jam/MainBuildRules b/build/jam/MainBuildRules index 69d6597d3d..4284ae7720 100644 --- a/build/jam/MainBuildRules +++ b/build/jam/MainBuildRules @@ -724,3 +724,12 @@ rule BuildPlatformStaticLibrary lib : sources : otherObjects StaticLibrary $(lib) : $(sources) : $(otherObjects) ; } +rule BuildPlatformStaticLibraryPIC target : sources : otherObjects +{ + # Like BuildPlatformStaticLibrary, but producing position independent code. + + ObjectCcFlags $(sources) : $(HOST_PIC_CCFLAGS) ; + ObjectC++Flags $(sources) : $(HOST_PIC_C++FLAGS) ; + + BuildPlatformStaticLibrary $(target) : $(sources) : $(otherObjects) ; +} From bd9d1df3a00fe5bb03cb1941d3b7cfdc659294e0 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 19:12:46 +0200 Subject: [PATCH 0003/1170] Added very simple BLooper class to libbe_build. --- headers/build/os/app/Looper.h | 29 ++++++++++++++++++++++++++++- src/build/libbe/app/Jamfile | 1 + src/build/libbe/app/Looper.cpp | 12 ++++++++++++ 3 files changed, 41 insertions(+), 1 deletion(-) create mode 100644 src/build/libbe/app/Looper.cpp diff --git a/headers/build/os/app/Looper.h b/headers/build/os/app/Looper.h index 945f37a455..dd446ca359 100644 --- a/headers/build/os/app/Looper.h +++ b/headers/build/os/app/Looper.h @@ -1 +1,28 @@ -#include <../os/app/Looper.h> +/* + * Copyright 2011, Haiku, Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ +#ifndef _LOOPER_H +#define _LOOPER_H + + +#include + + +// Port (Message Queue) Capacity +#define B_LOOPER_PORT_DEFAULT_CAPACITY 200 + + +class BLooper { +public: + BLooper(const char* name = NULL, + int32 priority = B_NORMAL_PRIORITY, + int32 port_capacity + = B_LOOPER_PORT_DEFAULT_CAPACITY); + + bool Lock() { return true; } + void Unlock() {} +}; + + +#endif // _LOOPER_H diff --git a/src/build/libbe/app/Jamfile b/src/build/libbe/app/Jamfile index 59459946c2..337083dd08 100644 --- a/src/build/libbe/app/Jamfile +++ b/src/build/libbe/app/Jamfile @@ -9,6 +9,7 @@ USES_BE_API on app_kit.o = true ; BuildPlatformMergeObjectPIC app_kit.o : Application.cpp AppMisc.cpp + Looper.cpp Message.cpp MessageAdapter.cpp Messenger.cpp diff --git a/src/build/libbe/app/Looper.cpp b/src/build/libbe/app/Looper.cpp new file mode 100644 index 0000000000..52254879a1 --- /dev/null +++ b/src/build/libbe/app/Looper.cpp @@ -0,0 +1,12 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + + +BLooper::BLooper(const char* name, int32 priority, int32 port_capacity) +{ +} From 1044b2eb82b4644cfe261301a652c261b3168f26 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 19:14:23 +0200 Subject: [PATCH 0004/1170] Added missing include. --- headers/build/os/storage/File.h | 1 + 1 file changed, 1 insertion(+) diff --git a/headers/build/os/storage/File.h b/headers/build/os/storage/File.h index 62b0d45814..96e589823f 100644 --- a/headers/build/os/storage/File.h +++ b/headers/build/os/storage/File.h @@ -12,6 +12,7 @@ #include #include +#include /*! From 41f39d0dd67e999ce7d339726cfab5ea0d0ad6d5 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 19:15:14 +0200 Subject: [PATCH 0005/1170] Removed obsolete TODO. --- src/bin/package/Jamfile | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/bin/package/Jamfile b/src/bin/package/Jamfile index 70c4ae3568..f15ae3f7f3 100644 --- a/src/bin/package/Jamfile +++ b/src/bin/package/Jamfile @@ -2,9 +2,6 @@ SubDir HAIKU_TOP src bin package ; UsePrivateHeaders kernel shared ; -DEFINES += B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT ; - # TODO: Remove when it is complete! - BinCommand package : command_create.cpp command_dump.cpp From 5eedc38011960b59a07c8ef16a2c7f5ce1c3d72a Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 19:46:18 +0200 Subject: [PATCH 0006/1170] Fixed printf() format related warnings. --- src/bin/package/command_create.cpp | 24 +++++++++++++----------- src/bin/package/command_list.cpp | 5 +++-- 2 files changed, 16 insertions(+), 13 deletions(-) diff --git a/src/bin/package/command_create.cpp b/src/bin/package/command_create.cpp index 5e901e99b9..66fbb6c28b 100644 --- a/src/bin/package/command_create.cpp +++ b/src/bin/package/command_create.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2011, Oliver Tappe * Distributed under the terms of the MIT License. */ @@ -11,6 +11,7 @@ #include #include #include +#include #include @@ -53,11 +54,11 @@ public: return; printf("----- TOC Info -----------------------------------\n"); - printf("cached strings size: %10llu (uncompressed)\n", + printf("cached strings size: %10" B_PRIu64 " (uncompressed)\n", uncompressedStringsSize); - printf("TOC main size: %10llu (uncompressed)\n", + printf("TOC main size: %10" B_PRIu64 " (uncompressed)\n", uncompressedMainSize); - printf("total TOC size: %10llu (uncompressed)\n", + printf("total TOC size: %10" B_PRIu64 " (uncompressed)\n", uncompressedTOCSize); } @@ -68,8 +69,8 @@ public: return; printf("----- Package Attribute Info ---------------------\n"); - printf("string count: %10lu\n", stringCount); - printf("package attributes size: %10lu (uncompressed)\n", + printf("string count: %10" B_PRIu32 "\n", stringCount); + printf("package attributes size: %10" B_PRIu32 " (uncompressed)\n", uncompressedSize); } @@ -80,11 +81,12 @@ public: return; printf("----- Package Info ----------------\n"); - printf("header size: %10lu\n", headerSize); - printf("heap size: %10llu\n", heapSize); - printf("TOC size: %10llu\n", tocSize); - printf("package attributes size: %10lu\n", packageAttributesSize); - printf("total size: %10llu\n", totalSize); + printf("header size: %10" B_PRIu32 "\n", headerSize); + printf("heap size: %10" B_PRIu64 "\n", heapSize); + printf("TOC size: %10" B_PRIu64 "\n", tocSize); + printf("package attributes size: %10" B_PRIu32 "\n", + packageAttributesSize); + printf("total size: %10" B_PRIu64 "\n", totalSize); printf("-----------------------------------\n"); } diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp index 0c2671d43a..c7ba11284b 100644 --- a/src/bin/package/command_list.cpp +++ b/src/bin/package/command_list.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -96,7 +97,7 @@ struct PackageContentListHandler : BPackageContentHandler { printf(" '%c%c%c%c'", int(type >> 24), int((type >> 16) & 0xff), int((type >> 8) & 0xff), int(type & 0xff)); } else - printf(" %#lx", type); + printf(" %#" B_PRIx32, type); printf(">\n"); return B_OK; From 1cb2d5a467d5d56b1c219ea7f891db960df09a1e Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 19:49:36 +0200 Subject: [PATCH 0007/1170] Use fs_close_attr()/write_pos() instead of close()/pwrite(). This makes it easier to reuse the code on non-Haiku platforms. --- src/bin/package/command_extract.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/bin/package/command_extract.cpp b/src/bin/package/command_extract.cpp index 28c30b69da..49d7562d63 100644 --- a/src/bin/package/command_extract.cpp +++ b/src/bin/package/command_extract.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -209,7 +209,7 @@ struct PackageContentExtractHandler : BPackageContentHandler { } else error = _ExtractFileData(&fPackageFileReader, data, fd); - close(fd); + fs_close_attr(fd); return error; } @@ -278,7 +278,7 @@ private: } // write - ssize_t bytesWritten = pwrite(fd, fDataBuffer, toCopy, offset); + ssize_t bytesWritten = write_pos(fd, offset, fDataBuffer, toCopy); if (bytesWritten < 0) { fprintf(stderr, "Error: Failed to write data: %s\n", strerror(errno)); From f1eeb32334a0d50d9f558095c85d99ff4316e219 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 19:58:24 +0200 Subject: [PATCH 0008/1170] Fixed x86_64 handling by the build system. * Map build variables HOST_CPU and HOST_ARCH to x86_64, if it they are * x86 and 64 bit and define the __x86_64__ C macro instead of __INTEL__ in that case. * : Also handle __x86_64__. --- build/jam/BuildSetup | 11 +++++++++-- headers/os/kernel/OS.h | 2 ++ 2 files changed, 11 insertions(+), 2 deletions(-) diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index 59f816336e..1830a6b8a5 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -583,6 +583,11 @@ if $(HOST_PLATFORM) = cygwin { HOST_CPU ?= $(OSPLAT:L) ; +# Jam doesn't know x86_64, so override HOST_CPU, if 64 bit. +if $(HOST_CPU) = x86 && $(HOST_PLATFORM_IS_64_BIT) { + HOST_CPU = x86_64 ; +} + HOST_ARCH ?= $(HOST_CPU) ; HOST_ARCH_MACRO_DEFINE = ARCH_$(HOST_CPU) ; @@ -677,7 +682,7 @@ for level in $(HAIKU_DEBUG_LEVELS[2-]) { } # ld flags -if $(HOST_ARCH) = x86 && $(HAIKU_HOST_USE_32BIT) = 1 { +if $(HOST_ARCH) = x86_64 && $(HAIKU_HOST_USE_32BIT) = 1 { HOST_LDFLAGS += -melf_i386 ; } @@ -762,7 +767,7 @@ if $(HOST_PLATFORM_BEOS_COMPATIBLE) { HOST_LIBSUPC++ = gcc_s.1 stdc++ ; HOST_LIBSTDC++ = ; } else if $(HOST_PLATFORM) = freebsd { - if $(HOST_CPU) = x86 && $(HOST_PLATFORM_IS_64_BIT) = 1 { + if $(HOST_CPU) = x86_64 { # amd64 FreeBSD 8 doesn't come without a shared libsupc++, and the # static one prevents us from building shared libraries. So we have # to work around by using the shared libstdc++. @@ -784,6 +789,8 @@ if $(HOST_PLATFORM_BEOS_COMPATIBLE) { # build platform we need to make sure, this is also defined. if $(HOST_CPU) = x86 { HOST_DEFINES += __INTEL__ ; + } else if $(HOST_CPU) = x86_64 { + HOST_DEFINES += __x86_64__ ; } else if $(HOST_CPU) = ppc { HOST_DEFINES += __POWERPC__ ; } else if $(HOST_CPU) = m68k { diff --git a/headers/os/kernel/OS.h b/headers/os/kernel/OS.h index a12deed5cd..383f857e9c 100644 --- a/headers/os/kernel/OS.h +++ b/headers/os/kernel/OS.h @@ -414,6 +414,8 @@ extern void ktrace_vprintf(const char *format, va_list args); #if __INTEL__ # define B_MAX_CPU_COUNT 8 +#elif __x86_64__ +# define B_MAX_CPU_COUNT 8 #elif __POWERPC__ # define B_MAX_CPU_COUNT 8 #elif __M68K__ From b795c9ce72dbd063cd30fcc051c7044153725d9f Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 20:03:33 +0200 Subject: [PATCH 0009/1170] Made the check for B_BUFFER_OVERFLOW more flexible. --- src/system/libroot/os/driver_settings.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/libroot/os/driver_settings.cpp b/src/system/libroot/os/driver_settings.cpp index bb6f6adfb7..5aa4c83915 100644 --- a/src/system/libroot/os/driver_settings.cpp +++ b/src/system/libroot/os/driver_settings.cpp @@ -53,7 +53,7 @@ #include #include -#ifndef HAIKU_TARGET_PLATFORM_HAIKU +#ifndef B_BUFFER_OVERFLOW # define B_BUFFER_OVERFLOW B_ERROR #endif From 62fef8b3fc0c41f048133edbbdb2dec3b2d65c3c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 20:05:01 +0200 Subject: [PATCH 0010/1170] Added driver settings and find_directory() support. find_directory() is a very simplified implementation, only supporting what we currently need. --- src/build/libroot/Jamfile | 16 ++++- src/build/libroot/find_directory.cpp | 97 ++++++++++++++++++++++++++++ 2 files changed, 112 insertions(+), 1 deletion(-) create mode 100644 src/build/libroot/find_directory.cpp diff --git a/src/build/libroot/Jamfile b/src/build/libroot/Jamfile index 8f244ab532..767c6371f3 100644 --- a/src/build/libroot/Jamfile +++ b/src/build/libroot/Jamfile @@ -9,7 +9,7 @@ UseHeaders [ FDirName $(HAIKU_TOP) headers build os interface ] : true ; UseHeaders [ FDirName $(HAIKU_TOP) headers build os storage ] : true ; UseHeaders [ FDirName $(HAIKU_TOP) headers build os support ] : true ; -UsePrivateBuildHeaders kernel ; +UsePrivateBuildHeaders kernel libroot ; { local defines = [ FDefines @@ -17,8 +17,15 @@ UsePrivateBuildHeaders kernel ; ] ; SubDirCcFlags $(defines) ; SubDirC++Flags $(defines) ; + + local defines = [ FDefines + HAIKU_BUILD_GENERATED_DIRECTORY="\\\"$(HAIKU_OUTPUT_DIR)\\\"" + ] ; + SubDirC++Flags $(defines) ; + ObjectC++Flags find_directory.cpp : $(defines) ; } + DEFINES += KMESSAGE_CONTAINER_ONLY ; ObjectC++Flags KMessage.cpp : $(HOST_BE_API_C++FLAGS) ; @@ -44,6 +51,7 @@ local librootSources = atomic.cpp byteorder.cpp errors.cpp + find_directory.cpp fs.cpp fs_attr.cpp fs_descriptors.cpp @@ -53,12 +61,16 @@ local librootSources = $(hostPlatformSources) + driver_settings.cpp + $(strlSources) strnlen.c KMessage.cpp ; +USES_BE_API on [ FGristFiles $(librootSources:S=$(SUFOBJ)) ] = true ; + BuildPlatformSharedLibrary libroot_build.so : $(librootSources) : @@ -70,6 +82,8 @@ BuildPlatformStaticLibrary libroot_build.a : [ FGristFiles $(librootSources:S=$(SUFOBJ)) ] ; +SEARCH on [ FGristFiles driver_settings.cpp ] + = [ FDirName $(HAIKU_TOP) src system libroot os ] ; SEARCH on [ FGristFiles $(strlSources) strnlen.c ] = [ FDirName $(HAIKU_TOP) src system libroot posix string ] ; SEARCH on [ FGristFiles KMessage.cpp ] diff --git a/src/build/libroot/find_directory.cpp b/src/build/libroot/find_directory.cpp new file mode 100644 index 0000000000..061ecf7bc6 --- /dev/null +++ b/src/build/libroot/find_directory.cpp @@ -0,0 +1,97 @@ +/* + * Copyright 2004, François Revol. + * Copyright 2007-2010, Axel Dörfler, axeld@pinc-software.de. + * Copyright 2011, Oliver Tappe + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include +#include +#include +#include + +#include + + +#ifndef HAIKU_BUILD_GENERATED_DIRECTORY +# error HAIKU_BUILD_GENERATED_DIRECTORY not defined! +#endif + + +/*! make dir and its parents if needed */ +static int +create_path(const char *path, mode_t mode) +{ + char buffer[B_PATH_NAME_LENGTH + 1]; + int pathLength; + int i = 0; + + if (path == NULL || ((pathLength = strlen(path)) > B_PATH_NAME_LENGTH)) + return EINVAL; + + while (++i < pathLength) { + const char *slash = strchr(&path[i], '/'); + struct stat st; + + if (slash == NULL) + i = pathLength; + else if (i != slash - path) + i = slash - path; + else + continue; + + strlcpy(buffer, path, i + 1); + if (stat(buffer, &st) < 0) { + errno = 0; + if (mkdir(buffer, mode) < 0) + return errno; + } + } + + return 0; +} + + +status_t +find_directory(directory_which which, dev_t device, bool createIt, + char *returnedPath, int32 pathLength) +{ + // we support only the handful of paths we need + const char* path; + switch (which) { + case B_COMMON_TEMP_DIRECTORY: + path = HAIKU_BUILD_GENERATED_DIRECTORY "/tmp"; + break; + case B_COMMON_SETTINGS_DIRECTORY: + path = HAIKU_BUILD_GENERATED_DIRECTORY "/common/settings"; + break; + case B_COMMON_CACHE_DIRECTORY: + path = HAIKU_BUILD_GENERATED_DIRECTORY "/common/cache"; + break; + case B_USER_SETTINGS_DIRECTORY: + path = HAIKU_BUILD_GENERATED_DIRECTORY "/user/settings"; + break; + case B_USER_CACHE_DIRECTORY: + path = HAIKU_BUILD_GENERATED_DIRECTORY "/user/cache"; + break; + default: + return B_BAD_VALUE; + } + + // create, if necessary + status_t error = B_OK; + struct stat st; + if (createIt && stat(path, &st) < 0) + error = create_path(path, 0755); + + if (error == B_OK) + strlcpy(returnedPath, path, pathLength); + + return error; +} + From e781b1b5a801e6fe2f364a302e3201458b07e58f Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 20:21:53 +0200 Subject: [PATCH 0011/1170] Open/close attribute support for xattrs backend For the xattr/BSD (untyped) attribute backend implement fs_fopen_attr() and fs_close_attr(). A new AttributeDescriptor is created. It is currently used in write_pos() only. --- src/build/libroot/fs.cpp | 111 ++++++++++--------- src/build/libroot/fs_attr_generic.cpp | 54 +++++----- src/build/libroot/fs_attr_untyped.cpp | 44 ++++++-- src/build/libroot/fs_descriptors.cpp | 147 ++++++++++++++++++++++++++ src/build/libroot/fs_descriptors.h | 36 ++++++- 5 files changed, 305 insertions(+), 87 deletions(-) diff --git a/src/build/libroot/fs.cpp b/src/build/libroot/fs.cpp index 35351ae01c..f8c0af2798 100644 --- a/src/build/libroot/fs.cpp +++ b/src/build/libroot/fs.cpp @@ -130,17 +130,17 @@ normalize_dir_path(string path, NodeRef ref, string &normalizedPath) status_t error = find_dir_entry(path.c_str(), ref, name, true) ; if (error != B_OK) return error; - + // recurse to get the parent dir path, if found error = normalize_dir_path(path, parentRef, normalizedPath); if (error != 0) return error; - // construct the normalizedPath + // construct the normalizedPath if (normalizedPath.length() > 1) // don't append "/", if parent is root normalizedPath += '/'; normalizedPath += name; - + return 0; } @@ -152,7 +152,7 @@ normalize_dir_path(const char *path, string &normalizedPath) struct stat st; if (stat(path, &st) < 0) return errno; - + return normalize_dir_path(path, NodeRef(st), normalizedPath); } @@ -162,7 +162,7 @@ normalize_entry_path(const char *path, string &normalizedPath) { const char *dirPath = NULL; const char *leafName = NULL; - + string dirPathString; if (const char *lastSlash = strrchr(path, '/')) { // found a slash: decompose into dir path and leaf name @@ -184,7 +184,7 @@ normalize_entry_path(const char *path, string &normalizedPath) // catch special case: no leaf, or leaf is a directory if (!leafName || strcmp(leafName, ".") == 0 || strcmp(leafName, "..") == 0) return normalize_dir_path(path, normalizedPath); - + // normalize the dir path status_t error = normalize_dir_path(dirPath, normalizedPath); if (error != B_OK) @@ -222,7 +222,7 @@ get_path(const NodeRef *ref, const char *name, string &path) DirPathMap::iterator it = sDirPathMap.find(*ref); if (it == sDirPathMap.end()) return B_ENTRY_NOT_FOUND; - + path = it->second; // stat the path to check, if it is still valid @@ -250,7 +250,7 @@ get_path(const NodeRef *ref, const char *name, string &path) path += '/'; path += name; } - + return B_OK; } @@ -272,7 +272,7 @@ BPrivate::get_path(int fd, const char *name, string &path) return error; return ::get_path(&ref, name, path); - + } else // no descriptor or absolute path return ::get_path((NodeRef*)NULL, name, path); } @@ -284,7 +284,7 @@ get_path(dev_t device, ino_t directory, const char *name, string &path) NodeRef ref; ref.device = device; ref.node = directory; - + return get_path(&ref, name, path); } @@ -315,7 +315,7 @@ _kern_entry_ref_to_path(dev_t device, ino_t node, const char *leaf, // copy it back to the user buffer if (strlcpy(userPath, path.c_str(), pathLength) >= pathLength) return B_BUFFER_OVERFLOW; - + return B_OK; } @@ -334,8 +334,8 @@ _kern_create_dir(int fd, const char *path, int perms) // mkdir if (mkdir(realPath.c_str(), perms) < 0) - return errno; - + return errno; + return B_OK; } @@ -352,8 +352,8 @@ _kern_create_dir_entry_ref(dev_t device, ino_t node, const char *name, // mkdir if (mkdir(realPath.c_str(), perms) < 0) - return errno; - + return errno; + return B_OK; } @@ -382,7 +382,7 @@ open_dir(const char *path) NodeRef ref(st); add_dir_path(path, ref); - // create descriptor + // create descriptor DirectoryDescriptor *descriptor = new DirectoryDescriptor(dir, ref); return add_descriptor(descriptor); } @@ -443,7 +443,7 @@ _kern_open_parent_dir(int fd, char *name, size_t nameLength) return B_BUFFER_OVERFLOW; // open the parent directory - + return open_dir(realPath.c_str()); } @@ -455,7 +455,7 @@ _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, if (maxCount <= 0) return B_BAD_VALUE; - // get the descriptor + // get the descriptor DirectoryDescriptor *descriptor = dynamic_cast(get_descriptor(fd)); if (!descriptor) @@ -484,7 +484,7 @@ _kern_read_dir(int fd, struct dirent *buffer, size_t bufferSize, status_t _kern_rewind_dir(int fd) { - // get the descriptor + // get the descriptor DirectoryDescriptor *descriptor = dynamic_cast(get_descriptor(fd)); if (!descriptor) @@ -523,7 +523,7 @@ open_file(const char *path, int openMode, int perms) status_t error = normalize_entry_path(path, normalizedPath); if (error != B_OK) return error; - + descriptor = new SymlinkDescriptor(normalizedPath.c_str()); } else { // open the file @@ -534,11 +534,11 @@ open_file(const char *path, int openMode, int perms) descriptor = new FileDescriptor(newFD); } - + // cache path, if this is a directory if (exists && S_ISDIR(st.st_mode)) add_dir_path(path, NodeRef(st)); - + return add_descriptor(descriptor); } @@ -603,7 +603,7 @@ _kern_read(int fd, off_t pos, void *buffer, size_t bufferSize) if (result < 0) return errno; } - + // read ssize_t bytesRead = haiku_host_platform_read(descriptor->fd, buffer, bufferSize); @@ -629,7 +629,7 @@ _kern_write(int fd, off_t pos, const void *buffer, size_t bufferSize) if (result < 0) return errno; } - + // read ssize_t bytesWritten = haiku_host_platform_write(descriptor->fd, buffer, bufferSize); @@ -706,10 +706,10 @@ _kern_read_stat(int fd, const char *path, bool traverseLink, Descriptor *descriptor = get_descriptor(fd); if (!descriptor) return B_FILE_ERROR; - + return descriptor->GetStat(traverseLink, st); } - + return B_OK; } @@ -734,7 +734,7 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, return errno; isSymlink = S_ISLNK(tmpStat.st_mode); - + } else { Descriptor *descriptor = get_descriptor(fd); if (!descriptor) @@ -743,17 +743,17 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, if (FileDescriptor *fileFD = dynamic_cast(descriptor)) { realFD = fileFD->fd; - + } else if (dynamic_cast(descriptor)) { error = get_path(fd, NULL, realPath); if (error != B_OK) return error; - + } else if (SymlinkDescriptor *linkFD = dynamic_cast(descriptor)) { realPath = linkFD->path; isSymlink = true; - + } else return B_FILE_ERROR; } @@ -762,23 +762,23 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, // available functions traverse symlinks. if (isSymlink && !traverseLink) return B_ERROR; - + if (realFD >= 0) { if (statMask & B_STAT_MODE) { if (fchmod(realFD, st->st_mode) < 0) return errno; } - + if (statMask & B_STAT_UID) { if (fchown(realFD, st->st_uid, (gid_t)-1) < 0) return errno; } - + if (statMask & B_STAT_GID) { if (fchown(realFD, (uid_t)-1, st->st_gid) < 0) return errno; } - + if (statMask & B_STAT_SIZE) { if (ftruncate(realFD, st->st_size) < 0) return errno; @@ -790,25 +790,25 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, | B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) { return B_ERROR; } - + return 0; - + } else { if (statMask & B_STAT_MODE) { if (chmod(realPath.c_str(), st->st_mode) < 0) return errno; } - + if (statMask & B_STAT_UID) { if (chown(realPath.c_str(), st->st_uid, (gid_t)-1) < 0) return errno; } - + if (statMask & B_STAT_GID) { if (chown(realPath.c_str(), (uid_t)-1, st->st_gid) < 0) return errno; } - + if (statMask & B_STAT_SIZE) { if (truncate(realPath.c_str(), st->st_size) < 0) return errno; @@ -822,18 +822,18 @@ _kern_write_stat(int fd, const char *path, bool traverseLink, if (stat(realPath.c_str(), &oldStat) < 0) return errno; } - + utimbuf buffer; buffer.actime = (statMask & B_STAT_ACCESS_TIME) ? st->st_atime : oldStat.st_atime; buffer.modtime = (statMask & B_STAT_MODIFICATION_TIME) ? st->st_mtime : oldStat.st_mtime; if (utime(realPath.c_str(), &buffer) < 0) return errno; } - - // not supported + + // not supported if (statMask & (B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME)) return B_ERROR; - } + } return B_OK; } @@ -878,7 +878,7 @@ _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize) if (*_bufferSize > 0) { if ((size_t)bytesRead == *_bufferSize) bytesRead--; - + buffer[bytesRead] = '\0'; } @@ -918,7 +918,7 @@ _kern_rename(int oldDir, const char *oldPath, int newDir, const char *newPath) error = get_path(newDir, newPath, realNewPath); if (error != B_OK) return error; - + // rename if (rename(realOldPath.c_str(), realNewPath.c_str()) < 0) return errno; @@ -954,7 +954,7 @@ read_pos(int fd, off_t pos, void *buffer, size_t bufferSize) off_t result = lseek(fd, pos, SEEK_SET); if (result < 0) return errno; - + // read ssize_t bytesRead = haiku_host_platform_read(fd, buffer, bufferSize); if (bytesRead < 0) { @@ -969,12 +969,25 @@ read_pos(int fd, off_t pos, void *buffer, size_t bufferSize) ssize_t write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize) { + // If this is an attribute descriptor, let it do the job. + AttributeDescriptor* descriptor + = dynamic_cast(get_descriptor(fd)); + if (descriptor != NULL) { + status_t error = descriptor->Write(pos, buffer, bufferSize); + if (error != B_OK) { + errno = error; + return -1; + } + + return 0; + } + // seek off_t result = lseek(fd, pos, SEEK_SET); if (result < 0) return errno; - // read + // write ssize_t bytesWritten = haiku_host_platform_write(fd, buffer, bufferSize); if (bytesWritten < 0) { errno = bytesWritten; @@ -992,7 +1005,7 @@ readv_pos(int fd, off_t pos, const struct iovec *vec, size_t count) off_t result = lseek(fd, pos, SEEK_SET); if (result < 0) return errno; - + // read ssize_t bytesRead = haiku_host_platform_readv(fd, vec, count); if (bytesRead < 0) { @@ -1011,7 +1024,7 @@ writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count) off_t result = lseek(fd, pos, SEEK_SET); if (result < 0) return errno; - + // read ssize_t bytesWritten = haiku_host_platform_writev(fd, vec, count); if (bytesWritten < 0) { diff --git a/src/build/libroot/fs_attr_generic.cpp b/src/build/libroot/fs_attr_generic.cpp index e42eb5eb12..ee18e65bb8 100644 --- a/src/build/libroot/fs_attr_generic.cpp +++ b/src/build/libroot/fs_attr_generic.cpp @@ -33,7 +33,7 @@ init_attribute_dir_base_dir() if (initialized) return initError; - + // stat the dir struct stat st; initError = B_OK; @@ -44,7 +44,7 @@ init_attribute_dir_base_dir() "directory base directory exists, but is no directory!\n"); initError = B_FILE_ERROR; } - + } else { // doesn't exist yet: create it if (mkdir(sAttributeDirBasePath, S_IRWXU | S_IRWXG | S_IRWXO) < 0) @@ -68,7 +68,7 @@ escape_attr_name(const char *name) escapedName += "__"; else escapedName += *name; - + name++; } @@ -84,7 +84,7 @@ deescape_attr_name(const char *name) return "___"; } name++; - + string deescapedName; while (*name != '\0') { if (*name == '_') { @@ -100,11 +100,11 @@ deescape_attr_name(const char *name) } } else deescapedName += *name; - + name++; } - return deescapedName; + return deescapedName; } // get_attribute_dir_path @@ -179,7 +179,7 @@ get_attribute_path(NodeRef ref, const char *path, int fd, errno = error; return -1; } - + // construct the attribute path attrPath = get_attribute_dir_path(ref) + '/'; string attrName(escape_attr_name(attribute)); @@ -206,7 +206,7 @@ get_attribute_path_virtual_fd(int fd, const char *attribute, string &attrPath, // (i.e. system) file descriptor, which is just as well. string path; bool pathValid = (get_path(fd, NULL, path) == B_OK); - + // get the attribute path return get_attribute_path(ref, (pathValid ? path.c_str() : NULL), (pathValid ? -1 : fd), attribute, attrPath, typePath); @@ -269,7 +269,7 @@ fs_fopen_attr_dir(int fd) // (i.e. system) file descriptor, which is just as well. string path; bool pathValid = (get_path(fd, NULL, path) == B_OK); - + // get the attribute path return open_attr_dir(NodeRef(st), (pathValid ? path.c_str() : NULL), (pathValid ? -1 : fd)); @@ -292,8 +292,8 @@ fs_read_attr_dir(DIR *dir) entry = readdir(dir); if (!entry) return NULL; - - // ignore administrative entries; the + + // ignore administrative entries; the if (entry->d_name[0] == '_') { string attrName = deescape_attr_name(entry->d_name); strcpy(entry->d_name, attrName.c_str()); @@ -309,15 +309,15 @@ fs_rewind_attr_dir(DIR *dir) rewinddir(dir); } -// fs_open_attr +// fs_fopen_attr int -fs_open_attr(int fd, const char *attribute, uint32 type, int openMode) +fs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode) { if (!attribute) { errno = B_BAD_VALUE; return -1; } - + // get the attribute path string attrPath; string typePath; @@ -344,7 +344,7 @@ fs_open_attr(int fd, const char *attribute, uint32 type, int openMode) // write the type into the file if (write(typeFD, &type, sizeof(type)) < 0) error = errno; - + close(typeFD); } else @@ -355,10 +355,10 @@ fs_open_attr(int fd, const char *attribute, uint32 type, int openMode) if (typeFD > 0) { unlink(typePath.c_str()); } - + close(attrFD); unlink(attrPath.c_str()); - + errno = error; return -1; } @@ -395,7 +395,7 @@ fs_read_attr(int fd, const char *attribute, uint32 type, off_t pos, errno = error; return -1; } - + return bytesRead; } @@ -421,7 +421,7 @@ fs_write_attr(int fd, const char *attribute, uint32 type, off_t pos, errno = error; return -1; } - + return bytesWritten; } @@ -433,7 +433,7 @@ fs_remove_attr(int fd, const char *attribute) errno = B_BAD_VALUE; return -1; } - + // get the attribute path string attrPath; string typePath; @@ -446,9 +446,9 @@ fs_remove_attr(int fd, const char *attribute) // remove the attribute if (unlink(attrPath.c_str()) < 0) return -1; - + unlink(typePath.c_str()); - + return B_OK; } @@ -474,7 +474,7 @@ fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo) struct stat st; if (lstat(attrPath.c_str(), &st) < 0) return -1; - + attrInfo->size = st.st_size; // now open the attribute type file and read the attribute's type @@ -496,7 +496,7 @@ fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo) return -1; } - return 0; + return 0; } @@ -524,14 +524,14 @@ _kern_open_attr_dir(int fd, const char *path) if (error != B_OK) return error; } - + // open the attr dir DIR *dir = open_attr_dir(ref, (path ? realPath.c_str() : NULL), (path ? -1 : fd)); if (!dir) return errno; - // create descriptor + // create descriptor AttrDirDescriptor *descriptor = new AttrDirDescriptor(dir, ref); return add_descriptor(descriptor); } @@ -571,7 +571,7 @@ _kern_rename_attr(int fromFile, const char *fromName, int toFile, return error; } - + return B_OK; } diff --git a/src/build/libroot/fs_attr_untyped.cpp b/src/build/libroot/fs_attr_untyped.cpp index 0a3472f012..6276dcff26 100644 --- a/src/build/libroot/fs_attr_untyped.cpp +++ b/src/build/libroot/fs_attr_untyped.cpp @@ -452,22 +452,50 @@ fs_rewind_attr_dir(DIR *dir) attrDir->RewindDir(); } -// fs_open_attr +// fs_fopen_attr int -fs_open_attr(int fd, const char *attribute, uint32 type, int openMode) +fs_fopen_attr(int fd, const char *attribute, uint32 type, int openMode) { - // not supported ATM - errno = B_BAD_VALUE; - return -1; + if (fd < 0) { + errno = B_BAD_VALUE; + return -1; + } + + AttributeDescriptor* descriptor = new(std::nothrow) AttributeDescriptor(fd, + attribute, type, openMode); + if (descriptor == NULL) { + errno = B_NO_MEMORY; + return -1; + } + + status_t error = descriptor->Init(); + if (error != B_OK) { + delete descriptor; + errno = error; + return -1; + } + + int attributeFD = add_descriptor(descriptor); + if (attributeFD < 0) { + delete descriptor; + errno = B_NO_MEMORY; + return -1; + } + + return attributeFD; } // fs_close_attr int fs_close_attr(int fd) { - // not supported ATM - errno = B_BAD_VALUE; - return -1; + status_t error = delete_descriptor(fd); + if (error != 0) { + errno = error; + return -1; + } + + return 0; } // fs_read_attr diff --git a/src/build/libroot/fs_descriptors.cpp b/src/build/libroot/fs_descriptors.cpp index d4599e289d..2bf311dca6 100644 --- a/src/build/libroot/fs_descriptors.cpp +++ b/src/build/libroot/fs_descriptors.cpp @@ -11,7 +11,9 @@ #include +#include #include +#include #include #include @@ -250,6 +252,151 @@ SymlinkDescriptor::GetPath(string& path) const } +// #pragma mark - AttributeDescriptor + + +AttributeDescriptor::AttributeDescriptor(int fileFD, const char* attribute, + uint32 type, int openMode) + : + fFileFD(dup(fileFD)), + fType(type), + fOpenMode(openMode), + fData(NULL), + fDataSize(0) + +{ + strlcpy(fAttribute, attribute, sizeof(fAttribute)); +} + + +AttributeDescriptor::~AttributeDescriptor() +{ + Close(); +} + + +status_t +AttributeDescriptor::Init() +{ + if (fFileFD < 0) + return B_IO_ERROR; + + // stat the attribute + attr_info info; + if (fs_stat_attr(fFileFD, fAttribute, &info) < 0) { + if (errno == B_ENTRY_NOT_FOUND) { + if ((fOpenMode & O_CREAT) == 0) + return errno; + + // create the attribute + if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0) + return errno; + return B_OK; + } + return errno; + } + + if ((fOpenMode & O_TRUNC) == 0) { + // truncate the attribute + if (fs_write_attr(fFileFD, fAttribute, fType, 0, NULL, 0) < 0) + return errno; + return B_OK; + } + + // we have to read in the attribute data + if (info.size == 0) + return B_OK; + + fData = (uint8*)malloc(info.size); + if (fData == NULL) + return B_NO_MEMORY; + + fDataSize = info.size; + + ssize_t bytesRead = fs_read_attr(fFileFD, fAttribute, fType, 0, fData, + fDataSize); + if (bytesRead < 0) + return errno; + if ((size_t)bytesRead != fDataSize) + return B_IO_ERROR; + + return B_OK; +} + + +status_t +AttributeDescriptor::Write(off_t offset, const void* buffer, size_t bufferSize) +{ + if (offset < 0) + return B_BAD_VALUE; + + if ((fOpenMode & O_ACCMODE) != O_WRONLY + && (fOpenMode & O_ACCMODE) != O_RDWR) { + return B_NOT_ALLOWED; + } + + // we may need to resize the buffer + size_t minSize = (size_t)offset + bufferSize; + if (minSize > fDataSize) { + uint8* data = (uint8*)realloc(fData, minSize); + if (data == NULL) + return B_NO_MEMORY; + + if ((size_t)offset > fDataSize) + memset(data + offset, 0, offset - fDataSize); + + fData = data; + fDataSize = minSize; + } + + // copy the data and write all of it + if (bufferSize == 0) + return B_OK; + + memcpy((uint8*)fData + offset, buffer, bufferSize); + + ssize_t bytesWritten = fs_write_attr(fFileFD, fAttribute, fType, 0, + fData, fDataSize); + if (bytesWritten < 0) + return errno; + if ((size_t)bytesWritten != fDataSize) + return B_IO_ERROR; + + return B_OK; +} + + +status_t +AttributeDescriptor::Close() +{ + if (fFileFD < 0) + return B_BAD_VALUE; + + close(fFileFD); + fFileFD = -1; + + free(fData); + fData = NULL; + fDataSize = 0; + + return B_OK; +} + + +status_t +AttributeDescriptor::Dup(Descriptor*& clone) +{ + return B_NOT_SUPPORTED; +} + + +status_t +AttributeDescriptor::GetStat(bool traverseLink, struct stat* st) +{ + return B_NOT_SUPPORTED; +} + + // #pragma mark - AttrDirDescriptor diff --git a/src/build/libroot/fs_descriptors.h b/src/build/libroot/fs_descriptors.h index 56dcb4c1d6..608f6f6fc6 100644 --- a/src/build/libroot/fs_descriptors.h +++ b/src/build/libroot/fs_descriptors.h @@ -5,6 +5,7 @@ #include +#include #include #include "NodeRef.h" @@ -35,7 +36,7 @@ struct Descriptor { struct FileDescriptor : Descriptor { FileDescriptor(int fd); virtual ~FileDescriptor(); - + virtual status_t Close(); virtual status_t Dup(Descriptor *&clone); virtual status_t GetStat(bool traverseLink, struct stat *st); @@ -50,7 +51,7 @@ struct DirectoryDescriptor : Descriptor { DirectoryDescriptor(DIR *dir, const NodeRef &ref); virtual ~DirectoryDescriptor(); - + virtual status_t Close(); virtual status_t Dup(Descriptor *&clone); virtual status_t GetStat(bool traverseLink, struct stat *st); @@ -71,12 +72,41 @@ struct SymlinkDescriptor : Descriptor { virtual status_t GetPath(string& path) const; }; +// AttributeDescriptor +struct AttributeDescriptor : Descriptor { + AttributeDescriptor(int fileFD, + const char* attribute, uint32 type, + int openMode); + virtual ~AttributeDescriptor(); + + status_t Init(); + status_t Write(off_t offset, const void* buffer, + size_t bufferSize); + + int FileFD() const { return fFileFD; } + const char* Attribute() const { return fAttribute; } + uint32 Type() const { return fType; } + int OpenMode() const { return fOpenMode; } + + virtual status_t Close(); + virtual status_t Dup(Descriptor*& clone); + virtual status_t GetStat(bool traverseLink, struct stat* st); + +private: + int fFileFD; + char fAttribute[B_ATTR_NAME_LENGTH]; + uint32 fType; + int fOpenMode; + uint8* fData; + size_t fDataSize; +}; + // AttrDirDescriptor struct AttrDirDescriptor : DirectoryDescriptor { AttrDirDescriptor(DIR *dir, const NodeRef &ref); virtual ~AttrDirDescriptor(); - + virtual status_t Close(); virtual status_t Dup(Descriptor *&clone); virtual status_t GetStat(bool traverseLink, struct stat *st); From a7bcad8194c7e9b18c91195172324689fc841259 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 20:28:14 +0200 Subject: [PATCH 0012/1170] Updated to current Haiku version --- headers/build/os/kernel/fs_attr.h | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/headers/build/os/kernel/fs_attr.h b/headers/build/os/kernel/fs_attr.h index 10c2d084a4..3f24985f05 100644 --- a/headers/build/os/kernel/fs_attr.h +++ b/headers/build/os/kernel/fs_attr.h @@ -1,7 +1,7 @@ -/* File System attributes -** -** Distributed under the terms of the OpenBeOS License. -*/ +/* + * Copyright 2002-2009, Haiku Inc. All Rights Reserved. + * Distributed under the terms of the MIT License. + */ #ifndef _FS_ATTR_H #define _FS_ATTR_H @@ -20,15 +20,18 @@ typedef struct attr_info { extern "C" { #endif -extern ssize_t fs_read_attr(int fd, const char *attribute, uint32 type, off_t pos, void *buffer, size_t readBytes); -extern ssize_t fs_write_attr(int fd, const char *attribute, uint32 type, off_t pos, const void *buffer, size_t readBytes); +extern ssize_t fs_read_attr(int fd, const char *attribute, uint32 type, + off_t pos, void *buffer, size_t readBytes); +extern ssize_t fs_write_attr(int fd, const char *attribute, uint32 type, + off_t pos, const void *buffer, size_t readBytes); extern int fs_remove_attr(int fd, const char *attribute); -extern int fs_stat_attr(int fd, const char *attribute, struct attr_info *attrInfo); +extern int fs_stat_attr(int fd, const char *attribute, + struct attr_info *attrInfo); -// ToDo: the following three functions are not part of the R5 API, and -// are only preliminary - they may change or be removed at any point -//extern int fs_open_attr(const char *path, const char *attribute, uint32 type, int openMode); -extern int fs_open_attr(int fd, const char *attribute, uint32 type, int openMode); +extern int fs_open_attr(const char *path, const char *attribute, + uint32 type, int openMode); +extern int fs_fopen_attr(int fd, const char *attribute, uint32 type, + int openMode); extern int fs_close_attr(int fd); extern DIR *fs_open_attr_dir(const char *path); From 14c34be2e11541af33f8a19f620c66a28810acef Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 20:30:06 +0200 Subject: [PATCH 0013/1170] Fixed host build issues/warnings --- src/kits/package/RepositoryInfo.cpp | 1 + src/kits/package/hpkg/DataReader.cpp | 2 +- src/kits/package/hpkg/PackageWriterImpl.cpp | 4 ++++ src/kits/package/hpkg/ReaderImplBase.cpp | 3 ++- 4 files changed, 8 insertions(+), 2 deletions(-) diff --git a/src/kits/package/RepositoryInfo.cpp b/src/kits/package/RepositoryInfo.cpp index c675632fcc..5878dfcccd 100644 --- a/src/kits/package/RepositoryInfo.cpp +++ b/src/kits/package/RepositoryInfo.cpp @@ -15,6 +15,7 @@ #include #include +#include #include diff --git a/src/kits/package/hpkg/DataReader.cpp b/src/kits/package/hpkg/DataReader.cpp index d5a2819ec2..2d2999c54d 100644 --- a/src/kits/package/hpkg/DataReader.cpp +++ b/src/kits/package/hpkg/DataReader.cpp @@ -90,7 +90,7 @@ BBufferDataReader::ReadData(off_t offset, void* buffer, size_t size) if (offset < 0) return B_BAD_VALUE; - if (size > fSize || offset > fSize - size) + if (size > fSize || offset > (off_t)fSize - (off_t)size) return B_ERROR; memcpy(buffer, (const uint8*)fData + offset, size); diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp index f2f277648d..3761d9e043 100644 --- a/src/kits/package/hpkg/PackageWriterImpl.cpp +++ b/src/kits/package/hpkg/PackageWriterImpl.cpp @@ -671,7 +671,11 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName, } _AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_ATIME, uint32(st.st_atime)); _AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_MTIME, uint32(st.st_mtime)); +#ifdef __HAIKU__ _AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_CRTIME, uint32(st.st_crtime)); +#else + _AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_CRTIME, uint32(st.st_mtime)); +#endif // TODO: File user/group! // add file data/symlink path diff --git a/src/kits/package/hpkg/ReaderImplBase.cpp b/src/kits/package/hpkg/ReaderImplBase.cpp index 9affaecd80..d7cb3e95af 100644 --- a/src/kits/package/hpkg/ReaderImplBase.cpp +++ b/src/kits/package/hpkg/ReaderImplBase.cpp @@ -964,7 +964,8 @@ ReaderImplBase::ReadCompressedBuffer(const SectionInfo& section) while (compressedSize > 0) { // read compressed buffer - size_t toRead = std::min(compressedSize, fScratchBufferSize); + size_t toRead = std::min((size_t)compressedSize, + fScratchBufferSize); error = ReadBuffer(offset, fScratchBuffer, toRead); if (error != B_OK) return error; From d451f7a329dc00c2bee7e7bd88ed24249dacd83c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 20:34:55 +0200 Subject: [PATCH 0014/1170] Added several APIs to libbe_build/libshared_build --- headers/build/os/support/Autolock.h | 1 + headers/build/private/kernel/util/DoublyLinkedList.h | 1 + headers/build/private/kernel/util/OpenHashTable.h | 1 + headers/build/private/kernel/util/SinglyLinkedList.h | 1 + headers/build/private/libroot/directories.h | 1 + headers/build/private/shared/HashMap.h | 1 + headers/build/private/shared/HashSet.h | 1 + headers/build/private/shared/HashString.h | 1 + headers/build/private/shared/NaturalCompare.h | 1 + headers/build/private/shared/SHA256.h | 1 + src/build/libbe/storage/Jamfile | 1 + src/build/libbe/support/Jamfile | 1 + src/build/libshared/Jamfile | 11 ++++++----- 13 files changed, 18 insertions(+), 5 deletions(-) create mode 100644 headers/build/os/support/Autolock.h create mode 100644 headers/build/private/kernel/util/DoublyLinkedList.h create mode 100644 headers/build/private/kernel/util/OpenHashTable.h create mode 100644 headers/build/private/kernel/util/SinglyLinkedList.h create mode 100644 headers/build/private/libroot/directories.h create mode 100644 headers/build/private/shared/HashMap.h create mode 100644 headers/build/private/shared/HashSet.h create mode 100644 headers/build/private/shared/HashString.h create mode 100644 headers/build/private/shared/NaturalCompare.h create mode 100644 headers/build/private/shared/SHA256.h diff --git a/headers/build/os/support/Autolock.h b/headers/build/os/support/Autolock.h new file mode 100644 index 0000000000..a99f1a26e0 --- /dev/null +++ b/headers/build/os/support/Autolock.h @@ -0,0 +1 @@ +#include <../os/support/Autolock.h> diff --git a/headers/build/private/kernel/util/DoublyLinkedList.h b/headers/build/private/kernel/util/DoublyLinkedList.h new file mode 100644 index 0000000000..850f514831 --- /dev/null +++ b/headers/build/private/kernel/util/DoublyLinkedList.h @@ -0,0 +1 @@ +#include <../private/kernel/util/DoublyLinkedList.h> diff --git a/headers/build/private/kernel/util/OpenHashTable.h b/headers/build/private/kernel/util/OpenHashTable.h new file mode 100644 index 0000000000..eadd683dc8 --- /dev/null +++ b/headers/build/private/kernel/util/OpenHashTable.h @@ -0,0 +1 @@ +#include <../private/kernel/util/OpenHashTable.h> diff --git a/headers/build/private/kernel/util/SinglyLinkedList.h b/headers/build/private/kernel/util/SinglyLinkedList.h new file mode 100644 index 0000000000..2b735deae1 --- /dev/null +++ b/headers/build/private/kernel/util/SinglyLinkedList.h @@ -0,0 +1 @@ +#include <../private/kernel/util/SinglyLinkedList.h> diff --git a/headers/build/private/libroot/directories.h b/headers/build/private/libroot/directories.h new file mode 100644 index 0000000000..f5eb3aff4e --- /dev/null +++ b/headers/build/private/libroot/directories.h @@ -0,0 +1 @@ +#include <../private/libroot/directories.h> diff --git a/headers/build/private/shared/HashMap.h b/headers/build/private/shared/HashMap.h new file mode 100644 index 0000000000..83e7dd1751 --- /dev/null +++ b/headers/build/private/shared/HashMap.h @@ -0,0 +1 @@ +#include <../private/shared/HashMap.h> diff --git a/headers/build/private/shared/HashSet.h b/headers/build/private/shared/HashSet.h new file mode 100644 index 0000000000..992e1b50a3 --- /dev/null +++ b/headers/build/private/shared/HashSet.h @@ -0,0 +1 @@ +#include <../private/shared/HashSet.h> diff --git a/headers/build/private/shared/HashString.h b/headers/build/private/shared/HashString.h new file mode 100644 index 0000000000..c652f45b9e --- /dev/null +++ b/headers/build/private/shared/HashString.h @@ -0,0 +1 @@ +#include <../private/shared/HashString.h> diff --git a/headers/build/private/shared/NaturalCompare.h b/headers/build/private/shared/NaturalCompare.h new file mode 100644 index 0000000000..740309c264 --- /dev/null +++ b/headers/build/private/shared/NaturalCompare.h @@ -0,0 +1 @@ +#include <../private/shared/NaturalCompare.h> diff --git a/headers/build/private/shared/SHA256.h b/headers/build/private/shared/SHA256.h new file mode 100644 index 0000000000..7108b49269 --- /dev/null +++ b/headers/build/private/shared/SHA256.h @@ -0,0 +1 @@ +#include <../private/shared/SHA256.h> diff --git a/src/build/libbe/storage/Jamfile b/src/build/libbe/storage/Jamfile index 3e8ee30246..cb2b27c53e 100644 --- a/src/build/libbe/storage/Jamfile +++ b/src/build/libbe/storage/Jamfile @@ -16,6 +16,7 @@ BuildPlatformMergeObjectPIC storage_kit.o : EntryList.cpp File.cpp FileIO.cpp + FindDirectory.cpp Mime.cpp MimeType.cpp Node.cpp diff --git a/src/build/libbe/support/Jamfile b/src/build/libbe/support/Jamfile index 0ee19c09b8..3f7e07e499 100644 --- a/src/build/libbe/support/Jamfile +++ b/src/build/libbe/support/Jamfile @@ -14,5 +14,6 @@ BuildPlatformMergeObjectPIC support_kit.o : Flattenable.cpp List.cpp Locker.cpp + PointerList.cpp String.cpp ; diff --git a/src/build/libshared/Jamfile b/src/build/libshared/Jamfile index ead0a41fde..94e74a5d9d 100644 --- a/src/build/libshared/Jamfile +++ b/src/build/libshared/Jamfile @@ -5,9 +5,10 @@ USES_BE_API on libshared_build.a = true ; UseHeaders [ FDirName $(HAIKU_TOP) headers build ] : true ; UsePrivateBuildHeaders shared ; -BuildPlatformStaticLibrary libshared_build.a : - Keymap.cpp -; +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits shared ] ; -SEARCH on [ FGristFiles Keymap.cpp ] - = [ FDirName $(HAIKU_TOP) src kits shared ] ; +BuildPlatformStaticLibraryPIC libshared_build.a : + Keymap.cpp + NaturalCompare.cpp + SHA256.cpp +; From 0ee9bc97d0a35cb34ab5321c34997f20172a870b Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 20:37:32 +0200 Subject: [PATCH 0015/1170] Build libpackage for the build platform --- .../build/os/package/AddRepositoryRequest.h | 1 + headers/build/os/package/Attributes.h | 1 + .../build/os/package/BlockBufferCacheNoLock.h | 1 + headers/build/os/package/Context.h | 1 + .../build/os/package/DropRepositoryRequest.h | 1 + headers/build/os/package/Job.h | 1 + .../build/os/package/PackageArchitecture.h | 1 + headers/build/os/package/PackageFlags.h | 1 + headers/build/os/package/PackageInfo.h | 1 + .../build/os/package/PackageInfoAttributes.h | 1 + headers/build/os/package/PackageResolvable.h | 1 + .../os/package/PackageResolvableExpression.h | 1 + .../os/package/PackageResolvableOperator.h | 1 + .../build/os/package/PackageResolvableType.h | 1 + headers/build/os/package/PackageRoster.h | 1 + headers/build/os/package/PackageVersion.h | 1 + .../os/package/RefreshRepositoryRequest.h | 1 + headers/build/os/package/RepositoryCache.h | 1 + headers/build/os/package/RepositoryConfig.h | 1 + headers/build/os/package/RepositoryInfo.h | 1 + headers/build/os/package/Request.h | 1 + .../build/os/package/hpkg/BlockBufferCache.h | 1 + headers/build/os/package/hpkg/BufferCache.h | 1 + headers/build/os/package/hpkg/DataOutput.h | 1 + headers/build/os/package/hpkg/DataReader.h | 1 + headers/build/os/package/hpkg/ErrorOutput.h | 1 + headers/build/os/package/hpkg/HPKGDefs.h | 1 + .../os/package/hpkg/PackageAttributeValue.h | 1 + .../os/package/hpkg/PackageContentHandler.h | 1 + headers/build/os/package/hpkg/PackageData.h | 1 + .../build/os/package/hpkg/PackageDataReader.h | 1 + headers/build/os/package/hpkg/PackageEntry.h | 1 + .../os/package/hpkg/PackageEntryAttribute.h | 1 + .../package/hpkg/PackageInfoAttributeValue.h | 1 + headers/build/os/package/hpkg/PackageReader.h | 1 + headers/build/os/package/hpkg/PackageWriter.h | 1 + .../package/hpkg/RepositoryContentHandler.h | 1 + .../build/os/package/hpkg/RepositoryReader.h | 1 + .../build/os/package/hpkg/RepositoryWriter.h | 1 + .../package/ActivateRepositoryCacheJob.h | 1 + .../package/ActivateRepositoryConfigJob.h | 1 + .../build/private/package/ChecksumAccessors.h | 1 + headers/build/private/package/FetchFileJob.h | 1 + .../build/private/package/HashableString.h | 1 + headers/build/private/package/JobQueue.h | 1 + .../private/package/RemoveRepositoryJob.h | 1 + .../build/private/package/TempfileManager.h | 1 + .../private/package/ValidateChecksumJob.h | 1 + .../package/hpkg/BlockBufferCacheImpl.h | 1 + .../build/private/package/hpkg/CachedBuffer.h | 1 + .../private/package/hpkg/HPKGDefsPrivate.h | 1 + .../private/package/hpkg/PackageReaderImpl.h | 1 + .../private/package/hpkg/PackageWriterImpl.h | 1 + .../private/package/hpkg/ReaderImplBase.h | 1 + .../package/hpkg/RepositoryReaderImpl.h | 1 + .../package/hpkg/RepositoryWriterImpl.h | 1 + headers/build/private/package/hpkg/Stacker.h | 1 + headers/build/private/package/hpkg/Strings.h | 1 + .../private/package/hpkg/WriterImplBase.h | 1 + .../package/hpkg/ZlibCompressionBase.h | 1 + .../private/package/hpkg/ZlibCompressor.h | 1 + .../private/package/hpkg/ZlibDecompressor.h | 1 + src/build/Jamfile | 1 + src/build/libpackage/Jamfile | 74 +++++++++++++++++++ 64 files changed, 137 insertions(+) create mode 100644 headers/build/os/package/AddRepositoryRequest.h create mode 100644 headers/build/os/package/Attributes.h create mode 100644 headers/build/os/package/BlockBufferCacheNoLock.h create mode 100644 headers/build/os/package/Context.h create mode 100644 headers/build/os/package/DropRepositoryRequest.h create mode 100644 headers/build/os/package/Job.h create mode 100644 headers/build/os/package/PackageArchitecture.h create mode 100644 headers/build/os/package/PackageFlags.h create mode 100644 headers/build/os/package/PackageInfo.h create mode 100644 headers/build/os/package/PackageInfoAttributes.h create mode 100644 headers/build/os/package/PackageResolvable.h create mode 100644 headers/build/os/package/PackageResolvableExpression.h create mode 100644 headers/build/os/package/PackageResolvableOperator.h create mode 100644 headers/build/os/package/PackageResolvableType.h create mode 100644 headers/build/os/package/PackageRoster.h create mode 100644 headers/build/os/package/PackageVersion.h create mode 100644 headers/build/os/package/RefreshRepositoryRequest.h create mode 100644 headers/build/os/package/RepositoryCache.h create mode 100644 headers/build/os/package/RepositoryConfig.h create mode 100644 headers/build/os/package/RepositoryInfo.h create mode 100644 headers/build/os/package/Request.h create mode 100644 headers/build/os/package/hpkg/BlockBufferCache.h create mode 100644 headers/build/os/package/hpkg/BufferCache.h create mode 100644 headers/build/os/package/hpkg/DataOutput.h create mode 100644 headers/build/os/package/hpkg/DataReader.h create mode 100644 headers/build/os/package/hpkg/ErrorOutput.h create mode 100644 headers/build/os/package/hpkg/HPKGDefs.h create mode 100644 headers/build/os/package/hpkg/PackageAttributeValue.h create mode 100644 headers/build/os/package/hpkg/PackageContentHandler.h create mode 100644 headers/build/os/package/hpkg/PackageData.h create mode 100644 headers/build/os/package/hpkg/PackageDataReader.h create mode 100644 headers/build/os/package/hpkg/PackageEntry.h create mode 100644 headers/build/os/package/hpkg/PackageEntryAttribute.h create mode 100644 headers/build/os/package/hpkg/PackageInfoAttributeValue.h create mode 100644 headers/build/os/package/hpkg/PackageReader.h create mode 100644 headers/build/os/package/hpkg/PackageWriter.h create mode 100644 headers/build/os/package/hpkg/RepositoryContentHandler.h create mode 100644 headers/build/os/package/hpkg/RepositoryReader.h create mode 100644 headers/build/os/package/hpkg/RepositoryWriter.h create mode 100644 headers/build/private/package/ActivateRepositoryCacheJob.h create mode 100644 headers/build/private/package/ActivateRepositoryConfigJob.h create mode 100644 headers/build/private/package/ChecksumAccessors.h create mode 100644 headers/build/private/package/FetchFileJob.h create mode 100644 headers/build/private/package/HashableString.h create mode 100644 headers/build/private/package/JobQueue.h create mode 100644 headers/build/private/package/RemoveRepositoryJob.h create mode 100644 headers/build/private/package/TempfileManager.h create mode 100644 headers/build/private/package/ValidateChecksumJob.h create mode 100644 headers/build/private/package/hpkg/BlockBufferCacheImpl.h create mode 100644 headers/build/private/package/hpkg/CachedBuffer.h create mode 100644 headers/build/private/package/hpkg/HPKGDefsPrivate.h create mode 100644 headers/build/private/package/hpkg/PackageReaderImpl.h create mode 100644 headers/build/private/package/hpkg/PackageWriterImpl.h create mode 100644 headers/build/private/package/hpkg/ReaderImplBase.h create mode 100644 headers/build/private/package/hpkg/RepositoryReaderImpl.h create mode 100644 headers/build/private/package/hpkg/RepositoryWriterImpl.h create mode 100644 headers/build/private/package/hpkg/Stacker.h create mode 100644 headers/build/private/package/hpkg/Strings.h create mode 100644 headers/build/private/package/hpkg/WriterImplBase.h create mode 100644 headers/build/private/package/hpkg/ZlibCompressionBase.h create mode 100644 headers/build/private/package/hpkg/ZlibCompressor.h create mode 100644 headers/build/private/package/hpkg/ZlibDecompressor.h create mode 100644 src/build/libpackage/Jamfile diff --git a/headers/build/os/package/AddRepositoryRequest.h b/headers/build/os/package/AddRepositoryRequest.h new file mode 100644 index 0000000000..56723bb559 --- /dev/null +++ b/headers/build/os/package/AddRepositoryRequest.h @@ -0,0 +1 @@ +#include <../os/package/AddRepositoryRequest.h> diff --git a/headers/build/os/package/Attributes.h b/headers/build/os/package/Attributes.h new file mode 100644 index 0000000000..146e52a2ef --- /dev/null +++ b/headers/build/os/package/Attributes.h @@ -0,0 +1 @@ +#include <../os/package/Attributes.h> diff --git a/headers/build/os/package/BlockBufferCacheNoLock.h b/headers/build/os/package/BlockBufferCacheNoLock.h new file mode 100644 index 0000000000..49b1d8e8cb --- /dev/null +++ b/headers/build/os/package/BlockBufferCacheNoLock.h @@ -0,0 +1 @@ +#include <../os/package/BlockBufferCacheNoLock.h> diff --git a/headers/build/os/package/Context.h b/headers/build/os/package/Context.h new file mode 100644 index 0000000000..1a5fcfa314 --- /dev/null +++ b/headers/build/os/package/Context.h @@ -0,0 +1 @@ +#include <../os/package/Context.h> diff --git a/headers/build/os/package/DropRepositoryRequest.h b/headers/build/os/package/DropRepositoryRequest.h new file mode 100644 index 0000000000..9139cbcfe7 --- /dev/null +++ b/headers/build/os/package/DropRepositoryRequest.h @@ -0,0 +1 @@ +#include <../os/package/DropRepositoryRequest.h> diff --git a/headers/build/os/package/Job.h b/headers/build/os/package/Job.h new file mode 100644 index 0000000000..86ba503535 --- /dev/null +++ b/headers/build/os/package/Job.h @@ -0,0 +1 @@ +#include <../os/package/Job.h> diff --git a/headers/build/os/package/PackageArchitecture.h b/headers/build/os/package/PackageArchitecture.h new file mode 100644 index 0000000000..81e9c22b0e --- /dev/null +++ b/headers/build/os/package/PackageArchitecture.h @@ -0,0 +1 @@ +#include <../os/package/PackageArchitecture.h> diff --git a/headers/build/os/package/PackageFlags.h b/headers/build/os/package/PackageFlags.h new file mode 100644 index 0000000000..f1a2a212ec --- /dev/null +++ b/headers/build/os/package/PackageFlags.h @@ -0,0 +1 @@ +#include <../os/package/PackageFlags.h> diff --git a/headers/build/os/package/PackageInfo.h b/headers/build/os/package/PackageInfo.h new file mode 100644 index 0000000000..2e36b95489 --- /dev/null +++ b/headers/build/os/package/PackageInfo.h @@ -0,0 +1 @@ +#include <../os/package/PackageInfo.h> diff --git a/headers/build/os/package/PackageInfoAttributes.h b/headers/build/os/package/PackageInfoAttributes.h new file mode 100644 index 0000000000..87b5e805e5 --- /dev/null +++ b/headers/build/os/package/PackageInfoAttributes.h @@ -0,0 +1 @@ +#include <../os/package/PackageInfoAttributes.h> diff --git a/headers/build/os/package/PackageResolvable.h b/headers/build/os/package/PackageResolvable.h new file mode 100644 index 0000000000..c6822604ab --- /dev/null +++ b/headers/build/os/package/PackageResolvable.h @@ -0,0 +1 @@ +#include <../os/package/PackageResolvable.h> diff --git a/headers/build/os/package/PackageResolvableExpression.h b/headers/build/os/package/PackageResolvableExpression.h new file mode 100644 index 0000000000..15593f0653 --- /dev/null +++ b/headers/build/os/package/PackageResolvableExpression.h @@ -0,0 +1 @@ +#include <../os/package/PackageResolvableExpression.h> diff --git a/headers/build/os/package/PackageResolvableOperator.h b/headers/build/os/package/PackageResolvableOperator.h new file mode 100644 index 0000000000..1f9e2b3d39 --- /dev/null +++ b/headers/build/os/package/PackageResolvableOperator.h @@ -0,0 +1 @@ +#include <../os/package/PackageResolvableOperator.h> diff --git a/headers/build/os/package/PackageResolvableType.h b/headers/build/os/package/PackageResolvableType.h new file mode 100644 index 0000000000..ad79a67740 --- /dev/null +++ b/headers/build/os/package/PackageResolvableType.h @@ -0,0 +1 @@ +#include <../os/package/PackageResolvableType.h> diff --git a/headers/build/os/package/PackageRoster.h b/headers/build/os/package/PackageRoster.h new file mode 100644 index 0000000000..79cff28009 --- /dev/null +++ b/headers/build/os/package/PackageRoster.h @@ -0,0 +1 @@ +#include <../os/package/PackageRoster.h> diff --git a/headers/build/os/package/PackageVersion.h b/headers/build/os/package/PackageVersion.h new file mode 100644 index 0000000000..6e070c4199 --- /dev/null +++ b/headers/build/os/package/PackageVersion.h @@ -0,0 +1 @@ +#include <../os/package/PackageVersion.h> diff --git a/headers/build/os/package/RefreshRepositoryRequest.h b/headers/build/os/package/RefreshRepositoryRequest.h new file mode 100644 index 0000000000..2451a9608c --- /dev/null +++ b/headers/build/os/package/RefreshRepositoryRequest.h @@ -0,0 +1 @@ +#include <../os/package/RefreshRepositoryRequest.h> diff --git a/headers/build/os/package/RepositoryCache.h b/headers/build/os/package/RepositoryCache.h new file mode 100644 index 0000000000..8d2dfc6bfa --- /dev/null +++ b/headers/build/os/package/RepositoryCache.h @@ -0,0 +1 @@ +#include <../os/package/RepositoryCache.h> diff --git a/headers/build/os/package/RepositoryConfig.h b/headers/build/os/package/RepositoryConfig.h new file mode 100644 index 0000000000..2b4fab3eda --- /dev/null +++ b/headers/build/os/package/RepositoryConfig.h @@ -0,0 +1 @@ +#include <../os/package/RepositoryConfig.h> diff --git a/headers/build/os/package/RepositoryInfo.h b/headers/build/os/package/RepositoryInfo.h new file mode 100644 index 0000000000..9da30b1f3d --- /dev/null +++ b/headers/build/os/package/RepositoryInfo.h @@ -0,0 +1 @@ +#include <../os/package/RepositoryInfo.h> diff --git a/headers/build/os/package/Request.h b/headers/build/os/package/Request.h new file mode 100644 index 0000000000..64c0d3e685 --- /dev/null +++ b/headers/build/os/package/Request.h @@ -0,0 +1 @@ +#include <../os/package/Request.h> diff --git a/headers/build/os/package/hpkg/BlockBufferCache.h b/headers/build/os/package/hpkg/BlockBufferCache.h new file mode 100644 index 0000000000..53f9dd5837 --- /dev/null +++ b/headers/build/os/package/hpkg/BlockBufferCache.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/BlockBufferCache.h> diff --git a/headers/build/os/package/hpkg/BufferCache.h b/headers/build/os/package/hpkg/BufferCache.h new file mode 100644 index 0000000000..c82ddeb0fa --- /dev/null +++ b/headers/build/os/package/hpkg/BufferCache.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/BufferCache.h> diff --git a/headers/build/os/package/hpkg/DataOutput.h b/headers/build/os/package/hpkg/DataOutput.h new file mode 100644 index 0000000000..565ceb4b01 --- /dev/null +++ b/headers/build/os/package/hpkg/DataOutput.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/DataOutput.h> diff --git a/headers/build/os/package/hpkg/DataReader.h b/headers/build/os/package/hpkg/DataReader.h new file mode 100644 index 0000000000..990d5a4e65 --- /dev/null +++ b/headers/build/os/package/hpkg/DataReader.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/DataReader.h> diff --git a/headers/build/os/package/hpkg/ErrorOutput.h b/headers/build/os/package/hpkg/ErrorOutput.h new file mode 100644 index 0000000000..98acf41881 --- /dev/null +++ b/headers/build/os/package/hpkg/ErrorOutput.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/ErrorOutput.h> diff --git a/headers/build/os/package/hpkg/HPKGDefs.h b/headers/build/os/package/hpkg/HPKGDefs.h new file mode 100644 index 0000000000..d09dc8c961 --- /dev/null +++ b/headers/build/os/package/hpkg/HPKGDefs.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/HPKGDefs.h> diff --git a/headers/build/os/package/hpkg/PackageAttributeValue.h b/headers/build/os/package/hpkg/PackageAttributeValue.h new file mode 100644 index 0000000000..300cb48c00 --- /dev/null +++ b/headers/build/os/package/hpkg/PackageAttributeValue.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/PackageAttributeValue.h> diff --git a/headers/build/os/package/hpkg/PackageContentHandler.h b/headers/build/os/package/hpkg/PackageContentHandler.h new file mode 100644 index 0000000000..b190f04751 --- /dev/null +++ b/headers/build/os/package/hpkg/PackageContentHandler.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/PackageContentHandler.h> diff --git a/headers/build/os/package/hpkg/PackageData.h b/headers/build/os/package/hpkg/PackageData.h new file mode 100644 index 0000000000..46c1b2d2bf --- /dev/null +++ b/headers/build/os/package/hpkg/PackageData.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/PackageData.h> diff --git a/headers/build/os/package/hpkg/PackageDataReader.h b/headers/build/os/package/hpkg/PackageDataReader.h new file mode 100644 index 0000000000..2101da8685 --- /dev/null +++ b/headers/build/os/package/hpkg/PackageDataReader.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/PackageDataReader.h> diff --git a/headers/build/os/package/hpkg/PackageEntry.h b/headers/build/os/package/hpkg/PackageEntry.h new file mode 100644 index 0000000000..8be30cb47c --- /dev/null +++ b/headers/build/os/package/hpkg/PackageEntry.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/PackageEntry.h> diff --git a/headers/build/os/package/hpkg/PackageEntryAttribute.h b/headers/build/os/package/hpkg/PackageEntryAttribute.h new file mode 100644 index 0000000000..9bcb6fab20 --- /dev/null +++ b/headers/build/os/package/hpkg/PackageEntryAttribute.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/PackageEntryAttribute.h> diff --git a/headers/build/os/package/hpkg/PackageInfoAttributeValue.h b/headers/build/os/package/hpkg/PackageInfoAttributeValue.h new file mode 100644 index 0000000000..b11a160228 --- /dev/null +++ b/headers/build/os/package/hpkg/PackageInfoAttributeValue.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/PackageInfoAttributeValue.h> diff --git a/headers/build/os/package/hpkg/PackageReader.h b/headers/build/os/package/hpkg/PackageReader.h new file mode 100644 index 0000000000..95f84dfc86 --- /dev/null +++ b/headers/build/os/package/hpkg/PackageReader.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/PackageReader.h> diff --git a/headers/build/os/package/hpkg/PackageWriter.h b/headers/build/os/package/hpkg/PackageWriter.h new file mode 100644 index 0000000000..0ce1391b03 --- /dev/null +++ b/headers/build/os/package/hpkg/PackageWriter.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/PackageWriter.h> diff --git a/headers/build/os/package/hpkg/RepositoryContentHandler.h b/headers/build/os/package/hpkg/RepositoryContentHandler.h new file mode 100644 index 0000000000..d98041c433 --- /dev/null +++ b/headers/build/os/package/hpkg/RepositoryContentHandler.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/RepositoryContentHandler.h> diff --git a/headers/build/os/package/hpkg/RepositoryReader.h b/headers/build/os/package/hpkg/RepositoryReader.h new file mode 100644 index 0000000000..0a75992cba --- /dev/null +++ b/headers/build/os/package/hpkg/RepositoryReader.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/RepositoryReader.h> diff --git a/headers/build/os/package/hpkg/RepositoryWriter.h b/headers/build/os/package/hpkg/RepositoryWriter.h new file mode 100644 index 0000000000..d73b7bdc43 --- /dev/null +++ b/headers/build/os/package/hpkg/RepositoryWriter.h @@ -0,0 +1 @@ +#include <../os/package/hpkg/RepositoryWriter.h> diff --git a/headers/build/private/package/ActivateRepositoryCacheJob.h b/headers/build/private/package/ActivateRepositoryCacheJob.h new file mode 100644 index 0000000000..5c335ceafd --- /dev/null +++ b/headers/build/private/package/ActivateRepositoryCacheJob.h @@ -0,0 +1 @@ +#include <../private/package/ActivateRepositoryCacheJob.h> diff --git a/headers/build/private/package/ActivateRepositoryConfigJob.h b/headers/build/private/package/ActivateRepositoryConfigJob.h new file mode 100644 index 0000000000..c5ea6f43b2 --- /dev/null +++ b/headers/build/private/package/ActivateRepositoryConfigJob.h @@ -0,0 +1 @@ +#include <../private/package/ActivateRepositoryConfigJob.h> diff --git a/headers/build/private/package/ChecksumAccessors.h b/headers/build/private/package/ChecksumAccessors.h new file mode 100644 index 0000000000..55ef76f47a --- /dev/null +++ b/headers/build/private/package/ChecksumAccessors.h @@ -0,0 +1 @@ +#include <../private/package/ChecksumAccessors.h> diff --git a/headers/build/private/package/FetchFileJob.h b/headers/build/private/package/FetchFileJob.h new file mode 100644 index 0000000000..aad2b1f2a4 --- /dev/null +++ b/headers/build/private/package/FetchFileJob.h @@ -0,0 +1 @@ +#include <../private/package/FetchFileJob.h> diff --git a/headers/build/private/package/HashableString.h b/headers/build/private/package/HashableString.h new file mode 100644 index 0000000000..fe9a7e7ec1 --- /dev/null +++ b/headers/build/private/package/HashableString.h @@ -0,0 +1 @@ +#include <../private/package/HashableString.h> diff --git a/headers/build/private/package/JobQueue.h b/headers/build/private/package/JobQueue.h new file mode 100644 index 0000000000..0a19a4dff0 --- /dev/null +++ b/headers/build/private/package/JobQueue.h @@ -0,0 +1 @@ +#include <../private/package/JobQueue.h> diff --git a/headers/build/private/package/RemoveRepositoryJob.h b/headers/build/private/package/RemoveRepositoryJob.h new file mode 100644 index 0000000000..2eafbab27a --- /dev/null +++ b/headers/build/private/package/RemoveRepositoryJob.h @@ -0,0 +1 @@ +#include <../private/package/RemoveRepositoryJob.h> diff --git a/headers/build/private/package/TempfileManager.h b/headers/build/private/package/TempfileManager.h new file mode 100644 index 0000000000..7b93744a87 --- /dev/null +++ b/headers/build/private/package/TempfileManager.h @@ -0,0 +1 @@ +#include <../private/package/TempfileManager.h> diff --git a/headers/build/private/package/ValidateChecksumJob.h b/headers/build/private/package/ValidateChecksumJob.h new file mode 100644 index 0000000000..f62ee6d852 --- /dev/null +++ b/headers/build/private/package/ValidateChecksumJob.h @@ -0,0 +1 @@ +#include <../private/package/ValidateChecksumJob.h> diff --git a/headers/build/private/package/hpkg/BlockBufferCacheImpl.h b/headers/build/private/package/hpkg/BlockBufferCacheImpl.h new file mode 100644 index 0000000000..7e6db95545 --- /dev/null +++ b/headers/build/private/package/hpkg/BlockBufferCacheImpl.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/BlockBufferCacheImpl.h> diff --git a/headers/build/private/package/hpkg/CachedBuffer.h b/headers/build/private/package/hpkg/CachedBuffer.h new file mode 100644 index 0000000000..f7a5c1dde6 --- /dev/null +++ b/headers/build/private/package/hpkg/CachedBuffer.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/CachedBuffer.h> diff --git a/headers/build/private/package/hpkg/HPKGDefsPrivate.h b/headers/build/private/package/hpkg/HPKGDefsPrivate.h new file mode 100644 index 0000000000..1661da6221 --- /dev/null +++ b/headers/build/private/package/hpkg/HPKGDefsPrivate.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/HPKGDefsPrivate.h> diff --git a/headers/build/private/package/hpkg/PackageReaderImpl.h b/headers/build/private/package/hpkg/PackageReaderImpl.h new file mode 100644 index 0000000000..1e3e939462 --- /dev/null +++ b/headers/build/private/package/hpkg/PackageReaderImpl.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/PackageReaderImpl.h> diff --git a/headers/build/private/package/hpkg/PackageWriterImpl.h b/headers/build/private/package/hpkg/PackageWriterImpl.h new file mode 100644 index 0000000000..8235c3a7fc --- /dev/null +++ b/headers/build/private/package/hpkg/PackageWriterImpl.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/PackageWriterImpl.h> diff --git a/headers/build/private/package/hpkg/ReaderImplBase.h b/headers/build/private/package/hpkg/ReaderImplBase.h new file mode 100644 index 0000000000..82b54a1c19 --- /dev/null +++ b/headers/build/private/package/hpkg/ReaderImplBase.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/ReaderImplBase.h> diff --git a/headers/build/private/package/hpkg/RepositoryReaderImpl.h b/headers/build/private/package/hpkg/RepositoryReaderImpl.h new file mode 100644 index 0000000000..8161822279 --- /dev/null +++ b/headers/build/private/package/hpkg/RepositoryReaderImpl.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/RepositoryReaderImpl.h> diff --git a/headers/build/private/package/hpkg/RepositoryWriterImpl.h b/headers/build/private/package/hpkg/RepositoryWriterImpl.h new file mode 100644 index 0000000000..ac0dcf29c3 --- /dev/null +++ b/headers/build/private/package/hpkg/RepositoryWriterImpl.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/RepositoryWriterImpl.h> diff --git a/headers/build/private/package/hpkg/Stacker.h b/headers/build/private/package/hpkg/Stacker.h new file mode 100644 index 0000000000..72cc4e3f30 --- /dev/null +++ b/headers/build/private/package/hpkg/Stacker.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/Stacker.h> diff --git a/headers/build/private/package/hpkg/Strings.h b/headers/build/private/package/hpkg/Strings.h new file mode 100644 index 0000000000..7f66cc1cfa --- /dev/null +++ b/headers/build/private/package/hpkg/Strings.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/Strings.h> diff --git a/headers/build/private/package/hpkg/WriterImplBase.h b/headers/build/private/package/hpkg/WriterImplBase.h new file mode 100644 index 0000000000..0eeb9413d7 --- /dev/null +++ b/headers/build/private/package/hpkg/WriterImplBase.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/WriterImplBase.h> diff --git a/headers/build/private/package/hpkg/ZlibCompressionBase.h b/headers/build/private/package/hpkg/ZlibCompressionBase.h new file mode 100644 index 0000000000..052cfd0bde --- /dev/null +++ b/headers/build/private/package/hpkg/ZlibCompressionBase.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/ZlibCompressionBase.h> diff --git a/headers/build/private/package/hpkg/ZlibCompressor.h b/headers/build/private/package/hpkg/ZlibCompressor.h new file mode 100644 index 0000000000..53865202e7 --- /dev/null +++ b/headers/build/private/package/hpkg/ZlibCompressor.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/ZlibCompressor.h> diff --git a/headers/build/private/package/hpkg/ZlibDecompressor.h b/headers/build/private/package/hpkg/ZlibDecompressor.h new file mode 100644 index 0000000000..698aca62f9 --- /dev/null +++ b/headers/build/private/package/hpkg/ZlibDecompressor.h @@ -0,0 +1 @@ +#include <../private/package/hpkg/ZlibDecompressor.h> diff --git a/src/build/Jamfile b/src/build/Jamfile index d74a12e801..17634b03de 100644 --- a/src/build/Jamfile +++ b/src/build/Jamfile @@ -2,5 +2,6 @@ SubDir HAIKU_TOP src build ; SubInclude HAIKU_TOP src build libbe ; SubInclude HAIKU_TOP src build libhaikucompat ; +SubInclude HAIKU_TOP src build libpackage ; SubInclude HAIKU_TOP src build libroot ; SubInclude HAIKU_TOP src build libshared ; diff --git a/src/build/libpackage/Jamfile b/src/build/libpackage/Jamfile new file mode 100644 index 0000000000..90308092f4 --- /dev/null +++ b/src/build/libpackage/Jamfile @@ -0,0 +1,74 @@ +SubDir HAIKU_TOP src build libpackage ; + +UsePrivateBuildHeaders kernel shared ; + +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package ] ; +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ; + +USES_BE_API on libpackage_build.so = true ; + +HPKG_SOURCES = + BlockBufferCache.cpp + BlockBufferCacheImpl.cpp + BufferCache.cpp + CachedBuffer.cpp + DataOutput.cpp + DataReader.cpp + ErrorOutput.cpp + PackageContentHandler.cpp + PackageData.cpp + PackageDataReader.cpp + PackageEntry.cpp + PackageEntryAttribute.cpp + PackageReader.cpp + PackageReaderImpl.cpp + PackageWriter.cpp + PackageWriterImpl.cpp + ReaderImplBase.cpp + RepositoryReader.cpp + RepositoryReaderImpl.cpp + RepositoryWriter.cpp + RepositoryWriterImpl.cpp + Strings.cpp + WriterImplBase.cpp + + # compression + ZlibCompressionBase.cpp + ZlibCompressor.cpp + ZlibDecompressor.cpp +; + +# locate the library +MakeLocate libpackage_build.so : $(HOST_BUILD_COMPATIBILITY_LIB_DIR) ; + +BuildPlatformSharedLibrary libpackage_build.so + : + ActivateRepositoryCacheJob.cpp + ActivateRepositoryConfigJob.cpp + AddRepositoryRequest.cpp + Attributes.cpp + BlockBufferCacheNoLock.cpp + ChecksumAccessors.cpp + Context.cpp + DropRepositoryRequest.cpp + FetchFileJob.cpp + Job.cpp + JobQueue.cpp + PackageInfo.cpp + PackageResolvable.cpp + PackageResolvableExpression.cpp + PackageRoster.cpp + PackageVersion.cpp + RefreshRepositoryRequest.cpp + RemoveRepositoryJob.cpp + RepositoryCache.cpp + RepositoryConfig.cpp + RepositoryInfo.cpp + Request.cpp + TempfileManager.cpp + ValidateChecksumJob.cpp + + $(HPKG_SOURCES) + : + libshared_build.a $(HOST_LIBBE) z $(HOST_LIBSTDC++) +; From 922e7ba1f3228e6f28db69b0ded8f86eb32dea17 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 20:38:09 +0200 Subject: [PATCH 0016/1170] Build the package tool for the build platform --- src/tools/Jamfile | 1 + src/tools/package/Jamfile | 19 +++++++++++++++++++ 2 files changed, 20 insertions(+) create mode 100644 src/tools/package/Jamfile diff --git a/src/tools/Jamfile b/src/tools/Jamfile index b6421f3fa4..566e373242 100644 --- a/src/tools/Jamfile +++ b/src/tools/Jamfile @@ -135,6 +135,7 @@ SubInclude HAIKU_TOP src tools hack_coff ; SubInclude HAIKU_TOP src tools keymap ; SubInclude HAIKU_TOP src tools locale ; SubInclude HAIKU_TOP src tools makebootable ; +SubInclude HAIKU_TOP src tools package ; SubInclude HAIKU_TOP src tools rc ; SubInclude HAIKU_TOP src tools remote_disk_server ; SubInclude HAIKU_TOP src tools resattr ; diff --git a/src/tools/package/Jamfile b/src/tools/package/Jamfile new file mode 100644 index 0000000000..9667f53dc8 --- /dev/null +++ b/src/tools/package/Jamfile @@ -0,0 +1,19 @@ +SubDir HAIKU_TOP src tools package ; + +UsePrivateBuildHeaders shared ; + +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src bin package ] ; + +USES_BE_API on package = true ; + +BuildPlatformMain package : + command_create.cpp + command_dump.cpp + command_extract.cpp + command_list.cpp + package.cpp + StandardErrorOutput.cpp + + : + libpackage_build.so $(HOST_LIBBE) $(HOST_LIBSUPC++) +; From efec892e2b29fa5ef58c89a261567ef819fc2c28 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 22:28:39 +0200 Subject: [PATCH 0017/1170] Added .gitignore --- .gitignore | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000000..f853046791 --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +generated* +build/jam/UserBuildConfig + From a1cada9784bda2472dcfc4c546bd0840b4ceeb4d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 22:53:44 +0200 Subject: [PATCH 0018/1170] Fix x86_64 BuildConfig issues * Resolve TODO: HOST_GCC_BASE_FLAGS should not be included in HOST_LDFLAGS. Enable adding "-fno-strict-aliasing -fno-tree-vrp" accordingly. * Fix handling of HOST_PLATFORM_IS_64_BIT and HAIKU_HOST_USE_32BIT: The former does now state whether the platform is effectively treated as 64 bit platform, i.e. it actually is 64 bit and the 32 bit mode is not enforced. HAIKU_HOST_USE_32BIT is now only set when the platform is actually 64 bit, but 32 bit mode is enforced. --- build/jam/BuildSetup | 41 +++++++++++++++++++++++++---------------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index 1830a6b8a5..c962832147 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -127,13 +127,10 @@ if $(HAIKU_USE_GCC_PIPE) = 1 { if $(HAIKU_GCC_VERSION[1]) >= 3 { HAIKU_GCC_BASE_FLAGS += -fno-strict-aliasing -fno-tree-vrp ; } -# TODO: With Haiku as the host platform, this does not appear to be set up -# correctly, at least when compiling the libbe_test target platform. When -# enabling the lines below, these flags suddenly appear as link flags passed -# to ld as well. -#if $(HOST_GCC_VERSION[1]) >= 3 { -# HOST_GCC_BASE_FLAGS += -fno-strict-aliasing -fno-tree-vrp ; -#} + +if $(HOST_GCC_VERSION[1]) >= 3 { + HOST_GCC_BASE_FLAGS += -fno-strict-aliasing -fno-tree-vrp ; +} # override gcc 2.95.3's header directory -- strictly necessary only when using # the BeOS native compiler (since its headers are incompatible), but it doesn't @@ -529,14 +526,26 @@ HAIKU_BUILD_DESCRIPTION ?= "Unknown Build" ; # analyze the host gcc machine spec to find out about 64-bitness HOST_PLATFORM_IS_64_BIT = ; +switch $(HOST_GCC_MACHINE) { + case amd64-* : HOST_PLATFORM_IS_64_BIT = 1 ; + case i686-apple-darwin10 : HOST_PLATFORM_IS_64_BIT = 1 ; + case x86_64-* : HOST_PLATFORM_IS_64_BIT = 1 ; +} + +# If HAIKU_HOST_USE_32BIT is set, add the required gcc base flag (the LD flag +# is set later), or, if the architecture isn't actually 64 bit, clear +# HAIKU_HOST_USE_32BIT. +# Afterwards HOST_PLATFORM_IS_64_BIT will indicate whether the architecture is +# effectively (i.e. when using the compiler/linker flags) 64 bit and +# HAIKU_HOST_USE_32BIT will be set, iff the architecture is really 64 bit and +# 32 bit mode was requested. if $(HAIKU_HOST_USE_32BIT) = 1 { - # enable GCC -m32 option - HOST_GCC_BASE_FLAGS = -m32 ; -} else { - switch $(HOST_GCC_MACHINE) { - case amd64-* : HOST_PLATFORM_IS_64_BIT = 1 ; - case i686-apple-darwin10 : HOST_PLATFORM_IS_64_BIT = 1 ; - case x86_64-* : HOST_PLATFORM_IS_64_BIT = 1 ; + if $(HOST_PLATFORM_IS_64_BIT) { + # enable GCC -m32 option + HOST_GCC_BASE_FLAGS = -m32 ; + HOST_PLATFORM_IS_64_BIT = ; + } else { + HAIKU_HOST_USE_32BIT = 0 ; } } @@ -550,7 +559,7 @@ HOST_RANLIB ?= $(RANLIB) ; HOST_CPPFLAGS ?= $(CPPFLAGS) ; HOST_CCFLAGS ?= $(HOST_GCC_BASE_FLAGS) $(CCFLAGS) ; HOST_C++FLAGS ?= $(HOST_GCC_BASE_FLAGS) $(C++FLAGS) ; -HOST_LDFLAGS ?= $(HOST_GCC_BASE_FLAGS) $(LDFLAGS) ; +HOST_LDFLAGS ?= $(LDFLAGS) ; HOST_LINKFLAGS ?= $(HOST_GCC_BASE_FLAGS) $(LINKFLAGS) ; HOST_DEFINES ?= $(DEFINES) ; HOST_HDRS ?= $(HDRS) ; @@ -682,7 +691,7 @@ for level in $(HAIKU_DEBUG_LEVELS[2-]) { } # ld flags -if $(HOST_ARCH) = x86_64 && $(HAIKU_HOST_USE_32BIT) = 1 { +if $(HAIKU_HOST_USE_32BIT) = 1 { HOST_LDFLAGS += -melf_i386 ; } From abd5edcb5f72f105fbbf7575750c8daa7b8f29de Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 16 Jun 2011 22:58:22 +0200 Subject: [PATCH 0019/1170] libroot_build: fix error.ccp build Since USES_BE_API is set by default on all libroot_build sources, the error.cpp was broken, since it wouldn't be exempt from the error mapping. Define the BUILDING_HAIKU_ERROR_MAPPER for it directly in the Jamfile, now. --- src/build/libroot/Jamfile | 14 ++++++++------ src/build/libroot/errors.cpp | 7 ++++--- 2 files changed, 12 insertions(+), 9 deletions(-) diff --git a/src/build/libroot/Jamfile b/src/build/libroot/Jamfile index 767c6371f3..a739eedd42 100644 --- a/src/build/libroot/Jamfile +++ b/src/build/libroot/Jamfile @@ -18,17 +18,19 @@ UsePrivateBuildHeaders kernel libroot ; SubDirCcFlags $(defines) ; SubDirC++Flags $(defines) ; - local defines = [ FDefines + defines = [ FDefines HAIKU_BUILD_GENERATED_DIRECTORY="\\\"$(HAIKU_OUTPUT_DIR)\\\"" ] ; - SubDirC++Flags $(defines) ; ObjectC++Flags find_directory.cpp : $(defines) ; + + defines = [ FDefines BUILDING_HAIKU_ERROR_MAPPER=1 ] ; + ObjectC++Flags errors.cpp : $(defines) ; + + defines = [ FDefines KMESSAGE_CONTAINER_ONLY=1 ] ; + ObjectC++Flags KMessage.cpp : $(defines) ; + } - -DEFINES += KMESSAGE_CONTAINER_ONLY ; -ObjectC++Flags KMessage.cpp : $(HOST_BE_API_C++FLAGS) ; - # locate the library MakeLocate libroot_build.so : $(HOST_BUILD_COMPATIBILITY_LIB_DIR) ; diff --git a/src/build/libroot/errors.cpp b/src/build/libroot/errors.cpp index e02d5dafbf..e0691a963d 100644 --- a/src/build/libroot/errors.cpp +++ b/src/build/libroot/errors.cpp @@ -1,8 +1,9 @@ +/* + * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ -#define BUILDING_HAIKU_ERROR_MAPPER 1 -#include - #include #include From e272fb5dec8ed35de0ad8303f675c4d9602777c8 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 17 Jun 2011 14:53:57 +0200 Subject: [PATCH 0020/1170] package: attribute iteration, license dir PackageWriterImpl: * Iterate through attributes using fs_read_attr_dir() instead of readdir(). Makes it work correctly on the build platform. * On the build platform look up the system licenses in their source directory rather than based on find_directory(). --- src/build/libpackage/Jamfile | 11 +++++++++++ src/kits/package/hpkg/PackageWriterImpl.cpp | 8 ++++++-- 2 files changed, 17 insertions(+), 2 deletions(-) diff --git a/src/build/libpackage/Jamfile b/src/build/libpackage/Jamfile index 90308092f4..e0ef43b062 100644 --- a/src/build/libpackage/Jamfile +++ b/src/build/libpackage/Jamfile @@ -7,6 +7,17 @@ SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ; USES_BE_API on libpackage_build.so = true ; + +{ + # The package writer needs to know where the license files are located. + local dataDir = [ FDirName $(HAIKU_TOP) data system data ] ; + local defines = [ FDefines + HAIKU_BUILD_SYSTEM_DATA_DIRECTORY="\\\"$(dataDir)\\\"" + ] ; + ObjectC++Flags PackageWriterImpl.cpp : $(defines) ; +} + + HPKG_SOURCES = BlockBufferCache.cpp BlockBufferCacheImpl.cpp diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp index 3761d9e043..7504796618 100644 --- a/src/kits/package/hpkg/PackageWriterImpl.cpp +++ b/src/kits/package/hpkg/PackageWriterImpl.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Copyright 2011, Oliver Tappe * Distributed under the terms of the MIT License. */ @@ -336,7 +336,11 @@ PackageWriterImpl::_CheckLicenses() { BPath systemLicensePath; status_t result +#ifdef HAIKU_TARGET_PLATFORM_HAIKU = find_directory(B_SYSTEM_DATA_DIRECTORY, &systemLicensePath); +#else + = systemLicensePath.SetTo(HAIKU_BUILD_SYSTEM_DATA_DIRECTORY); +#endif if (result != B_OK) { fListener->PrintError("unable to find system data path!\n"); return result; @@ -706,7 +710,7 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName, if (DIR* attrDir = fs_fopen_attr_dir(fd)) { CObjectDeleter attrDirCloser(attrDir, fs_close_attr_dir); - while (dirent* entry = readdir(attrDir)) { + while (dirent* entry = fs_read_attr_dir(attrDir)) { attr_info attrInfo; if (fs_stat_attr(fd, entry->d_name, &attrInfo) < 0) { fListener->PrintError( From 9e3bdfb0efe4133551f924157f2df541afbf6a4c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 17 Jun 2011 14:56:35 +0200 Subject: [PATCH 0021/1170] Generalize some image rules Pulled generalized *ToContainer versions out of several *ToHaikuImage rules. --- build/jam/ImageRules | 111 ++++++++++++++++++++++++++++--------------- 1 file changed, 74 insertions(+), 37 deletions(-) diff --git a/build/jam/ImageRules b/build/jam/ImageRules index ebbe599f12..df2b81a0c9 100644 --- a/build/jam/ImageRules +++ b/build/jam/ImageRules @@ -283,6 +283,38 @@ rule CopyDirectoryToContainer container : directoryTokens : sourceDirectory DIRECTORIES_TO_INSTALL on $(directory) += $(targetDir) ; } + +rule AddHeaderDirectoryToContainer container : dirTokens : dirName + : alwaysUpdate +{ + # AddHeaderDirectoryToContainer : : [ ] + # : ; + + CopyDirectoryToContainer $(container) : system develop headers + : [ FDirName $(HAIKU_TOP) headers $(dirTokens) ] + : $(dirName) : -x .svn : $(alwaysUpdate) ; +} + + +rule AddWifiFirmwareToContainer container : driver : package : archive : extract +{ + # AddWifiFirmwareToContainer : : : + # : + + # complete location to wifi firmware archive + local firmwareArchive = [ FDirName + $(HAIKU_TOP) data system data firmware $(driver) $(archive) ] ; + + local dirTokens = system data firmware $(driver) ; + if $(extract) = true || $(extract) = 1 { + ExtractArchiveToContainer $(container) : $(dirTokens) + : $(firmwareArchive) : $(package) ; + } else { + AddFilesToContainer $(container) : $(dirTokens) : $(firmwareArchive) ; + } +} + + rule ExtractArchiveToContainer container : directoryTokens : archiveFile : extractedSubDir { @@ -345,7 +377,8 @@ rule AddBootModuleSymlinksToContainer container : targets # AddBootModuleSymlinksToContainer : ; # - # If the image shall only be updated, we don't add any symlinks. + # If the container shall only be updated, we don't add any symlinks. + if [ on $(container) return $(HAIKU_CONTAINER_UPDATE_ONLY) ] && ! [ IncludeAllTargetsInContainer $(container) ] { return ; @@ -376,6 +409,29 @@ rule AddBootModuleSymlinksToContainer container : targets } +rule AddLibrariesToContainer container : directory : libs +{ + # AddLibrariesToContainer : : + # + # Installs libraries with the appropriate links into the container. + # + + local lib ; + for lib in $(libs) { + local abiVersion = [ on $(lib) return $(HAIKU_LIB_ABI_VERSION) ] ; + if $(abiVersion) { + local abiVersionedLib = $(lib).$(abiVersion) ; + AddFilesToContainer $(container) : $(directory) : $(lib) + : $(abiVersionedLib) ; + AddSymlinkToContainer $(container) : $(directory) + : $(abiVersionedLib) : $(lib) ; + } else { + AddFilesToContainer $(container) : $(directory) : $(lib) ; + } + } +} + + rule CreateContainerMakeDirectoriesScript container : script { MakeLocate $(script) : $(HAIKU_OUTPUT_DIR) ; @@ -709,26 +765,16 @@ rule AddHeaderDirectoryToHaikuImage dirTokens : dirName : alwaysUpdate # AddHeaderDirectoryToHaikuImage : [ ] # : ; - CopyDirectoryToHaikuImage system develop headers - : [ FDirName $(HAIKU_TOP) headers $(dirTokens) ] - : $(dirName) : -x .svn : $(alwaysUpdate) ; + AddHeaderDirectoryToContainer $(HAIKU_IMAGE_CONTAINER_NAME) : $(dirTokens) + : $(dirName) : $(alwaysUpdate) ; } rule AddWifiFirmwareToHaikuImage driver : package : archive : extract { - #AddWifiFirmwareToHaikuImage : : : + # AddWifiFirmwareToHaikuImage : : : - # complete location to wifi firmware archive - local firmwareArchive = [ FDirName - $(HAIKU_TOP) data system data firmware $(driver) $(archive) ] ; - - local dirTokens = system data firmware $(driver) ; - if $(extract) = true || $(extract) = 1 { - ExtractArchiveToHaikuImage $(dirTokens) : $(firmwareArchive) : - : $(package) ; - } else { - AddFilesToHaikuImage $(dirTokens) : $(firmwareArchive) ; - } + AddWifiFirmwareToHaikuImage $(HAIKU_IMAGE_CONTAINER_NAME) : $(driver) + : $(package) : $(archive) : $(extract) ; } rule ExtractArchiveToHaikuImage dirTokens : archiveFile : alwaysUpdate @@ -978,6 +1024,18 @@ rule AddLicenseToHaikuImage file : name : searchPath } +rule AddLibrariesToHaikuImage directory : libs +{ + # AddLibraryToHaikuImage : + # + # Installs libraries with the appropriate links onto the image. + # + + AddLibrariesToContainer $(HAIKU_IMAGE_CONTAINER_NAME) : $(directory) + : $(libs) ; +} + + rule CreateHaikuImageMakeDirectoriesScript script { CreateContainerMakeDirectoriesScript $(HAIKU_IMAGE_CONTAINER_NAME) @@ -1133,27 +1191,6 @@ actions BuildNetBootArchive1 } -rule AddLibrariesToHaikuImage directory : libs -{ - # AddLibraryToHaikuImage : - # - # Installs libraries with the appropriate links onto the image. - # - - local lib ; - for lib in $(libs) { - local abiVersion = [ on $(lib) return $(HAIKU_LIB_ABI_VERSION) ] ; - if $(abiVersion) { - local abiVersionedLib = $(lib).$(abiVersion) ; - AddFilesToHaikuImage $(directory) : $(lib) : $(abiVersionedLib) ; - AddSymlinkToHaikuImage $(directory) : $(abiVersionedLib) : $(lib) ; - } else { - AddFilesToHaikuImage $(directory) : $(lib) ; - } - } -} - - #pragma mark - Floppy Boot Archive rules From 355b8ba7553a58e35406084ea875f8f3f519a12b Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 17 Jun 2011 15:11:16 +0200 Subject: [PATCH 0022/1170] Build a system Haiku package * Create rules (build/jam/PackageRules) and a script, build_haiku_package, to build hpkg files. * Move all rule invocations that copy files and created symlinks and directories in the "system" directory from HaikuImage to HaikuPackages, which creates a package "haiku.hpkg". * build_haiku_image: Comment out adding the copyrights info to AboutSystem for the moment. --- build/jam/BuildSetup | 7 + build/jam/HaikuImage | 331 +--------------------------- build/jam/HaikuPackages | 345 ++++++++++++++++++++++++++++++ build/jam/PackageRules | 182 +++++++++++++++- build/scripts/build_haiku_image | 20 +- build/scripts/build_haiku_package | 66 ++++++ src/data/package_infos/haiku | 19 ++ 7 files changed, 631 insertions(+), 339 deletions(-) create mode 100644 build/jam/HaikuPackages create mode 100755 build/scripts/build_haiku_package create mode 100644 src/data/package_infos/haiku diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index c962832147..b416107de4 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -1139,6 +1139,13 @@ HAIKU_TMP_DIR ?= [ FDirName $(HAIKU_OUTPUT_DIR) tmp ] ; HAIKU_PACKAGE_DIR ?= [ FDirName $(HAIKU_OUTPUT_DIR) packages ] ; HAIKU_PACKAGE_OBJECT_DIR ?= [ FDirName $(HAIKU_OBJECT_DIR) packages ] ; + # TODO: Remove those together with the obsolete package rules! + +HAIKU_PACKAGES_DIR = [ FDirName $(TARGET_COMMON_DEBUG_OBJECT_DIR) + packages ] ; +HAIKU_PACKAGES_BUILD_DIR = [ FDirName $(TARGET_COMMON_DEBUG_OBJECT_DIR) + packages_build ] ; +HAIKU_PACKAGE_INFOS_DIR = [ FDirName $(HAIKU_TOP) src data package_infos ] ; TARGET_TEST_DIR ?= [ FDirName $(HAIKU_TEST_DIR) $(TARGET_PLATFORM) ] ; diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 6ab711fe84..26d1af4565 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -194,153 +194,9 @@ SYSTEM_ADD_ONS_BUS_MANAGERS = $(ATA_ONLY)ata pci $(X86_ONLY)ps2 $(X86_ONLY)isa SYSTEM_ADD_ONS_FILE_SYSTEMS = bfs bindfs btrfs cdda exfat ext2 fat iso9660 nfs attribute_overlay write_overlay ntfs packagefs reiserfs udf googlefs ; -# wifi firmware -for driver in $(SYSTEM_ADD_ONS_DRIVERS_NET) { - local package = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_PACKAGE) ] ; - local archive = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_ARCHIVE) ] ; - local extract = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_DO_EXTRACT) ] ; - if $(archive) { - AddWifiFirmwareToHaikuImage $(driver) : $(package) : $(archive) - : $(extract) ; - } - local packages = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_PACKAGES) ] ; - local archives = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_ARCHIVES) ] ; - for archive in $(archives) { - AddWifiFirmwareToHaikuImage $(driver) : $(packages[1]) : $(archive) - : $(extract) ; - packages = $(packages[2-]) ; - } -} +include [ FDirName $(HAIKU_BUILD_RULES_DIR) HaikuPackages ] ; -# modules -AddFilesToHaikuImage system add-ons kernel bus_managers - : $(SYSTEM_ADD_ONS_BUS_MANAGERS) ; -AddFilesToHaikuImage system add-ons kernel busses agp_gart - : $(X86_ONLY)intel ; - -if $(HAIKU_ATA_STACK) = 1 { - AddFilesToHaikuImage system add-ons kernel busses ata - : generic_ide_pci it8211 legacy_sata silicon_image_3112 - $(X86_ONLY)ide_isa ; -} else { - AddFilesToHaikuImage system add-ons kernel busses ide - : generic_ide_pci it8211 legacy_sata silicon_image_3112 - $(X86_ONLY)ide_isa ; -} - -AddFilesToHaikuImage system add-ons kernel busses scsi - : ahci ; -AddFilesToHaikuImage system add-ons kernel busses usb - : uhci ohci ehci ; -AddFilesToHaikuImage system add-ons kernel console - : vga_text ; -AddFilesToHaikuImage system add-ons kernel debugger - : demangle $(X86_ONLY)disasm - invalidate_on_exit usb_keyboard run_on_exit ; -AddFilesToHaikuImage system add-ons kernel file_systems - : $(SYSTEM_ADD_ONS_FILE_SYSTEMS) ; -AddFilesToHaikuImage system add-ons kernel generic - : $(ATA_ONLY)ata_adapter dpc $(IDE_ONLY)ide_adapter locked_pool mpu401 - scsi_periph tty ; -AddFilesToHaikuImage - system add-ons kernel partitioning_systems - : amiga_rdb apple efi_gpt intel session ; -AddFilesToHaikuImage - system add-ons kernel interrupt_controllers - : $(PPC_ONLY)openpic ; - -if $(TARGET_ARCH) = x86 { - AddFilesToHaikuImage system add-ons kernel cpu - : generic_x86 ; -} - -# drivers -AddNewDriversToHaikuImage disk scsi : scsi_cd scsi_disk ; -AddNewDriversToHaikuImage power : $(X86_ONLY)enhanced_speedstep ; -AddNewDriversToHaikuImage power : $(X86_ONLY)acpi_battery ; - -# legacy drivers -AddDriversToHaikuImage : console dprintf null - random tty zero ; -AddDriversToHaikuImage audio hmulti : $(SYSTEM_ADD_ONS_DRIVERS_AUDIO) ; -AddDriversToHaikuImage audio old : $(SYSTEM_ADD_ONS_DRIVERS_AUDIO_OLD) ; -AddDriversToHaikuImage midi : $(SYSTEM_ADD_ONS_DRIVERS_MIDI) ; -AddDriversToHaikuImage bus : usb_raw fw_raw ; -AddDriversToHaikuImage disk floppy : $(X86_ONLY)pc_floppy ; -AddDriversToHaikuImage disk usb : usb_disk ; -AddDriversToHaikuImage disk usb : usb_floppy ; -AddDriversToHaikuImage printer usb : usb_printer ; -AddDriversToHaikuImage disk virtual : nbd ; -AddDriversToHaikuImage dvb : cx23882 ; -AddDriversToHaikuImage graphics : $(SYSTEM_ADD_ONS_DRIVERS_GRAPHICS) ; -AddDriversToHaikuImage input : ps2_hid usb_hid wacom ; -AddDriversToHaikuImage misc : poke mem ; -AddDriversToHaikuImage net : $(SYSTEM_ADD_ONS_DRIVERS_NET) ; -AddDriversToHaikuImage ports : usb_serial ; -#AddDriversToHaikuImage power : $(SYSTEM_ADD_ONS_DRIVERS_POWER) ; - -# kernel -AddFilesToHaikuImage system - : kernel_$(TARGET_ARCH) ; - -# libs -AddLibrariesToHaikuImage system lib - : $(SYSTEM_LIBS) $(PRIVATE_SYSTEM_LIBS) ; - -# libnetwork.so replaces quite a few libraries -SYSTEM_LIBS_LIBNETWORK_ALIASES - = libsocket.so libbind.so libnet.so ; - -if $(HAIKU_GCC_VERSION[1]) = 2 { - local lib ; - for lib in $(SYSTEM_LIBS_LIBNETWORK_ALIASES) { - AddSymlinkToHaikuImage system lib - : libnetwork.so : $(lib) ; - } - - AddSymlinkToHaikuImage system lib : libbnetapi.so - : libnetapi.so ; -} - - -# libGL.so has GLU (like BeOS) *and* GLUT API built-in -SYSTEM_LIBS_LIBGL_ALIASES - = libGLU.so libglut.so ; - -if $(TARGET_ARCH) = x86 { - local lib ; - for lib in $(SYSTEM_LIBS_LIBGL_ALIASES) { - AddSymlinkToHaikuImage system lib - : libGL.so : $(lib) ; - } -} - -SYSTEM_LIBS_ALIASES = - $(SYSTEM_LIBS_LIBNETWORK_ALIASES) - libnetapi.so - $(SYSTEM_LIBS_LIBGL_ALIASES) -; - -# servers -AddFilesToHaikuImage system servers : $(SYSTEM_SERVERS) ; - -# apps -AddFilesToHaikuImage system : runtime_loader ; -AddFilesToHaikuImage system : Deskbar Tracker ; -AddFilesToHaikuImage system bin : $(SYSTEM_BIN) consoled ; -AddFilesToHaikuImage system apps : $(SYSTEM_APPS) ; -AddFilesToHaikuImage system preferences - : $(SYSTEM_PREFERENCES) ; -AddFilesToHaikuImage system demos : $(SYSTEM_DEMOS) ; - -SEARCH on which = [ FDirName $(HAIKU_TOP) data bin ] ; -AddFilesToHaikuImage system bin : which ; -SEARCH on installoptionalpackage = [ FDirName $(HAIKU_TOP) data bin ] ; -AddFilesToHaikuImage system bin : installoptionalpackage ; -SEARCH on install-wifi-firmwares.sh = [ FDirName $(HAIKU_TOP) data bin ] ; -AddFilesToHaikuImage system bin - : install-wifi-firmwares.sh ; # TODO: remove! # Add the files to be used by installoptionalpackage. @@ -354,9 +210,6 @@ for name in $(optional-pkg-files) { } AddInstalledPackagesFileToHaikuImage ; -AddSymlinkToHaikuImage system bin : bash : sh ; -AddSymlinkToHaikuImage system bin : trash : untrash ; - AddSymlinkToHaikuImage home Desktop : /boot/home : Home ; # Mailbox folders and symlink @@ -404,23 +257,8 @@ for linkTarget in $(SYSTEM_DEMOS) { : /boot/system/demos/$(linkTarget) : $(linkTarget) ; } -AddSymlinkToHaikuImage system bin : bzip2 : bunzip2 ; -AddSymlinkToHaikuImage system bin : less : more ; -AddSymlinkToHaikuImage system bin : gzip : gunzip ; -AddSymlinkToHaikuImage system bin : gzip : zcat ; -AddSymlinkToHaikuImage system bin : zdiff : zcmp ; -AddSymlinkToHaikuImage system bin : unzip : zipinfo ; -AddSymlinkToHaikuImage system bin : gawk : awk ; -AddSymlinkToHaikuImage system bin : grep : egrep ; -AddSymlinkToHaikuImage system bin : grep : fgrep ; - # scripts and data files -local bootScripts = Bootscript Bootscript.cd SetupEnvironment Netscript - InstallerInitScript InstallerFinishScript ; -SEARCH on $(bootScripts) = [ FDirName $(HAIKU_TOP) data system boot ] ; -AddFilesToHaikuImage system boot : $(bootScripts) ; - local userBootScripts = UserBootscript UserSetupEnvironment.sample ; SEARCH on $(userBootScripts) = [ FDirName $(HAIKU_TOP) data config boot ] ; AddFilesToHaikuImage home config boot : $(userBootScripts) ; @@ -428,37 +266,21 @@ AddFilesToHaikuImage home config boot : $(userBootScripts) ; # Add boot launch directory AddDirectoryToHaikuImage home config boot launch ; -local logoArtwork = - $(HAIKU_INCLUDE_TRADEMARKS)"HAIKU logo - white on blue - big.png" - $(HAIKU_INCLUDE_TRADEMARKS)"HAIKU logo - white on blue - normal.png" ; -SEARCH on $(logoArtwork) = [ FDirName $(HAIKU_TOP) data artwork ] ; -AddFilesToHaikuImage system data artwork : $(logoArtwork) ; - -AddDirectoryToHaikuImage system data sounds ; - # Add mail provider infos. AddFilesToHaikuImage home config settings Mail ProviderInfo : $(HAIKU_PROVIDER_INFOS) ; -# Mail spell check dictionaries -local spellFiles = words geekspeak ; -spellFiles = $(spellFiles:G=spell) ; -SEARCH on $(spellFiles) - = [ FDirName $(HAIKU_TOP) src apps mail ] ; -AddFilesToHaikuImage system data spell_check word_dictionary - : $(spellFiles) ; - local etcDir = [ FDirName $(HAIKU_TOP) data etc ] ; local etcFiles = inputrc profile ; etcFiles = $(etcFiles:G=etc) ; -SEARCH on $(etcFiles) = [ FDirName $(etcDir) ] ; +SEARCH on $(etcFiles) = $(etcDir) ; etcFiles += termcap sysless sysless.in ; AddFilesToHaikuImage common settings etc : $(etcFiles) ; local profileFiles = [ Glob $(etcDir)/profile.d : *.sh ] ; profileFiles = $(profileFiles:G=profile-d) ; -AddDirectoryToHaikuImage common etc profile.d ; -AddFilesToHaikuImage common etc profile.d : $(profileFiles) ; +AddDirectoryToHaikuImage common settings etc profile.d ; +AddFilesToHaikuImage common settings etc profile.d : $(profileFiles) ; #local bashCompletionFiles = [ Glob $(etcDir)/bash_completion.d : * ] ; #local bashCompletionHelperFiles @@ -471,52 +293,6 @@ AddFilesToHaikuImage common etc profile.d : $(profileFiles) ; #AddFilesToHaikuImage common etc bash_completion.d helpers # : $(bashCompletionHelperFiles) ; -local dataFiles = teapot.data ; -dataFiles = $(dataFiles:G=data) ; -SEARCH on $(dataFiles) = [ FDirName $(HAIKU_TOP) data system data ] ; -AddFilesToHaikuImage system data : $(dataFiles) ; - -local fortuneFiles = [ Glob $(HAIKU_TOP)/data/system/data/fortunes - : [a-zA-Z0-9]* ] ; -fortuneFiles = $(fortuneFiles:G=data!fortunes) ; -AddFilesToHaikuImage system data fortunes : $(fortuneFiles) ; - -local fontDir = [ FDirName $(HAIKU_TOP) data system data fonts ] ; -local psFonts = [ Glob $(fontDir)/psfonts : *.afm *.pfb ] ; -local ttFonts = [ Glob $(fontDir)/ttfonts : *.ttf ] ; -AddFilesToHaikuImage system data fonts psfonts : $(psFonts) ; -AddFilesToHaikuImage system data fonts ttfonts : $(ttFonts) ; - -local cannaDir = [ FDirName $(HAIKU_TOP) data system data Canna ] ; -local cannaDefault = [ Glob $(cannaDir)/default : *.canna *.gz ] ; -local cannaDic = [ Glob $(cannaDir)/dic : *.cbp ] ; -local cannaDicCanna = [ Glob $(cannaDir)/dic/canna - : *.cld *.ctd *.cbd *.dir ] ; -AddFilesToHaikuImage system data Canna default - : $(cannaDefault) ; -AddFilesToHaikuImage system data Canna dic : $(cannaDic) ; -AddFilesToHaikuImage system data Canna dic canna - : $(cannaDicCanna) ; -AddDirectoryToHaikuImage system data Canna dic group ; -AddDirectoryToHaikuImage system data Canna dic user ; - -local keymapFiles = [ Glob [ FDirName $(HAIKU_TOP) src data keymaps ] - : *.keymap ] ; -keymapFiles = $(keymapFiles:BG=keymap) ; -AddFilesToHaikuImage system data Keymaps : $(keymapFiles) ; -AddSymlinkToHaikuImage system data Keymaps : Swedish - : Finnish ; -AddSymlinkToHaikuImage system data Keymaps : Slovene - : Croatian ; -AddSymlinkToHaikuImage system data Keymaps : US-International - : Brazilian ; - -local keyboardLayoutsDir - = [ FDirName $(HAIKU_TOP) data system data KeyboardLayouts ] ; -local keyboardLayouts = [ Glob $(keyboardLayoutsDir) : [^.]* ] ; -AddFilesToHaikuImage system data KeyboardLayouts - : $(keyboardLayouts) ; - local driverSettingsFiles = kernel ; SEARCH on $(driverSettingsFiles) = [ FDirName $(HAIKU_TOP) data settings kernel drivers ] ; @@ -543,80 +319,6 @@ AddFilesToHaikuImage common settings : fresh_install ; # boot loader AddFilesToHaikuImage system : haiku_loader ; -# boot module links -AddBootModuleSymlinksToHaikuImage - $(X86_ONLY)acpi $(ATA_ONLY)ata pci $(X86_ONLY)isa config_manager dpc - $(IDE_ONLY)ide scsi usb - $(PPC_ONLY)openpic - $(ATA_ONLY)ata_adapter $(IDE_ONLY)ide_adapter locked_pool scsi_periph - ahci generic_ide_pci it8211 legacy_sata silicon_image_3112 - $(X86_ONLY)ide_isa - uhci ohci ehci - scsi_cd scsi_disk usb_disk - intel - bfs -; - -# add-ons -AddFilesToHaikuImage system add-ons accelerants - : $(SYSTEM_ADD_ONS_ACCELERANTS) ; -AddFilesToHaikuImage system add-ons opengl - : Mesa\ Software\ Renderer ; -AddFilesToHaikuImage system add-ons Translators - : $(SYSTEM_ADD_ONS_TRANSLATORS) ; -AddFilesToHaikuImage system add-ons locale catalogs - : $(SYSTEM_ADD_ONS_LOCALE_CATALOGS) ; -AddFilesToHaikuImage system add-ons locale catalogs - : $(SYSTEM_ADD_ONS_LOCALE_CATALOGS) ; -AddFilesToHaikuImage - system add-ons mail_daemon inbound_protocols - : POP3 IMAP ; -AddFilesToHaikuImage - system add-ons mail_daemon outbound_protocols : SMTP ; -AddFilesToHaikuImage - system add-ons mail_daemon inbound_filters - : MatchHeader SpamFilter NewMailNotification ; -AddFilesToHaikuImage - system add-ons mail_daemon outbound_filters - : Fortune ; -AddFilesToHaikuImage system add-ons media - : $(SYSTEM_ADD_ONS_MEDIA) ; -AddFilesToHaikuImage system add-ons media plugins - : $(SYSTEM_ADD_ONS_MEDIA_PLUGINS) ; -AddFilesToHaikuImage system add-ons Tracker - : FileType-F Mark\ as… Mark\ as\ Read-R Open\ Target\ Folder-O - Open\ Terminal-T ZipOMatic-Z ; -AddSymlinkToHaikuImage system add-ons Tracker - : /boot/system/preferences/Backgrounds : Background-B ; -AddSymlinkToHaikuImage system add-ons Tracker - : /boot/system/apps/TextSearch : TextSearch-G ; -AddSymlinkToHaikuImage system add-ons Tracker - : /boot/system/apps/DiskUsage : DiskUsage-I ; -AddFilesToHaikuImage system add-ons input_server devices - : keyboard mouse tablet wacom ; -AddFilesToHaikuImage system add-ons input_server filters - : screen_saver shortcut_catcher ; -AddFilesToHaikuImage system add-ons kernel network - : notifications stack ; -AddFilesToHaikuImage system add-ons kernel network devices - : $(SYSTEM_NETWORK_DEVICES) ; -AddFilesToHaikuImage - system add-ons kernel network datalink_protocols - : $(SYSTEM_NETWORK_DATALINK_PROTOCOLS) ; -AddFilesToHaikuImage system add-ons kernel network ppp - : $(SYSTEM_NETWORK_PPP) ; -AddFilesToHaikuImage system add-ons kernel network protocols - : $(SYSTEM_NETWORK_PROTOCOLS) ; -AddFilesToHaikuImage system add-ons Print - : $(SYSTEM_ADD_ONS_PRINT) ; -AddFilesToHaikuImage system add-ons Print transport - : $(SYSTEM_ADD_ONS_PRINT_TRANSPORT) ; -AddFilesToHaikuImage system add-ons Screen\ Savers - : $(SYSTEM_ADD_ONS_SCREENSAVERS) ; - -AddFilesToHaikuImage system add-ons disk_systems - : intel bfs ; - # decorators AddDirectoryToHaikuImage home config add-ons decorators ; AddFilesToHaikuImage home config add-ons decorators : @@ -646,11 +348,6 @@ AddDirectoryToHaikuImage home config add-ons Tracker ; AddDirectoryToHaikuImage home config add-ons Print ; AddDirectoryToHaikuImage home config add-ons Screen\ Savers ; AddDirectoryToHaikuImage home config add-ons Translators ; -AddDirectoryToHaikuImage system data synth ; -AddDirectoryToHaikuImage system add-ons input_server methods ; - -# optional -AddFilesToHaikuImage optional system add-ons input_server methods : canna ; # printers AddDirectoryToHaikuImage home config settings printers Preview @@ -658,11 +355,6 @@ AddDirectoryToHaikuImage home config settings printers Preview AddDirectoryToHaikuImage home config settings printers "Save as PDF" : home-config-settings-printers-save-as-pdf.rdef ; -# PDF Writer enconding files -CopyDirectoryToHaikuImage system data - : [ FDirName $(HAIKU_TOP) src add-ons print drivers pdf encoding ] - : "PDF Writer" : -x .svn -x Jamfile ; - # Gutenprint data files CopyDirectoryToHaikuImage common data : [ FDirName $(HAIKU_TOP) src libs print libgutenprint src xml ] @@ -673,21 +365,6 @@ CopyDirectoryToHaikuImage home config settings Media : [ FDirName $(HAIKU_TOP) data settings media dvb ] : dvb : -x .svn -x Jamfile ; -# licenses -CopyDirectoryToHaikuImage system data - : [ FDirName $(HAIKU_TOP) data system data licenses ] - : licenses : -x .svn ; - -# Copy documentation as per DiskUsage's license requirement. -CopyDirectoryToHaikuImage system documentation - : [ FDirName $(HAIKU_TOP) docs apps diskusage ] - : diskusage : -x .svn ; - -# Copy documentation as per PDFlib Lite's license requirement. -CopyDirectoryToHaikuImage system documentation - : [ FDirName $(HAIKU_TOP) src libs pdflib doc ] - : pdflib : -x .svn ; - # Copy sample programs as per PDFlib Lite's license requirement. CopyDirectoryToHaikuImage develop sample-code : [ FDirName $(HAIKU_TOP) src libs pdflib bind pdflib ] diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages new file mode 100644 index 0000000000..8bb519a3f6 --- /dev/null +++ b/build/jam/HaikuPackages @@ -0,0 +1,345 @@ +local haikuPackage = haiku.hpkg ; +HaikuPackage $(haikuPackage) ; + + +# wifi firmware +for driver in $(SYSTEM_ADD_ONS_DRIVERS_NET) { + local package = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_PACKAGE) ] ; + local archive = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_ARCHIVE) ] ; + local extract = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_DO_EXTRACT) ] ; + if $(archive) { + AddWifiFirmwareToPackage $(haikuPackage) : $(driver) : $(package) + : $(archive) : $(extract) ; + } + local packages = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_PACKAGES) ] ; + local archives = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_ARCHIVES) ] ; + for archive in $(archives) { + AddWifiFirmwareToPackage $(haikuPackage) : $(driver) : $(packages[1]) + : $(archive) : $(extract) ; + packages = $(packages[2-]) ; + } +} + + +# modules +AddFilesToPackage $(haikuPackage) : system add-ons kernel bus_managers + : $(SYSTEM_ADD_ONS_BUS_MANAGERS) ; +AddFilesToPackage $(haikuPackage) : system add-ons kernel busses agp_gart + : $(X86_ONLY)intel ; + +if $(HAIKU_ATA_STACK) = 1 { + AddFilesToPackage $(haikuPackage) : system add-ons kernel busses ata + : generic_ide_pci it8211 legacy_sata silicon_image_3112 + $(X86_ONLY)ide_isa ; +} else { + AddFilesToPackage $(haikuPackage) : system add-ons kernel busses ide + : generic_ide_pci it8211 legacy_sata silicon_image_3112 + $(X86_ONLY)ide_isa ; +} + +AddFilesToPackage $(haikuPackage) : system add-ons kernel busses scsi + : ahci ; +AddFilesToPackage $(haikuPackage) : system add-ons kernel busses usb + : uhci ohci ehci ; +AddFilesToPackage $(haikuPackage) : system add-ons kernel console + : vga_text ; +AddFilesToPackage $(haikuPackage) : system add-ons kernel debugger + : demangle $(X86_ONLY)disasm + invalidate_on_exit usb_keyboard run_on_exit ; +AddFilesToPackage $(haikuPackage) : system add-ons kernel file_systems + : $(SYSTEM_ADD_ONS_FILE_SYSTEMS) ; +AddFilesToPackage $(haikuPackage) : system add-ons kernel generic + : $(ATA_ONLY)ata_adapter dpc $(IDE_ONLY)ide_adapter locked_pool mpu401 + scsi_periph tty ; +AddFilesToPackage $(haikuPackage) : + system add-ons kernel partitioning_systems + : amiga_rdb apple efi_gpt intel session ; +AddFilesToPackage $(haikuPackage) : + system add-ons kernel interrupt_controllers + : $(PPC_ONLY)openpic ; + +if $(TARGET_ARCH) = x86 { + AddFilesToPackage $(haikuPackage) : system add-ons kernel cpu + : generic_x86 ; +} + +# drivers +AddNewDriversToPackage $(haikuPackage) : disk scsi : scsi_cd scsi_disk ; +AddNewDriversToPackage $(haikuPackage) : power : $(X86_ONLY)enhanced_speedstep ; +AddNewDriversToPackage $(haikuPackage) : power : $(X86_ONLY)acpi_battery ; + +# legacy drivers +AddDriversToPackage $(haikuPackage) : + : console dprintf null random tty zero ; +AddDriversToPackage $(haikuPackage) : audio hmulti + : $(SYSTEM_ADD_ONS_DRIVERS_AUDIO) ; +AddDriversToPackage $(haikuPackage) : audio old + : $(SYSTEM_ADD_ONS_DRIVERS_AUDIO_OLD) ; +AddDriversToPackage $(haikuPackage) : midi + : $(SYSTEM_ADD_ONS_DRIVERS_MIDI) ; +AddDriversToPackage $(haikuPackage) : bus : usb_raw fw_raw ; +AddDriversToPackage $(haikuPackage) : disk floppy : $(X86_ONLY)pc_floppy ; +AddDriversToPackage $(haikuPackage) : disk usb : usb_disk ; +AddDriversToPackage $(haikuPackage) : disk usb : usb_floppy ; +AddDriversToPackage $(haikuPackage) : printer usb : usb_printer ; +AddDriversToPackage $(haikuPackage) : disk virtual : nbd ; +AddDriversToPackage $(haikuPackage) : dvb : cx23882 ; +AddDriversToPackage $(haikuPackage) : graphics + : $(SYSTEM_ADD_ONS_DRIVERS_GRAPHICS) ; +AddDriversToPackage $(haikuPackage) : input : ps2_hid usb_hid wacom ; +AddDriversToPackage $(haikuPackage) : misc : poke mem ; +AddDriversToPackage $(haikuPackage) : net + : $(SYSTEM_ADD_ONS_DRIVERS_NET) ; +AddDriversToPackage $(haikuPackage) : ports : usb_serial ; +#AddDriversToPackage $(haikuPackage) : power +# : $(SYSTEM_ADD_ONS_DRIVERS_POWER) ; + +# kernel +AddFilesToPackage $(haikuPackage) : system + : kernel_$(TARGET_ARCH) ; + +# libs +AddLibrariesToPackage $(haikuPackage) : system lib + : $(SYSTEM_LIBS) $(PRIVATE_SYSTEM_LIBS) ; + +# libnetwork.so replaces quite a few libraries +SYSTEM_LIBS_LIBNETWORK_ALIASES + = libsocket.so libbind.so libnet.so ; + +if $(HAIKU_GCC_VERSION[1]) = 2 { + local lib ; + for lib in $(SYSTEM_LIBS_LIBNETWORK_ALIASES) { + AddSymlinkToPackage $(haikuPackage) : system lib + : libnetwork.so : $(lib) ; + } + + AddSymlinkToPackage $(haikuPackage) : system lib : libbnetapi.so + : libnetapi.so ; +} + + +# libGL.so has GLU (like BeOS) *and* GLUT API built-in +SYSTEM_LIBS_LIBGL_ALIASES + = libGLU.so libglut.so ; + +if $(TARGET_ARCH) = x86 { + local lib ; + for lib in $(SYSTEM_LIBS_LIBGL_ALIASES) { + AddSymlinkToPackage $(haikuPackage) : system lib : libGL.so : $(lib) ; + } +} + +SYSTEM_LIBS_ALIASES = + $(SYSTEM_LIBS_LIBNETWORK_ALIASES) + libnetapi.so + $(SYSTEM_LIBS_LIBGL_ALIASES) +; + +# servers +AddFilesToPackage $(haikuPackage) : system servers : $(SYSTEM_SERVERS) ; + +# apps +AddFilesToPackage $(haikuPackage) : system : runtime_loader ; +AddFilesToPackage $(haikuPackage) : system : Deskbar Tracker ; +AddFilesToPackage $(haikuPackage) : system bin : $(SYSTEM_BIN) consoled ; +AddFilesToPackage $(haikuPackage) : system apps : $(SYSTEM_APPS) ; +AddFilesToPackage $(haikuPackage) : system preferences + : $(SYSTEM_PREFERENCES) ; +AddFilesToPackage $(haikuPackage) : system demos : $(SYSTEM_DEMOS) ; + +SEARCH on which = [ FDirName $(HAIKU_TOP) data bin ] ; +AddFilesToPackage $(haikuPackage) : system bin : which ; +SEARCH on installoptionalpackage = [ FDirName $(HAIKU_TOP) data bin ] ; +AddFilesToPackage $(haikuPackage) : system bin : installoptionalpackage ; +SEARCH on install-wifi-firmwares.sh = [ FDirName $(HAIKU_TOP) data bin ] ; +AddFilesToPackage $(haikuPackage) : system bin : install-wifi-firmwares.sh ; + +AddSymlinkToPackage $(haikuPackage) : system bin : bash : sh ; +AddSymlinkToPackage $(haikuPackage) : system bin : trash : untrash ; + +AddSymlinkToPackage $(haikuPackage) : system bin : bzip2 : bunzip2 ; +AddSymlinkToPackage $(haikuPackage) : system bin : less : more ; +AddSymlinkToPackage $(haikuPackage) : system bin : gzip : gunzip ; +AddSymlinkToPackage $(haikuPackage) : system bin : gzip : zcat ; +AddSymlinkToPackage $(haikuPackage) : system bin : zdiff : zcmp ; +AddSymlinkToPackage $(haikuPackage) : system bin : unzip : zipinfo ; +AddSymlinkToPackage $(haikuPackage) : system bin : gawk : awk ; +AddSymlinkToPackage $(haikuPackage) : system bin : grep : egrep ; +AddSymlinkToPackage $(haikuPackage) : system bin : grep : fgrep ; + +# scripts and data files +local bootScripts = Bootscript Bootscript.cd SetupEnvironment Netscript + InstallerInitScript InstallerFinishScript ; +SEARCH on $(bootScripts) = [ FDirName $(HAIKU_TOP) data system boot ] ; +AddFilesToPackage $(haikuPackage) : system boot : $(bootScripts) ; + +# artwork and sounds +local logoArtwork = + $(HAIKU_INCLUDE_TRADEMARKS)"HAIKU logo - white on blue - big.png" + $(HAIKU_INCLUDE_TRADEMARKS)"HAIKU logo - white on blue - normal.png" ; +SEARCH on $(logoArtwork) = [ FDirName $(HAIKU_TOP) data artwork ] ; +AddFilesToPackage $(haikuPackage) : system data artwork : $(logoArtwork) ; + +AddDirectoryToPackage $(haikuPackage) : system data sounds ; + +# Mail spell check dictionaries +local spellFiles = words geekspeak ; +spellFiles = $(spellFiles:G=spell) ; +SEARCH on $(spellFiles) = [ FDirName $(HAIKU_TOP) src apps mail ] ; +AddFilesToPackage $(haikuPackage) : system data spell_check word_dictionary + : $(spellFiles) ; + +local dataFiles = teapot.data ; +dataFiles = $(dataFiles:G=data) ; +SEARCH on $(dataFiles) = [ FDirName $(HAIKU_TOP) data system data ] ; +AddFilesToPackage $(haikuPackage) : system data : $(dataFiles) ; + +local fortuneFiles = [ Glob $(HAIKU_TOP)/data/system/data/fortunes + : [a-zA-Z0-9]* ] ; +fortuneFiles = $(fortuneFiles:G=data!fortunes) ; +AddFilesToPackage $(haikuPackage) : system data fortunes : $(fortuneFiles) ; + +local fontDir = [ FDirName $(HAIKU_TOP) data system data fonts ] ; +local psFonts = [ Glob $(fontDir)/psfonts : *.afm *.pfb ] ; +local ttFonts = [ Glob $(fontDir)/ttfonts : *.ttf ] ; +AddFilesToPackage $(haikuPackage) : system data fonts psfonts : $(psFonts) ; +AddFilesToPackage $(haikuPackage) : system data fonts ttfonts : $(ttFonts) ; + +local cannaDir = [ FDirName $(HAIKU_TOP) data system data Canna ] ; +local cannaDefault = [ Glob $(cannaDir)/default : *.canna *.gz ] ; +local cannaDic = [ Glob $(cannaDir)/dic : *.cbp ] ; +local cannaDicCanna = [ Glob $(cannaDir)/dic/canna + : *.cld *.ctd *.cbd *.dir ] ; +AddFilesToPackage $(haikuPackage) : system data Canna default + : $(cannaDefault) ; +AddFilesToPackage $(haikuPackage) : system data Canna dic : $(cannaDic) ; +AddFilesToPackage $(haikuPackage) : system data Canna dic canna + : $(cannaDicCanna) ; +AddDirectoryToPackage $(haikuPackage) : system data Canna dic group ; +AddDirectoryToPackage $(haikuPackage) : system data Canna dic user ; + +local keymapFiles = [ Glob [ FDirName $(HAIKU_TOP) src data keymaps ] + : *.keymap ] ; +keymapFiles = $(keymapFiles:BG=keymap) ; +AddFilesToPackage $(haikuPackage) : system data Keymaps : $(keymapFiles) ; +AddSymlinkToPackage $(haikuPackage) : system data Keymaps : Swedish + : Finnish ; +AddSymlinkToPackage $(haikuPackage) : system data Keymaps : Slovene + : Croatian ; +AddSymlinkToPackage $(haikuPackage) : system data Keymaps : US-International + : Brazilian ; + +local keyboardLayoutsDir + = [ FDirName $(HAIKU_TOP) data system data KeyboardLayouts ] ; +local keyboardLayouts = [ Glob $(keyboardLayoutsDir) : [^.]* ] ; +AddFilesToPackage $(haikuPackage) : system data KeyboardLayouts + : $(keyboardLayouts) ; + +# boot loader +AddFilesToPackage $(haikuPackage) : system : haiku_loader ; + +# boot module links +AddBootModuleSymlinksToPackage $(haikuPackage) : + $(X86_ONLY)acpi $(ATA_ONLY)ata pci $(X86_ONLY)isa config_manager dpc + $(IDE_ONLY)ide scsi usb + $(PPC_ONLY)openpic + $(ATA_ONLY)ata_adapter $(IDE_ONLY)ide_adapter locked_pool scsi_periph + ahci generic_ide_pci it8211 legacy_sata silicon_image_3112 + $(X86_ONLY)ide_isa + uhci ohci ehci + scsi_cd scsi_disk usb_disk + intel + bfs +; + +# add-ons +AddFilesToPackage $(haikuPackage) : system add-ons accelerants + : $(SYSTEM_ADD_ONS_ACCELERANTS) ; +AddFilesToPackage $(haikuPackage) : system add-ons opengl + : Mesa\ Software\ Renderer ; +AddFilesToPackage $(haikuPackage) : system add-ons Translators + : $(SYSTEM_ADD_ONS_TRANSLATORS) ; +AddFilesToPackage $(haikuPackage) : system add-ons locale catalogs + : $(SYSTEM_ADD_ONS_LOCALE_CATALOGS) ; +AddFilesToPackage $(haikuPackage) : system add-ons locale catalogs + : $(SYSTEM_ADD_ONS_LOCALE_CATALOGS) ; +AddFilesToPackage $(haikuPackage) : + system add-ons mail_daemon inbound_protocols + : POP3 IMAP ; +AddFilesToPackage $(haikuPackage) : + system add-ons mail_daemon outbound_protocols : SMTP ; +AddFilesToPackage $(haikuPackage) : + system add-ons mail_daemon inbound_filters + : MatchHeader SpamFilter NewMailNotification ; +AddFilesToPackage $(haikuPackage) : + system add-ons mail_daemon outbound_filters + : Fortune ; +AddFilesToPackage $(haikuPackage) : system add-ons media + : $(SYSTEM_ADD_ONS_MEDIA) ; +AddFilesToPackage $(haikuPackage) : system add-ons media plugins + : $(SYSTEM_ADD_ONS_MEDIA_PLUGINS) ; +AddFilesToPackage $(haikuPackage) : system add-ons Tracker + : FileType-F Mark\ as… Mark\ as\ Read-R Open\ Target\ Folder-O + Open\ Terminal-T ZipOMatic-Z ; +AddSymlinkToPackage $(haikuPackage) : system add-ons Tracker + : /boot/system/preferences/Backgrounds : Background-B ; +AddSymlinkToPackage $(haikuPackage) : system add-ons Tracker + : /boot/system/apps/TextSearch : TextSearch-G ; +AddSymlinkToPackage $(haikuPackage) : system add-ons Tracker + : /boot/system/apps/DiskUsage : DiskUsage-I ; +AddFilesToPackage $(haikuPackage) : system add-ons input_server devices + : keyboard mouse tablet wacom ; +AddFilesToPackage $(haikuPackage) : system add-ons input_server filters + : screen_saver shortcut_catcher ; +AddFilesToPackage $(haikuPackage) : system add-ons kernel network + : notifications stack ; +AddFilesToPackage $(haikuPackage) : system add-ons kernel network devices + : $(SYSTEM_NETWORK_DEVICES) ; +AddFilesToPackage $(haikuPackage) : + system add-ons kernel network datalink_protocols + : $(SYSTEM_NETWORK_DATALINK_PROTOCOLS) ; +AddFilesToPackage $(haikuPackage) : system add-ons kernel network ppp + : $(SYSTEM_NETWORK_PPP) ; +AddFilesToPackage $(haikuPackage) : system add-ons kernel network protocols + : $(SYSTEM_NETWORK_PROTOCOLS) ; +AddFilesToPackage $(haikuPackage) : system add-ons Print + : $(SYSTEM_ADD_ONS_PRINT) ; +AddFilesToPackage $(haikuPackage) : system add-ons Print transport + : $(SYSTEM_ADD_ONS_PRINT_TRANSPORT) ; +AddFilesToPackage $(haikuPackage) : system add-ons Screen\ Savers + : $(SYSTEM_ADD_ONS_SCREENSAVERS) ; + +AddFilesToPackage $(haikuPackage) : system add-ons disk_systems + : intel bfs ; + + +AddDirectoryToPackage $(haikuPackage) : system data synth ; +AddDirectoryToPackage $(haikuPackage) : system add-ons input_server methods ; + +# optional +AddFilesToPackage $(haikuPackage) : optional system add-ons input_server methods + : canna ; + + +# PDF Writer enconding files +CopyDirectoryToPackage $(haikuPackage) : system data + : [ FDirName $(HAIKU_TOP) src add-ons print drivers pdf encoding ] + : "PDF Writer" : -x .svn -x Jamfile ; + +# licenses +CopyDirectoryToPackage $(haikuPackage) : system data + : [ FDirName $(HAIKU_TOP) data system data licenses ] + : licenses : -x .svn ; + +# Copy documentation as per DiskUsage's license requirement. +CopyDirectoryToPackage $(haikuPackage) : system documentation + : [ FDirName $(HAIKU_TOP) docs apps diskusage ] + : diskusage : -x .svn ; + +# Copy documentation as per PDFlib Lite's license requirement. +CopyDirectoryToPackage $(haikuPackage) : system documentation + : [ FDirName $(HAIKU_TOP) src libs pdflib doc ] + : pdflib : -x .svn ; + + +BuildHaikuPackage $(haikuPackage) : haiku ; diff --git a/build/jam/PackageRules b/build/jam/PackageRules index a155d47967..1413209300 100644 --- a/build/jam/PackageRules +++ b/build/jam/PackageRules @@ -40,7 +40,7 @@ rule FPackageConfigSubPath } else { configSubPath = $(TARGET_PLATFORM) $(TARGET_ARCH) ; } - + if $(DEBUG) = 0 { configSubPath += release ; } else { @@ -120,7 +120,7 @@ rule PackageSymLink local packagename = $(1) ; local symlinkPath = $(2) ; local symlinkTarget = $(3) ; - + local configSubPath = [ FPackageConfigSubPath $(packagename) ] ; local symlinkDir = [ FReverse $(symlinkPath) ] ; @@ -159,7 +159,7 @@ rule PackageDriverSymLink { # PackageDriverSymLink : ; # : Package name. - # : Path components relative to the + # : Path components relative to the # /boot/home/config/add-ons/kernel/drivers/dev directory, e.g. # "graphics mga.driver" (no quotation, of course). # @@ -248,3 +248,179 @@ actions together LinkInstallZip { ln -sf "`pwd`/$(2)" "$(1)" ; } + + +# TODO: The stuff above should be moved (Copy) or removed (the rest). + + +#pragma mark - Haiku Packages + + +rule FHaikuPackageGrist package +{ + local grist = [ Match "<(.*)>" : $(package:G) ] ; + return hpkg_$(grist:E="")_$(package:G=) ; +} + + +rule HaikuPackage package +{ + local grist = [ FHaikuPackageGrist $(package) ] ; + + HAIKU_CONTAINER_GRIST on $(package) = $(grist) ; + HAIKU_INCLUDE_IN_CONTAINER_VAR on $(package) + = $(grist)_HAIKU_INCLUDE_IN_PACKAGE ; + HAIKU_INSTALL_TARGETS_VAR on $(package) + = $(grist)_HAIKU_PACKAGE_INSTALL_TARGETS ; +} + + +rule BuildHaikuPackage package : packageInfo +{ + local grist = [ FHaikuPackageGrist $(package) ] ; + + local tempDir = [ FDirName $(HAIKU_PACKAGES_BUILD_DIR) $(grist) ] ; + local scriptDir = [ FDirName $(tempDir) scripts ] ; + + # locate the package and package info + MakeLocate $(package) : $(HAIKU_PACKAGES_DIR) ; + SEARCH on $(packageInfo) += $(HAIKU_PACKAGE_INFOS_DIR) ; + LocalDepends $(package) : $(packageInfo) ; + + # prepare the script that initializes the shell variables + local initVariablesScript = <$(grist)>haiku.package-init-vars ; + MakeLocate $(initVariablesScript) : $(scriptDir) ; + Always $(initVariablesScript) ; + + local script = $(initVariablesScript) ; + AddVariableToScript $(script) : sourceDir : $(HAIKU_TOP) ; + AddVariableToScript $(script) : outputDir : $(HAIKU_OUTPUT_DIR) ; + AddVariableToScript $(script) : tmpDir : $(tempDir) ; + AddVariableToScript $(script) : addBuildCompatibilityLibDir + : $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) ; + AddTargetVariableToScript $(script) : addattr ; + AddTargetVariableToScript $(script) : copyattr ; + AddTargetVariableToScript $(script) : package ; + AddTargetVariableToScript $(script) : rc ; + AddTargetVariableToScript $(script) : resattr ; + AddTargetVariableToScript $(script) : unzip ; + if $(HOST_RM_ATTRS_TARGET) { + AddTargetVariableToScript $(script) : $(HOST_RM_ATTRS_TARGET) + : rmAttrs ; + } else { + AddVariableToScript $(script) : rmAttrs : rm ; + } + + # create the other scripts + local makeDirsScript = <$(grist)>haiku.package-make-dirs ; + local copyFilesScript = <$(grist)>haiku.package-copy-files ; + + MakeLocate $(makeDirsScript) $(copyFilesScript) : $(scriptDir) ; + + CreateContainerMakeDirectoriesScript $(package) : $(makeDirsScript) ; + CreateContainerCopyFilesScript $(package) : $(copyFilesScript) ; + + local scripts = $(initVariablesScript) $(makeDirsScript) + $(copyFilesScript) ; + + # call the build actions + local mainScript = build_haiku_package ; + SEARCH on $(mainScript) = [ FDirName $(HAIKU_TOP) build scripts ] ; + + LocalDepends $(package) : $(mainScript) $(scripts) ; + BuildHaikuPackage1 $(package) : $(mainScript) $(packageInfo) $(scripts) ; +} + + +actions BuildHaikuPackage1 +{ + $(2[1]) "$(1)" "$(2[2])" $(2[3-]) +} + + +rule AddDirectoryToPackage package : directoryTokens : attributeFiles +{ + local dir = [ AddDirectoryToContainer $(package) : $(directoryTokens) ] ; + local grist = [ FHaikuPackageGrist $(package) ] ; + + if $(attributeFiles) { + SEARCH on $(attributeFiles) + += [ FDirName $(HAIKU_TOP) data package_directories $(grist) ] ; + ATTRIBUTE_FILES on $(dir) += $(attributeFiles) ; + } + + return $(dir) ; +} + + +rule AddFilesToPackage package : directory : targets : destName +{ + AddFilesToContainer $(package) : $(directory) : $(targets) : $(destName) ; +} + + +rule AddSymlinkToPackage package : directoryTokens : linkTarget : linkName +{ + linkTarget = $(linkTarget:J=/) ; + + AddSymlinkToContainer $(package) : $(directoryTokens) : $(linkTarget) + : $(linkName) ; +} + + +rule CopyDirectoryToPackage package : directoryTokens : sourceDirectory + : targetDirectoryName : excludePatterns : alwaysUpdate +{ + CopyDirectoryToContainer $(package) : $(directoryTokens) + : $(sourceDirectory) : $(targetDirectoryName) : $(excludePatterns) + : $(alwaysUpdate) ; +} + + +rule AddHeaderDirectoryToPackage package : dirTokens : dirName : alwaysUpdate +{ + AddHeaderDirectoryToContainer $(package) : $(dirTokens) : $(dirName) + : $(alwaysUpdate) ; +} + + +rule AddWifiFirmwareToPackage package : driver : subDirToExtract : archive + : extract +{ + AddWifiFirmwareToContainer $(package) : $(driver) : $(subDirToExtract) + : $(archive) : $(extract) ; +} + + +rule ExtractArchiveToPackage package : dirTokens : archiveFile : alwaysUpdate + : extractedSubDir +{ + # TODO: Update support? + ExtractArchiveToContainer $(package) : $(dirTokens) : $(archiveFile) + : $(extractedSubDir) ; +} + + +rule AddDriversToPackage package : relativeDirectoryTokens : targets +{ + AddDriversToContainer $(package) : $(relativeDirectoryTokens) : $(targets) ; +} + + +rule AddNewDriversToPackage package : relativeDirectoryTokens : targets +{ + AddNewDriversToContainer $(package) : $(relativeDirectoryTokens) + : $(targets) ; +} + + +rule AddBootModuleSymlinksToPackage package : targets +{ + AddBootModuleSymlinksToContainer $(package) : $(targets) ; +} + + +rule AddLibrariesToPackage package : directory : libs +{ + AddLibrariesToContainer $(package) : $(directory) : $(libs) ; +} diff --git a/build/scripts/build_haiku_image b/build/scripts/build_haiku_image index 1d2aed0647..1025c4bf7b 100755 --- a/build/scripts/build_haiku_image +++ b/build/scripts/build_haiku_image @@ -331,16 +331,18 @@ fi # ! updateOnly # add the concatenated copyrights as an attribute to AboutSystem +# TODO: That might not be necessary, when all third-party software everything +# is packaged. Though we might not package everything. -if [ ! $updateOnly ]; then - if [ -f $copyrightsFile ]; then - copyrightAttrs=$tmpDir/copyrightAttrs - $rmAttrs -f $copyrightAttrs - touch $copyrightAttrs - $addattr -f $copyrightsFile COPYRIGHTS $copyrightAttrs - $copyAttrs ${sPrefix}$copyrightAttrs ${tPrefix}system/apps/AboutSystem - fi -fi +# if [ ! $updateOnly ]; then +# if [ -f $copyrightsFile ]; then +# copyrightAttrs=$tmpDir/copyrightAttrs +# $rmAttrs -f $copyrightAttrs +# touch $copyrightAttrs +# $addattr -f $copyrightsFile COPYRIGHTS $copyrightAttrs +# $copyAttrs ${sPrefix}$copyrightAttrs ${tPrefix}system/apps/AboutSystem +# fi +# fi if [ $isCD ]; then # generate the attribute stores diff --git a/build/scripts/build_haiku_package b/build/scripts/build_haiku_package new file mode 100755 index 0000000000..2b326d55d8 --- /dev/null +++ b/build/scripts/build_haiku_package @@ -0,0 +1,66 @@ +#!/bin/sh +set -o errexit + +# The first argument is the shell script that initializes the variables: +# sourceDir +# outputDir +# tmpDir +# addBuildCompatibilityLibDir +# +# addattr +# copyattr +# package +# rc +# rmAttrs +# unzip +# + +if [ $# -le 1 ]; then + echo "$0: Missing parameters!" >&2 + exit 1 +fi + +packagePath="$1" +packageInfoPath="$2" +shift 2 +echo "Building package $1 with info $2..." + +if [ $# -gt 0 ]; then + . $1 + shift +fi + +# this adds the build library dir to LD_LIBRARY_PATH +eval "$addBuildCompatibilityLibDir" + + +# make a clean contents dir +contentsDir="$tmpDir/contents" +$rmAttrs -rf "$contentsDir" +mkdir -p "$contentsDir" + + +# map the shell commands +sPrefix= +tPrefix="$contentsDir/" +cd=cd +scd=: +cp="$copyattr -d" +copyAttrs="$copyattr" +ln=ln +mkdir=mkdir +rm=$rmAttrs +mkindex=mkindex + + +# execute the scripts preparing the package contents +while [ $# -gt 0 ]; do + . $1 + shift +done + + +# create the package +cp "$packageInfoPath" "$contentsDir/.PackageInfo" +rm -f "$packagePath" +$package create -C "$contentsDir" "$packagePath" diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku new file mode 100644 index 0000000000..4c2db1e64f --- /dev/null +++ b/src/data/package_infos/haiku @@ -0,0 +1,19 @@ +name = Haiku +version = 1-1 +architecture = x86 +summary = "The Haiku base system" +description = "The Haiku base system includes all system core software, like +boot loader, kernel, the system libraries, servers, and applications." + +packager = "Ingo Weinhold " +vendor = "Haiku Project" + +copyright = "2001-2011 Haiku, Inc. et al" +licenses = [ "MIT" ] + +provides = [ + haiku +] + +requires = [ +] From 93211f331fa18d566cedcbf86ea6554af074ad96 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 17 Jun 2011 16:03:56 +0200 Subject: [PATCH 0023/1170] PackageWriterImpl: Build platform symlink issues On a non-Haiku build platform map openat(), fstat(), and FileDescriptorCloser to _kern_open(), _kern_read_stat(), and BuildFileDescriptorCloser respectively, so symlinks can be opened and stat()ed. --- src/kits/package/hpkg/PackageWriterImpl.cpp | 71 ++++++++++++++++++++- 1 file changed, 70 insertions(+), 1 deletion(-) diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp index 7504796618..feccb880a9 100644 --- a/src/kits/package/hpkg/PackageWriterImpl.cpp +++ b/src/kits/package/hpkg/PackageWriterImpl.cpp @@ -38,6 +38,75 @@ using BPrivate::FileDescriptorCloser; +// We need to remap a few file operations on non-Haiku platforms, so dealing +// with symlinks works correctly. +#ifndef __HAIKU__ + + +extern "C" int _kern_open(int fd, const char *path, int openMode, int perms); +extern "C" status_t _kern_close(int fd); +extern "C" status_t _kern_read_stat(int fd, const char *path, bool traverseLink, + struct stat *st, size_t statSize); + + +static int +build_openat(int dirFD, const char* fileName, int openMode, int permissions) +{ + int fd = _kern_open(dirFD, fileName, openMode, permissions); + if (fd < 0) { + errno = fd; + return -1; + } + + return fd; +} + + +static int +build_fstat(int fd, struct stat* st) +{ + status_t error = _kern_read_stat(fd, NULL, false, st, sizeof(struct stat)); + if (error != B_OK) { + errno = error; + return -1; + } + + return 0; +} + + +struct BuildFileDescriptorCloser { + BuildFileDescriptorCloser(int fd) + : + fFD(fd) + { + } + + ~BuildFileDescriptorCloser() + { + if (fFD >= 0) + _kern_close(fFD); + } + +private: + int fFD; +}; + + +#undef openat +#define openat(dirFD, fileName, openMode) \ + build_openat(dirFD, fileName, openMode, 0) + +#undef fstat +#define fstat(fd, st) build_fstat(fd, st) + +#undef FileDescriptorCloser +#define FileDescriptorCloser BuildFileDescriptorCloser + + +#endif + + namespace BPackageKit { namespace BHPKG { @@ -914,7 +983,7 @@ PackageWriterImpl::_WriteZlibCompressedData(BDataReader& dataReader, off_t size, uint64 writeOffset, uint64& _compressedSize) { // Use zlib compression only for data large enough. - if (size < kZlibCompressionSizeThreshold) + if (size < (off_t)kZlibCompressionSizeThreshold) return B_BAD_VALUE; // fDataBuffer is 2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB, so split it into From d1f40ef6361b4111a6601f42f41945f1418d1fea Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 18 Jun 2011 01:47:59 +0200 Subject: [PATCH 0024/1170] HaikuPackages: Remove the "system" path component --- build/jam/HaikuPackages | 199 +++++++++++++++++++--------------------- 1 file changed, 94 insertions(+), 105 deletions(-) diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages index 8bb519a3f6..f96e77c539 100644 --- a/build/jam/HaikuPackages +++ b/build/jam/HaikuPackages @@ -22,45 +22,42 @@ for driver in $(SYSTEM_ADD_ONS_DRIVERS_NET) { # modules -AddFilesToPackage $(haikuPackage) : system add-ons kernel bus_managers +AddFilesToPackage $(haikuPackage) : add-ons kernel bus_managers : $(SYSTEM_ADD_ONS_BUS_MANAGERS) ; -AddFilesToPackage $(haikuPackage) : system add-ons kernel busses agp_gart +AddFilesToPackage $(haikuPackage) : add-ons kernel busses agp_gart : $(X86_ONLY)intel ; if $(HAIKU_ATA_STACK) = 1 { - AddFilesToPackage $(haikuPackage) : system add-ons kernel busses ata + AddFilesToPackage $(haikuPackage) : add-ons kernel busses ata : generic_ide_pci it8211 legacy_sata silicon_image_3112 $(X86_ONLY)ide_isa ; } else { - AddFilesToPackage $(haikuPackage) : system add-ons kernel busses ide + AddFilesToPackage $(haikuPackage) : add-ons kernel busses ide : generic_ide_pci it8211 legacy_sata silicon_image_3112 $(X86_ONLY)ide_isa ; } -AddFilesToPackage $(haikuPackage) : system add-ons kernel busses scsi +AddFilesToPackage $(haikuPackage) : add-ons kernel busses scsi : ahci ; -AddFilesToPackage $(haikuPackage) : system add-ons kernel busses usb +AddFilesToPackage $(haikuPackage) : add-ons kernel busses usb : uhci ohci ehci ; -AddFilesToPackage $(haikuPackage) : system add-ons kernel console +AddFilesToPackage $(haikuPackage) : add-ons kernel console : vga_text ; -AddFilesToPackage $(haikuPackage) : system add-ons kernel debugger +AddFilesToPackage $(haikuPackage) : add-ons kernel debugger : demangle $(X86_ONLY)disasm invalidate_on_exit usb_keyboard run_on_exit ; -AddFilesToPackage $(haikuPackage) : system add-ons kernel file_systems +AddFilesToPackage $(haikuPackage) : add-ons kernel file_systems : $(SYSTEM_ADD_ONS_FILE_SYSTEMS) ; -AddFilesToPackage $(haikuPackage) : system add-ons kernel generic +AddFilesToPackage $(haikuPackage) : add-ons kernel generic : $(ATA_ONLY)ata_adapter dpc $(IDE_ONLY)ide_adapter locked_pool mpu401 scsi_periph tty ; -AddFilesToPackage $(haikuPackage) : - system add-ons kernel partitioning_systems +AddFilesToPackage $(haikuPackage) : add-ons kernel partitioning_systems : amiga_rdb apple efi_gpt intel session ; -AddFilesToPackage $(haikuPackage) : - system add-ons kernel interrupt_controllers +AddFilesToPackage $(haikuPackage) : add-ons kernel interrupt_controllers : $(PPC_ONLY)openpic ; if $(TARGET_ARCH) = x86 { - AddFilesToPackage $(haikuPackage) : system add-ons kernel cpu - : generic_x86 ; + AddFilesToPackage $(haikuPackage) : add-ons kernel cpu : generic_x86 ; } # drivers @@ -95,11 +92,10 @@ AddDriversToPackage $(haikuPackage) : ports : usb_serial ; # : $(SYSTEM_ADD_ONS_DRIVERS_POWER) ; # kernel -AddFilesToPackage $(haikuPackage) : system - : kernel_$(TARGET_ARCH) ; +AddFilesToPackage $(haikuPackage) : : kernel_$(TARGET_ARCH) ; # libs -AddLibrariesToPackage $(haikuPackage) : system lib +AddLibrariesToPackage $(haikuPackage) : lib : $(SYSTEM_LIBS) $(PRIVATE_SYSTEM_LIBS) ; # libnetwork.so replaces quite a few libraries @@ -109,12 +105,10 @@ SYSTEM_LIBS_LIBNETWORK_ALIASES if $(HAIKU_GCC_VERSION[1]) = 2 { local lib ; for lib in $(SYSTEM_LIBS_LIBNETWORK_ALIASES) { - AddSymlinkToPackage $(haikuPackage) : system lib - : libnetwork.so : $(lib) ; + AddSymlinkToPackage $(haikuPackage) : lib : libnetwork.so : $(lib) ; } - AddSymlinkToPackage $(haikuPackage) : system lib : libbnetapi.so - : libnetapi.so ; + AddSymlinkToPackage $(haikuPackage) : lib : libbnetapi.so : libnetapi.so ; } @@ -125,7 +119,7 @@ SYSTEM_LIBS_LIBGL_ALIASES if $(TARGET_ARCH) = x86 { local lib ; for lib in $(SYSTEM_LIBS_LIBGL_ALIASES) { - AddSymlinkToPackage $(haikuPackage) : system lib : libGL.so : $(lib) ; + AddSymlinkToPackage $(haikuPackage) : lib : libGL.so : $(lib) ; } } @@ -136,107 +130,105 @@ SYSTEM_LIBS_ALIASES = ; # servers -AddFilesToPackage $(haikuPackage) : system servers : $(SYSTEM_SERVERS) ; +AddFilesToPackage $(haikuPackage) : servers : $(SYSTEM_SERVERS) ; # apps -AddFilesToPackage $(haikuPackage) : system : runtime_loader ; -AddFilesToPackage $(haikuPackage) : system : Deskbar Tracker ; -AddFilesToPackage $(haikuPackage) : system bin : $(SYSTEM_BIN) consoled ; -AddFilesToPackage $(haikuPackage) : system apps : $(SYSTEM_APPS) ; -AddFilesToPackage $(haikuPackage) : system preferences - : $(SYSTEM_PREFERENCES) ; -AddFilesToPackage $(haikuPackage) : system demos : $(SYSTEM_DEMOS) ; +AddFilesToPackage $(haikuPackage) : : runtime_loader ; +AddFilesToPackage $(haikuPackage) : : Deskbar Tracker ; +AddFilesToPackage $(haikuPackage) : bin : $(SYSTEM_BIN) consoled ; +AddFilesToPackage $(haikuPackage) : apps : $(SYSTEM_APPS) ; +AddFilesToPackage $(haikuPackage) : preferences : $(SYSTEM_PREFERENCES) ; +AddFilesToPackage $(haikuPackage) : demos : $(SYSTEM_DEMOS) ; SEARCH on which = [ FDirName $(HAIKU_TOP) data bin ] ; -AddFilesToPackage $(haikuPackage) : system bin : which ; +AddFilesToPackage $(haikuPackage) : bin : which ; SEARCH on installoptionalpackage = [ FDirName $(HAIKU_TOP) data bin ] ; -AddFilesToPackage $(haikuPackage) : system bin : installoptionalpackage ; +AddFilesToPackage $(haikuPackage) : bin : installoptionalpackage ; SEARCH on install-wifi-firmwares.sh = [ FDirName $(HAIKU_TOP) data bin ] ; -AddFilesToPackage $(haikuPackage) : system bin : install-wifi-firmwares.sh ; +AddFilesToPackage $(haikuPackage) : bin : install-wifi-firmwares.sh ; -AddSymlinkToPackage $(haikuPackage) : system bin : bash : sh ; -AddSymlinkToPackage $(haikuPackage) : system bin : trash : untrash ; +AddSymlinkToPackage $(haikuPackage) : bin : bash : sh ; +AddSymlinkToPackage $(haikuPackage) : bin : trash : untrash ; -AddSymlinkToPackage $(haikuPackage) : system bin : bzip2 : bunzip2 ; -AddSymlinkToPackage $(haikuPackage) : system bin : less : more ; -AddSymlinkToPackage $(haikuPackage) : system bin : gzip : gunzip ; -AddSymlinkToPackage $(haikuPackage) : system bin : gzip : zcat ; -AddSymlinkToPackage $(haikuPackage) : system bin : zdiff : zcmp ; -AddSymlinkToPackage $(haikuPackage) : system bin : unzip : zipinfo ; -AddSymlinkToPackage $(haikuPackage) : system bin : gawk : awk ; -AddSymlinkToPackage $(haikuPackage) : system bin : grep : egrep ; -AddSymlinkToPackage $(haikuPackage) : system bin : grep : fgrep ; +AddSymlinkToPackage $(haikuPackage) : bin : bzip2 : bunzip2 ; +AddSymlinkToPackage $(haikuPackage) : bin : less : more ; +AddSymlinkToPackage $(haikuPackage) : bin : gzip : gunzip ; +AddSymlinkToPackage $(haikuPackage) : bin : gzip : zcat ; +AddSymlinkToPackage $(haikuPackage) : bin : zdiff : zcmp ; +AddSymlinkToPackage $(haikuPackage) : bin : unzip : zipinfo ; +AddSymlinkToPackage $(haikuPackage) : bin : gawk : awk ; +AddSymlinkToPackage $(haikuPackage) : bin : grep : egrep ; +AddSymlinkToPackage $(haikuPackage) : bin : grep : fgrep ; # scripts and data files local bootScripts = Bootscript Bootscript.cd SetupEnvironment Netscript InstallerInitScript InstallerFinishScript ; SEARCH on $(bootScripts) = [ FDirName $(HAIKU_TOP) data system boot ] ; -AddFilesToPackage $(haikuPackage) : system boot : $(bootScripts) ; +AddFilesToPackage $(haikuPackage) : boot : $(bootScripts) ; # artwork and sounds local logoArtwork = $(HAIKU_INCLUDE_TRADEMARKS)"HAIKU logo - white on blue - big.png" $(HAIKU_INCLUDE_TRADEMARKS)"HAIKU logo - white on blue - normal.png" ; SEARCH on $(logoArtwork) = [ FDirName $(HAIKU_TOP) data artwork ] ; -AddFilesToPackage $(haikuPackage) : system data artwork : $(logoArtwork) ; +AddFilesToPackage $(haikuPackage) : data artwork : $(logoArtwork) ; -AddDirectoryToPackage $(haikuPackage) : system data sounds ; +AddDirectoryToPackage $(haikuPackage) : data sounds ; # Mail spell check dictionaries local spellFiles = words geekspeak ; spellFiles = $(spellFiles:G=spell) ; SEARCH on $(spellFiles) = [ FDirName $(HAIKU_TOP) src apps mail ] ; -AddFilesToPackage $(haikuPackage) : system data spell_check word_dictionary +AddFilesToPackage $(haikuPackage) : data spell_check word_dictionary : $(spellFiles) ; local dataFiles = teapot.data ; dataFiles = $(dataFiles:G=data) ; SEARCH on $(dataFiles) = [ FDirName $(HAIKU_TOP) data system data ] ; -AddFilesToPackage $(haikuPackage) : system data : $(dataFiles) ; +AddFilesToPackage $(haikuPackage) : data : $(dataFiles) ; local fortuneFiles = [ Glob $(HAIKU_TOP)/data/system/data/fortunes : [a-zA-Z0-9]* ] ; fortuneFiles = $(fortuneFiles:G=data!fortunes) ; -AddFilesToPackage $(haikuPackage) : system data fortunes : $(fortuneFiles) ; +AddFilesToPackage $(haikuPackage) : data fortunes : $(fortuneFiles) ; local fontDir = [ FDirName $(HAIKU_TOP) data system data fonts ] ; local psFonts = [ Glob $(fontDir)/psfonts : *.afm *.pfb ] ; local ttFonts = [ Glob $(fontDir)/ttfonts : *.ttf ] ; -AddFilesToPackage $(haikuPackage) : system data fonts psfonts : $(psFonts) ; -AddFilesToPackage $(haikuPackage) : system data fonts ttfonts : $(ttFonts) ; +AddFilesToPackage $(haikuPackage) : data fonts psfonts : $(psFonts) ; +AddFilesToPackage $(haikuPackage) : data fonts ttfonts : $(ttFonts) ; local cannaDir = [ FDirName $(HAIKU_TOP) data system data Canna ] ; local cannaDefault = [ Glob $(cannaDir)/default : *.canna *.gz ] ; local cannaDic = [ Glob $(cannaDir)/dic : *.cbp ] ; local cannaDicCanna = [ Glob $(cannaDir)/dic/canna : *.cld *.ctd *.cbd *.dir ] ; -AddFilesToPackage $(haikuPackage) : system data Canna default +AddFilesToPackage $(haikuPackage) : data Canna default : $(cannaDefault) ; -AddFilesToPackage $(haikuPackage) : system data Canna dic : $(cannaDic) ; -AddFilesToPackage $(haikuPackage) : system data Canna dic canna +AddFilesToPackage $(haikuPackage) : data Canna dic : $(cannaDic) ; +AddFilesToPackage $(haikuPackage) : data Canna dic canna : $(cannaDicCanna) ; -AddDirectoryToPackage $(haikuPackage) : system data Canna dic group ; -AddDirectoryToPackage $(haikuPackage) : system data Canna dic user ; +AddDirectoryToPackage $(haikuPackage) : data Canna dic group ; +AddDirectoryToPackage $(haikuPackage) : data Canna dic user ; local keymapFiles = [ Glob [ FDirName $(HAIKU_TOP) src data keymaps ] : *.keymap ] ; keymapFiles = $(keymapFiles:BG=keymap) ; -AddFilesToPackage $(haikuPackage) : system data Keymaps : $(keymapFiles) ; -AddSymlinkToPackage $(haikuPackage) : system data Keymaps : Swedish +AddFilesToPackage $(haikuPackage) : data Keymaps : $(keymapFiles) ; +AddSymlinkToPackage $(haikuPackage) : data Keymaps : Swedish : Finnish ; -AddSymlinkToPackage $(haikuPackage) : system data Keymaps : Slovene +AddSymlinkToPackage $(haikuPackage) : data Keymaps : Slovene : Croatian ; -AddSymlinkToPackage $(haikuPackage) : system data Keymaps : US-International +AddSymlinkToPackage $(haikuPackage) : data Keymaps : US-International : Brazilian ; local keyboardLayoutsDir = [ FDirName $(HAIKU_TOP) data system data KeyboardLayouts ] ; local keyboardLayouts = [ Glob $(keyboardLayoutsDir) : [^.]* ] ; -AddFilesToPackage $(haikuPackage) : system data KeyboardLayouts - : $(keyboardLayouts) ; +AddFilesToPackage $(haikuPackage) : data KeyboardLayouts : $(keyboardLayouts) ; # boot loader -AddFilesToPackage $(haikuPackage) : system : haiku_loader ; +AddFilesToPackage $(haikuPackage) : : haiku_loader ; # boot module links AddBootModuleSymlinksToPackage $(haikuPackage) : @@ -253,91 +245,88 @@ AddBootModuleSymlinksToPackage $(haikuPackage) : ; # add-ons -AddFilesToPackage $(haikuPackage) : system add-ons accelerants +AddFilesToPackage $(haikuPackage) : add-ons accelerants : $(SYSTEM_ADD_ONS_ACCELERANTS) ; -AddFilesToPackage $(haikuPackage) : system add-ons opengl +AddFilesToPackage $(haikuPackage) : add-ons opengl : Mesa\ Software\ Renderer ; -AddFilesToPackage $(haikuPackage) : system add-ons Translators +AddFilesToPackage $(haikuPackage) : add-ons Translators : $(SYSTEM_ADD_ONS_TRANSLATORS) ; -AddFilesToPackage $(haikuPackage) : system add-ons locale catalogs +AddFilesToPackage $(haikuPackage) : add-ons locale catalogs : $(SYSTEM_ADD_ONS_LOCALE_CATALOGS) ; -AddFilesToPackage $(haikuPackage) : system add-ons locale catalogs +AddFilesToPackage $(haikuPackage) : add-ons locale catalogs : $(SYSTEM_ADD_ONS_LOCALE_CATALOGS) ; -AddFilesToPackage $(haikuPackage) : - system add-ons mail_daemon inbound_protocols +AddFilesToPackage $(haikuPackage) : add-ons mail_daemon inbound_protocols : POP3 IMAP ; -AddFilesToPackage $(haikuPackage) : - system add-ons mail_daemon outbound_protocols : SMTP ; -AddFilesToPackage $(haikuPackage) : - system add-ons mail_daemon inbound_filters +AddFilesToPackage $(haikuPackage) : add-ons mail_daemon outbound_protocols + : SMTP ; +AddFilesToPackage $(haikuPackage) : add-ons mail_daemon inbound_filters : MatchHeader SpamFilter NewMailNotification ; -AddFilesToPackage $(haikuPackage) : - system add-ons mail_daemon outbound_filters +AddFilesToPackage $(haikuPackage) : add-ons mail_daemon outbound_filters : Fortune ; -AddFilesToPackage $(haikuPackage) : system add-ons media - : $(SYSTEM_ADD_ONS_MEDIA) ; -AddFilesToPackage $(haikuPackage) : system add-ons media plugins +AddFilesToPackage $(haikuPackage) : add-ons media : $(SYSTEM_ADD_ONS_MEDIA) ; +AddFilesToPackage $(haikuPackage) : add-ons media plugins : $(SYSTEM_ADD_ONS_MEDIA_PLUGINS) ; -AddFilesToPackage $(haikuPackage) : system add-ons Tracker +AddFilesToPackage $(haikuPackage) : add-ons Tracker : FileType-F Mark\ as… Mark\ as\ Read-R Open\ Target\ Folder-O Open\ Terminal-T ZipOMatic-Z ; -AddSymlinkToPackage $(haikuPackage) : system add-ons Tracker +AddSymlinkToPackage $(haikuPackage) : add-ons Tracker : /boot/system/preferences/Backgrounds : Background-B ; -AddSymlinkToPackage $(haikuPackage) : system add-ons Tracker +AddSymlinkToPackage $(haikuPackage) : add-ons Tracker : /boot/system/apps/TextSearch : TextSearch-G ; -AddSymlinkToPackage $(haikuPackage) : system add-ons Tracker +AddSymlinkToPackage $(haikuPackage) : add-ons Tracker : /boot/system/apps/DiskUsage : DiskUsage-I ; -AddFilesToPackage $(haikuPackage) : system add-ons input_server devices +AddFilesToPackage $(haikuPackage) : add-ons input_server devices : keyboard mouse tablet wacom ; -AddFilesToPackage $(haikuPackage) : system add-ons input_server filters +AddFilesToPackage $(haikuPackage) : add-ons input_server filters : screen_saver shortcut_catcher ; -AddFilesToPackage $(haikuPackage) : system add-ons kernel network +AddFilesToPackage $(haikuPackage) : add-ons kernel network : notifications stack ; -AddFilesToPackage $(haikuPackage) : system add-ons kernel network devices +AddFilesToPackage $(haikuPackage) : add-ons kernel network devices : $(SYSTEM_NETWORK_DEVICES) ; -AddFilesToPackage $(haikuPackage) : - system add-ons kernel network datalink_protocols +AddFilesToPackage $(haikuPackage) : add-ons kernel network datalink_protocols : $(SYSTEM_NETWORK_DATALINK_PROTOCOLS) ; -AddFilesToPackage $(haikuPackage) : system add-ons kernel network ppp +AddFilesToPackage $(haikuPackage) : add-ons kernel network ppp : $(SYSTEM_NETWORK_PPP) ; -AddFilesToPackage $(haikuPackage) : system add-ons kernel network protocols +AddFilesToPackage $(haikuPackage) : add-ons kernel network protocols : $(SYSTEM_NETWORK_PROTOCOLS) ; -AddFilesToPackage $(haikuPackage) : system add-ons Print +AddFilesToPackage $(haikuPackage) : add-ons Print : $(SYSTEM_ADD_ONS_PRINT) ; -AddFilesToPackage $(haikuPackage) : system add-ons Print transport +AddFilesToPackage $(haikuPackage) : add-ons Print transport : $(SYSTEM_ADD_ONS_PRINT_TRANSPORT) ; -AddFilesToPackage $(haikuPackage) : system add-ons Screen\ Savers +AddFilesToPackage $(haikuPackage) : add-ons Screen\ Savers : $(SYSTEM_ADD_ONS_SCREENSAVERS) ; -AddFilesToPackage $(haikuPackage) : system add-ons disk_systems +AddFilesToPackage $(haikuPackage) : add-ons disk_systems : intel bfs ; -AddDirectoryToPackage $(haikuPackage) : system data synth ; -AddDirectoryToPackage $(haikuPackage) : system add-ons input_server methods ; +AddDirectoryToPackage $(haikuPackage) : data synth ; +AddDirectoryToPackage $(haikuPackage) : add-ons input_server methods ; # optional -AddFilesToPackage $(haikuPackage) : optional system add-ons input_server methods +# TODO: We should probably build another package that can be installed, if +# desired. +AddFilesToPackage $(haikuPackage) : optional add-ons input_server methods : canna ; # PDF Writer enconding files -CopyDirectoryToPackage $(haikuPackage) : system data +CopyDirectoryToPackage $(haikuPackage) : data : [ FDirName $(HAIKU_TOP) src add-ons print drivers pdf encoding ] : "PDF Writer" : -x .svn -x Jamfile ; # licenses -CopyDirectoryToPackage $(haikuPackage) : system data +CopyDirectoryToPackage $(haikuPackage) : data : [ FDirName $(HAIKU_TOP) data system data licenses ] : licenses : -x .svn ; # Copy documentation as per DiskUsage's license requirement. -CopyDirectoryToPackage $(haikuPackage) : system documentation +CopyDirectoryToPackage $(haikuPackage) : documentation : [ FDirName $(HAIKU_TOP) docs apps diskusage ] : diskusage : -x .svn ; # Copy documentation as per PDFlib Lite's license requirement. -CopyDirectoryToPackage $(haikuPackage) : system documentation +CopyDirectoryToPackage $(haikuPackage) : documentation : [ FDirName $(HAIKU_TOP) src libs pdflib doc ] : pdflib : -x .svn ; From dcdeed6176ea40e52a44f17be2573b6fed3946ba Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 18 Jun 2011 01:57:35 +0200 Subject: [PATCH 0025/1170] AddDirectoryTo{HaikuImage,...} refactoring Move common code from AddDirectoryToHaikuImage/AddDirectoryToPackage to AddDirectoryToContainer. AddDirectoryToPackage was incorrect, using an incorrect search directory for the attribute files. --- build/jam/ImageRules | 24 +++++++++++------------- build/jam/PackageRules | 12 ++---------- 2 files changed, 13 insertions(+), 23 deletions(-) diff --git a/build/jam/ImageRules b/build/jam/ImageRules index df2b81a0c9..fd3f30758c 100644 --- a/build/jam/ImageRules +++ b/build/jam/ImageRules @@ -97,9 +97,9 @@ actions AddTargetVariableToScript1 #pragma mark - -rule AddDirectoryToContainer container : directoryTokens +rule AddDirectoryToContainer container : directoryTokens : attributeFiles { - # AddDirectoryToContainer : + # AddDirectoryToContainer : : local containerGrist = [ on $(container) return $(HAIKU_CONTAINER_GRIST) ] ; local directory = [ FDirName $(directoryTokens) ] ; @@ -121,6 +121,12 @@ rule AddDirectoryToContainer container : directoryTokens } } + if $(attributeFiles) { + SEARCH on $(attributeFiles) + += [ FDirName $(HAIKU_TOP) data image_directories ] ; + ATTRIBUTE_FILES on $(dir) += $(attributeFiles) ; + } + return $(directory) ; } @@ -699,18 +705,10 @@ rule IsUpdateHaikuImageOnly rule AddDirectoryToHaikuImage directoryTokens : attributeFiles { - # AddDirectoryToHaikuImage + # AddDirectoryToHaikuImage : - local dir = [ AddDirectoryToContainer $(HAIKU_IMAGE_CONTAINER_NAME) - : $(directoryTokens) ] ; - - if $(attributeFiles) { - SEARCH on $(attributeFiles) - += [ FDirName $(HAIKU_TOP) data image_directories ] ; - ATTRIBUTE_FILES on $(dir) += $(attributeFiles) ; - } - - return $(dir) ; + return [ AddDirectoryToContainer $(HAIKU_IMAGE_CONTAINER_NAME) + : $(directoryTokens) : $(attributeFiles) ] ; } rule AddFilesToHaikuImage directory : targets : destName diff --git a/build/jam/PackageRules b/build/jam/PackageRules index 1413209300..241878bbea 100644 --- a/build/jam/PackageRules +++ b/build/jam/PackageRules @@ -340,16 +340,8 @@ actions BuildHaikuPackage1 rule AddDirectoryToPackage package : directoryTokens : attributeFiles { - local dir = [ AddDirectoryToContainer $(package) : $(directoryTokens) ] ; - local grist = [ FHaikuPackageGrist $(package) ] ; - - if $(attributeFiles) { - SEARCH on $(attributeFiles) - += [ FDirName $(HAIKU_TOP) data package_directories $(grist) ] ; - ATTRIBUTE_FILES on $(dir) += $(attributeFiles) ; - } - - return $(dir) ; + return [ AddDirectoryToContainer $(package) + : $(directoryTokens) : $(attributeFiles) ] ; } From 2bda1e84fe48b888d799bea8aeae9b1ba3f8a77f Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 18 Jun 2011 02:19:53 +0200 Subject: [PATCH 0026/1170] Package rule: introduce current package notion The HaikuPackage rule now sets the variable HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE to the given package and all *ToPackage rules use that instead of a parameter. This saves passing the package in each of those rule invocations. --- build/jam/HaikuPackages | 278 ++++++++++++++++++---------------------- build/jam/PackageRules | 70 +++++----- 2 files changed, 160 insertions(+), 188 deletions(-) diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages index f96e77c539..d26edfc785 100644 --- a/build/jam/HaikuPackages +++ b/build/jam/HaikuPackages @@ -8,107 +8,92 @@ for driver in $(SYSTEM_ADD_ONS_DRIVERS_NET) { local archive = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_ARCHIVE) ] ; local extract = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_DO_EXTRACT) ] ; if $(archive) { - AddWifiFirmwareToPackage $(haikuPackage) : $(driver) : $(package) - : $(archive) : $(extract) ; + AddWifiFirmwareToPackage $(driver) : $(package) : $(archive) + : $(extract) ; } local packages = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_PACKAGES) ] ; local archives = [ on $(driver) return $(HAIKU_WIFI_FIRMWARE_ARCHIVES) ] ; for archive in $(archives) { - AddWifiFirmwareToPackage $(haikuPackage) : $(driver) : $(packages[1]) - : $(archive) : $(extract) ; + AddWifiFirmwareToPackage $(driver) : $(packages[1]) : $(archive) + : $(extract) ; packages = $(packages[2-]) ; } } # modules -AddFilesToPackage $(haikuPackage) : add-ons kernel bus_managers - : $(SYSTEM_ADD_ONS_BUS_MANAGERS) ; -AddFilesToPackage $(haikuPackage) : add-ons kernel busses agp_gart - : $(X86_ONLY)intel ; +AddFilesToPackage add-ons kernel bus_managers : $(SYSTEM_ADD_ONS_BUS_MANAGERS) ; +AddFilesToPackage add-ons kernel busses agp_gart : $(X86_ONLY)intel ; if $(HAIKU_ATA_STACK) = 1 { - AddFilesToPackage $(haikuPackage) : add-ons kernel busses ata + AddFilesToPackage add-ons kernel busses ata : generic_ide_pci it8211 legacy_sata silicon_image_3112 $(X86_ONLY)ide_isa ; } else { - AddFilesToPackage $(haikuPackage) : add-ons kernel busses ide + AddFilesToPackage add-ons kernel busses ide : generic_ide_pci it8211 legacy_sata silicon_image_3112 $(X86_ONLY)ide_isa ; } -AddFilesToPackage $(haikuPackage) : add-ons kernel busses scsi - : ahci ; -AddFilesToPackage $(haikuPackage) : add-ons kernel busses usb - : uhci ohci ehci ; -AddFilesToPackage $(haikuPackage) : add-ons kernel console - : vga_text ; -AddFilesToPackage $(haikuPackage) : add-ons kernel debugger +AddFilesToPackage add-ons kernel busses scsi : ahci ; +AddFilesToPackage add-ons kernel busses usb : uhci ohci ehci ; +AddFilesToPackage add-ons kernel console : vga_text ; +AddFilesToPackage add-ons kernel debugger : demangle $(X86_ONLY)disasm invalidate_on_exit usb_keyboard run_on_exit ; -AddFilesToPackage $(haikuPackage) : add-ons kernel file_systems - : $(SYSTEM_ADD_ONS_FILE_SYSTEMS) ; -AddFilesToPackage $(haikuPackage) : add-ons kernel generic +AddFilesToPackage add-ons kernel file_systems : $(SYSTEM_ADD_ONS_FILE_SYSTEMS) ; +AddFilesToPackage add-ons kernel generic : $(ATA_ONLY)ata_adapter dpc $(IDE_ONLY)ide_adapter locked_pool mpu401 scsi_periph tty ; -AddFilesToPackage $(haikuPackage) : add-ons kernel partitioning_systems +AddFilesToPackage add-ons kernel partitioning_systems : amiga_rdb apple efi_gpt intel session ; -AddFilesToPackage $(haikuPackage) : add-ons kernel interrupt_controllers - : $(PPC_ONLY)openpic ; +AddFilesToPackage add-ons kernel interrupt_controllers : $(PPC_ONLY)openpic ; if $(TARGET_ARCH) = x86 { - AddFilesToPackage $(haikuPackage) : add-ons kernel cpu : generic_x86 ; + AddFilesToPackage add-ons kernel cpu : generic_x86 ; } # drivers -AddNewDriversToPackage $(haikuPackage) : disk scsi : scsi_cd scsi_disk ; -AddNewDriversToPackage $(haikuPackage) : power : $(X86_ONLY)enhanced_speedstep ; -AddNewDriversToPackage $(haikuPackage) : power : $(X86_ONLY)acpi_battery ; +AddNewDriversToPackage disk scsi : scsi_cd scsi_disk ; +AddNewDriversToPackage power : $(X86_ONLY)enhanced_speedstep ; +AddNewDriversToPackage power : $(X86_ONLY)acpi_battery ; # legacy drivers -AddDriversToPackage $(haikuPackage) : - : console dprintf null random tty zero ; -AddDriversToPackage $(haikuPackage) : audio hmulti - : $(SYSTEM_ADD_ONS_DRIVERS_AUDIO) ; -AddDriversToPackage $(haikuPackage) : audio old - : $(SYSTEM_ADD_ONS_DRIVERS_AUDIO_OLD) ; -AddDriversToPackage $(haikuPackage) : midi - : $(SYSTEM_ADD_ONS_DRIVERS_MIDI) ; -AddDriversToPackage $(haikuPackage) : bus : usb_raw fw_raw ; -AddDriversToPackage $(haikuPackage) : disk floppy : $(X86_ONLY)pc_floppy ; -AddDriversToPackage $(haikuPackage) : disk usb : usb_disk ; -AddDriversToPackage $(haikuPackage) : disk usb : usb_floppy ; -AddDriversToPackage $(haikuPackage) : printer usb : usb_printer ; -AddDriversToPackage $(haikuPackage) : disk virtual : nbd ; -AddDriversToPackage $(haikuPackage) : dvb : cx23882 ; -AddDriversToPackage $(haikuPackage) : graphics - : $(SYSTEM_ADD_ONS_DRIVERS_GRAPHICS) ; -AddDriversToPackage $(haikuPackage) : input : ps2_hid usb_hid wacom ; -AddDriversToPackage $(haikuPackage) : misc : poke mem ; -AddDriversToPackage $(haikuPackage) : net - : $(SYSTEM_ADD_ONS_DRIVERS_NET) ; -AddDriversToPackage $(haikuPackage) : ports : usb_serial ; -#AddDriversToPackage $(haikuPackage) : power -# : $(SYSTEM_ADD_ONS_DRIVERS_POWER) ; +AddDriversToPackage : console dprintf null random tty + zero ; +AddDriversToPackage audio hmulti : $(SYSTEM_ADD_ONS_DRIVERS_AUDIO) ; +AddDriversToPackage audio old : $(SYSTEM_ADD_ONS_DRIVERS_AUDIO_OLD) ; +AddDriversToPackage midi : $(SYSTEM_ADD_ONS_DRIVERS_MIDI) ; +AddDriversToPackage bus : usb_raw fw_raw ; +AddDriversToPackage disk floppy : $(X86_ONLY)pc_floppy ; +AddDriversToPackage disk usb : usb_disk ; +AddDriversToPackage disk usb : usb_floppy ; +AddDriversToPackage printer usb : usb_printer ; +AddDriversToPackage disk virtual : nbd ; +AddDriversToPackage dvb : cx23882 ; +AddDriversToPackage graphics : $(SYSTEM_ADD_ONS_DRIVERS_GRAPHICS) ; +AddDriversToPackage input : ps2_hid usb_hid wacom ; +AddDriversToPackage misc : poke mem ; +AddDriversToPackage net : $(SYSTEM_ADD_ONS_DRIVERS_NET) ; +AddDriversToPackage ports : usb_serial ; +#AddDriversToPackage power : $(SYSTEM_ADD_ONS_DRIVERS_POWER) ; # kernel -AddFilesToPackage $(haikuPackage) : : kernel_$(TARGET_ARCH) ; +AddFilesToPackage : kernel_$(TARGET_ARCH) ; # libs -AddLibrariesToPackage $(haikuPackage) : lib - : $(SYSTEM_LIBS) $(PRIVATE_SYSTEM_LIBS) ; +AddLibrariesToPackage lib : $(SYSTEM_LIBS) $(PRIVATE_SYSTEM_LIBS) ; # libnetwork.so replaces quite a few libraries -SYSTEM_LIBS_LIBNETWORK_ALIASES - = libsocket.so libbind.so libnet.so ; +SYSTEM_LIBS_LIBNETWORK_ALIASES = libsocket.so libbind.so libnet.so ; if $(HAIKU_GCC_VERSION[1]) = 2 { local lib ; for lib in $(SYSTEM_LIBS_LIBNETWORK_ALIASES) { - AddSymlinkToPackage $(haikuPackage) : lib : libnetwork.so : $(lib) ; + AddSymlinkToPackage lib : libnetwork.so : $(lib) ; } - AddSymlinkToPackage $(haikuPackage) : lib : libbnetapi.so : libnetapi.so ; + AddSymlinkToPackage lib : libbnetapi.so : libnetapi.so ; } @@ -119,7 +104,7 @@ SYSTEM_LIBS_LIBGL_ALIASES if $(TARGET_ARCH) = x86 { local lib ; for lib in $(SYSTEM_LIBS_LIBGL_ALIASES) { - AddSymlinkToPackage $(haikuPackage) : lib : libGL.so : $(lib) ; + AddSymlinkToPackage lib : libGL.so : $(lib) ; } } @@ -130,108 +115,102 @@ SYSTEM_LIBS_ALIASES = ; # servers -AddFilesToPackage $(haikuPackage) : servers : $(SYSTEM_SERVERS) ; +AddFilesToPackage servers : $(SYSTEM_SERVERS) ; # apps -AddFilesToPackage $(haikuPackage) : : runtime_loader ; -AddFilesToPackage $(haikuPackage) : : Deskbar Tracker ; -AddFilesToPackage $(haikuPackage) : bin : $(SYSTEM_BIN) consoled ; -AddFilesToPackage $(haikuPackage) : apps : $(SYSTEM_APPS) ; -AddFilesToPackage $(haikuPackage) : preferences : $(SYSTEM_PREFERENCES) ; -AddFilesToPackage $(haikuPackage) : demos : $(SYSTEM_DEMOS) ; +AddFilesToPackage : runtime_loader ; +AddFilesToPackage : Deskbar Tracker ; +AddFilesToPackage bin : $(SYSTEM_BIN) consoled ; +AddFilesToPackage apps : $(SYSTEM_APPS) ; +AddFilesToPackage preferences : $(SYSTEM_PREFERENCES) ; +AddFilesToPackage demos : $(SYSTEM_DEMOS) ; SEARCH on which = [ FDirName $(HAIKU_TOP) data bin ] ; -AddFilesToPackage $(haikuPackage) : bin : which ; +AddFilesToPackage bin : which ; SEARCH on installoptionalpackage = [ FDirName $(HAIKU_TOP) data bin ] ; -AddFilesToPackage $(haikuPackage) : bin : installoptionalpackage ; +AddFilesToPackage bin : installoptionalpackage ; SEARCH on install-wifi-firmwares.sh = [ FDirName $(HAIKU_TOP) data bin ] ; -AddFilesToPackage $(haikuPackage) : bin : install-wifi-firmwares.sh ; +AddFilesToPackage bin : install-wifi-firmwares.sh ; -AddSymlinkToPackage $(haikuPackage) : bin : bash : sh ; -AddSymlinkToPackage $(haikuPackage) : bin : trash : untrash ; +AddSymlinkToPackage bin : bash : sh ; +AddSymlinkToPackage bin : trash : untrash ; -AddSymlinkToPackage $(haikuPackage) : bin : bzip2 : bunzip2 ; -AddSymlinkToPackage $(haikuPackage) : bin : less : more ; -AddSymlinkToPackage $(haikuPackage) : bin : gzip : gunzip ; -AddSymlinkToPackage $(haikuPackage) : bin : gzip : zcat ; -AddSymlinkToPackage $(haikuPackage) : bin : zdiff : zcmp ; -AddSymlinkToPackage $(haikuPackage) : bin : unzip : zipinfo ; -AddSymlinkToPackage $(haikuPackage) : bin : gawk : awk ; -AddSymlinkToPackage $(haikuPackage) : bin : grep : egrep ; -AddSymlinkToPackage $(haikuPackage) : bin : grep : fgrep ; +AddSymlinkToPackage bin : bzip2 : bunzip2 ; +AddSymlinkToPackage bin : less : more ; +AddSymlinkToPackage bin : gzip : gunzip ; +AddSymlinkToPackage bin : gzip : zcat ; +AddSymlinkToPackage bin : zdiff : zcmp ; +AddSymlinkToPackage bin : unzip : zipinfo ; +AddSymlinkToPackage bin : gawk : awk ; +AddSymlinkToPackage bin : grep : egrep ; +AddSymlinkToPackage bin : grep : fgrep ; # scripts and data files local bootScripts = Bootscript Bootscript.cd SetupEnvironment Netscript InstallerInitScript InstallerFinishScript ; SEARCH on $(bootScripts) = [ FDirName $(HAIKU_TOP) data system boot ] ; -AddFilesToPackage $(haikuPackage) : boot : $(bootScripts) ; +AddFilesToPackage boot : $(bootScripts) ; # artwork and sounds local logoArtwork = $(HAIKU_INCLUDE_TRADEMARKS)"HAIKU logo - white on blue - big.png" $(HAIKU_INCLUDE_TRADEMARKS)"HAIKU logo - white on blue - normal.png" ; SEARCH on $(logoArtwork) = [ FDirName $(HAIKU_TOP) data artwork ] ; -AddFilesToPackage $(haikuPackage) : data artwork : $(logoArtwork) ; +AddFilesToPackage data artwork : $(logoArtwork) ; -AddDirectoryToPackage $(haikuPackage) : data sounds ; +AddDirectoryToPackage data sounds ; # Mail spell check dictionaries local spellFiles = words geekspeak ; spellFiles = $(spellFiles:G=spell) ; SEARCH on $(spellFiles) = [ FDirName $(HAIKU_TOP) src apps mail ] ; -AddFilesToPackage $(haikuPackage) : data spell_check word_dictionary - : $(spellFiles) ; +AddFilesToPackage data spell_check word_dictionary : $(spellFiles) ; local dataFiles = teapot.data ; dataFiles = $(dataFiles:G=data) ; SEARCH on $(dataFiles) = [ FDirName $(HAIKU_TOP) data system data ] ; -AddFilesToPackage $(haikuPackage) : data : $(dataFiles) ; +AddFilesToPackage data : $(dataFiles) ; local fortuneFiles = [ Glob $(HAIKU_TOP)/data/system/data/fortunes : [a-zA-Z0-9]* ] ; fortuneFiles = $(fortuneFiles:G=data!fortunes) ; -AddFilesToPackage $(haikuPackage) : data fortunes : $(fortuneFiles) ; +AddFilesToPackage data fortunes : $(fortuneFiles) ; local fontDir = [ FDirName $(HAIKU_TOP) data system data fonts ] ; local psFonts = [ Glob $(fontDir)/psfonts : *.afm *.pfb ] ; local ttFonts = [ Glob $(fontDir)/ttfonts : *.ttf ] ; -AddFilesToPackage $(haikuPackage) : data fonts psfonts : $(psFonts) ; -AddFilesToPackage $(haikuPackage) : data fonts ttfonts : $(ttFonts) ; +AddFilesToPackage data fonts psfonts : $(psFonts) ; +AddFilesToPackage data fonts ttfonts : $(ttFonts) ; local cannaDir = [ FDirName $(HAIKU_TOP) data system data Canna ] ; local cannaDefault = [ Glob $(cannaDir)/default : *.canna *.gz ] ; local cannaDic = [ Glob $(cannaDir)/dic : *.cbp ] ; local cannaDicCanna = [ Glob $(cannaDir)/dic/canna : *.cld *.ctd *.cbd *.dir ] ; -AddFilesToPackage $(haikuPackage) : data Canna default - : $(cannaDefault) ; -AddFilesToPackage $(haikuPackage) : data Canna dic : $(cannaDic) ; -AddFilesToPackage $(haikuPackage) : data Canna dic canna - : $(cannaDicCanna) ; -AddDirectoryToPackage $(haikuPackage) : data Canna dic group ; -AddDirectoryToPackage $(haikuPackage) : data Canna dic user ; +AddFilesToPackage data Canna default : $(cannaDefault) ; +AddFilesToPackage data Canna dic : $(cannaDic) ; +AddFilesToPackage data Canna dic canna : $(cannaDicCanna) ; +AddDirectoryToPackage data Canna dic group ; +AddDirectoryToPackage data Canna dic user ; local keymapFiles = [ Glob [ FDirName $(HAIKU_TOP) src data keymaps ] : *.keymap ] ; keymapFiles = $(keymapFiles:BG=keymap) ; -AddFilesToPackage $(haikuPackage) : data Keymaps : $(keymapFiles) ; -AddSymlinkToPackage $(haikuPackage) : data Keymaps : Swedish - : Finnish ; -AddSymlinkToPackage $(haikuPackage) : data Keymaps : Slovene - : Croatian ; -AddSymlinkToPackage $(haikuPackage) : data Keymaps : US-International - : Brazilian ; +AddFilesToPackage data Keymaps : $(keymapFiles) ; +AddSymlinkToPackage data Keymaps : Swedish : Finnish ; +AddSymlinkToPackage data Keymaps : Slovene : Croatian ; +AddSymlinkToPackage data Keymaps : US-International : Brazilian ; local keyboardLayoutsDir = [ FDirName $(HAIKU_TOP) data system data KeyboardLayouts ] ; local keyboardLayouts = [ Glob $(keyboardLayoutsDir) : [^.]* ] ; -AddFilesToPackage $(haikuPackage) : data KeyboardLayouts : $(keyboardLayouts) ; +AddFilesToPackage data KeyboardLayouts : $(keyboardLayouts) ; # boot loader -AddFilesToPackage $(haikuPackage) : : haiku_loader ; +AddFilesToPackage : haiku_loader ; # boot module links -AddBootModuleSymlinksToPackage $(haikuPackage) : +AddBootModuleSymlinksToPackage $(X86_ONLY)acpi $(ATA_ONLY)ata pci $(X86_ONLY)isa config_manager dpc $(IDE_ONLY)ide scsi usb $(PPC_ONLY)openpic @@ -245,88 +224,75 @@ AddBootModuleSymlinksToPackage $(haikuPackage) : ; # add-ons -AddFilesToPackage $(haikuPackage) : add-ons accelerants - : $(SYSTEM_ADD_ONS_ACCELERANTS) ; -AddFilesToPackage $(haikuPackage) : add-ons opengl - : Mesa\ Software\ Renderer ; -AddFilesToPackage $(haikuPackage) : add-ons Translators - : $(SYSTEM_ADD_ONS_TRANSLATORS) ; -AddFilesToPackage $(haikuPackage) : add-ons locale catalogs - : $(SYSTEM_ADD_ONS_LOCALE_CATALOGS) ; -AddFilesToPackage $(haikuPackage) : add-ons locale catalogs - : $(SYSTEM_ADD_ONS_LOCALE_CATALOGS) ; -AddFilesToPackage $(haikuPackage) : add-ons mail_daemon inbound_protocols - : POP3 IMAP ; -AddFilesToPackage $(haikuPackage) : add-ons mail_daemon outbound_protocols - : SMTP ; -AddFilesToPackage $(haikuPackage) : add-ons mail_daemon inbound_filters +AddFilesToPackage add-ons accelerants : $(SYSTEM_ADD_ONS_ACCELERANTS) ; +AddFilesToPackage add-ons opengl : Mesa\ Software\ Renderer ; +AddFilesToPackage add-ons Translators : $(SYSTEM_ADD_ONS_TRANSLATORS) ; +AddFilesToPackage add-ons locale catalogs : $(SYSTEM_ADD_ONS_LOCALE_CATALOGS) ; + +AddFilesToPackage add-ons mail_daemon inbound_protocols : POP3 IMAP ; +AddFilesToPackage add-ons mail_daemon outbound_protocols : SMTP ; +AddFilesToPackage add-ons mail_daemon inbound_filters : MatchHeader SpamFilter NewMailNotification ; -AddFilesToPackage $(haikuPackage) : add-ons mail_daemon outbound_filters - : Fortune ; -AddFilesToPackage $(haikuPackage) : add-ons media : $(SYSTEM_ADD_ONS_MEDIA) ; -AddFilesToPackage $(haikuPackage) : add-ons media plugins - : $(SYSTEM_ADD_ONS_MEDIA_PLUGINS) ; -AddFilesToPackage $(haikuPackage) : add-ons Tracker +AddFilesToPackage add-ons mail_daemon outbound_filters : Fortune ; + +AddFilesToPackage add-ons media : $(SYSTEM_ADD_ONS_MEDIA) ; +AddFilesToPackage add-ons media plugins : $(SYSTEM_ADD_ONS_MEDIA_PLUGINS) ; +AddFilesToPackage add-ons Tracker : FileType-F Mark\ as… Mark\ as\ Read-R Open\ Target\ Folder-O - Open\ Terminal-T ZipOMatic-Z ; -AddSymlinkToPackage $(haikuPackage) : add-ons Tracker + Open\ Terminal-T ZipOMatic-Z ; +AddSymlinkToPackage add-ons Tracker : /boot/system/preferences/Backgrounds : Background-B ; -AddSymlinkToPackage $(haikuPackage) : add-ons Tracker +AddSymlinkToPackage add-ons Tracker : /boot/system/apps/TextSearch : TextSearch-G ; -AddSymlinkToPackage $(haikuPackage) : add-ons Tracker +AddSymlinkToPackage add-ons Tracker : /boot/system/apps/DiskUsage : DiskUsage-I ; -AddFilesToPackage $(haikuPackage) : add-ons input_server devices +AddFilesToPackage add-ons input_server devices : keyboard mouse tablet wacom ; -AddFilesToPackage $(haikuPackage) : add-ons input_server filters +AddFilesToPackage add-ons input_server filters : screen_saver shortcut_catcher ; -AddFilesToPackage $(haikuPackage) : add-ons kernel network +AddFilesToPackage add-ons kernel network : notifications stack ; -AddFilesToPackage $(haikuPackage) : add-ons kernel network devices +AddFilesToPackage add-ons kernel network devices : $(SYSTEM_NETWORK_DEVICES) ; -AddFilesToPackage $(haikuPackage) : add-ons kernel network datalink_protocols +AddFilesToPackage add-ons kernel network datalink_protocols : $(SYSTEM_NETWORK_DATALINK_PROTOCOLS) ; -AddFilesToPackage $(haikuPackage) : add-ons kernel network ppp - : $(SYSTEM_NETWORK_PPP) ; -AddFilesToPackage $(haikuPackage) : add-ons kernel network protocols +AddFilesToPackage add-ons kernel network ppp: $(SYSTEM_NETWORK_PPP) ; +AddFilesToPackage add-ons kernel network protocols : $(SYSTEM_NETWORK_PROTOCOLS) ; -AddFilesToPackage $(haikuPackage) : add-ons Print - : $(SYSTEM_ADD_ONS_PRINT) ; -AddFilesToPackage $(haikuPackage) : add-ons Print transport +AddFilesToPackage add-ons Print : $(SYSTEM_ADD_ONS_PRINT) ; +AddFilesToPackage add-ons Print transport : $(SYSTEM_ADD_ONS_PRINT_TRANSPORT) ; -AddFilesToPackage $(haikuPackage) : add-ons Screen\ Savers - : $(SYSTEM_ADD_ONS_SCREENSAVERS) ; +AddFilesToPackage add-ons Screen\ Savers : $(SYSTEM_ADD_ONS_SCREENSAVERS) ; -AddFilesToPackage $(haikuPackage) : add-ons disk_systems - : intel bfs ; +AddFilesToPackage add-ons disk_systems : intel bfs ; -AddDirectoryToPackage $(haikuPackage) : data synth ; -AddDirectoryToPackage $(haikuPackage) : add-ons input_server methods ; +AddDirectoryToPackage data synth ; +AddDirectoryToPackage add-ons input_server methods ; # optional -# TODO: We should probably build another package that can be installed, if -# desired. -AddFilesToPackage $(haikuPackage) : optional add-ons input_server methods - : canna ; +# TODO: We should probably build another package (including the data files +# above) that can be installed, if desired. +AddFilesToPackage optional add-ons input_server methods : canna ; # PDF Writer enconding files -CopyDirectoryToPackage $(haikuPackage) : data +CopyDirectoryToPackage data : [ FDirName $(HAIKU_TOP) src add-ons print drivers pdf encoding ] : "PDF Writer" : -x .svn -x Jamfile ; # licenses -CopyDirectoryToPackage $(haikuPackage) : data +CopyDirectoryToPackage data : [ FDirName $(HAIKU_TOP) data system data licenses ] : licenses : -x .svn ; # Copy documentation as per DiskUsage's license requirement. -CopyDirectoryToPackage $(haikuPackage) : documentation +CopyDirectoryToPackage documentation : [ FDirName $(HAIKU_TOP) docs apps diskusage ] : diskusage : -x .svn ; # Copy documentation as per PDFlib Lite's license requirement. -CopyDirectoryToPackage $(haikuPackage) : documentation +CopyDirectoryToPackage documentation : [ FDirName $(HAIKU_TOP) src libs pdflib doc ] : pdflib : -x .svn ; diff --git a/build/jam/PackageRules b/build/jam/PackageRules index 241878bbea..00a998bbe8 100644 --- a/build/jam/PackageRules +++ b/build/jam/PackageRules @@ -272,6 +272,8 @@ rule HaikuPackage package = $(grist)_HAIKU_INCLUDE_IN_PACKAGE ; HAIKU_INSTALL_TARGETS_VAR on $(package) = $(grist)_HAIKU_PACKAGE_INSTALL_TARGETS ; + + HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE = $(package) ; } @@ -338,81 +340,85 @@ actions BuildHaikuPackage1 } -rule AddDirectoryToPackage package : directoryTokens : attributeFiles +rule AddDirectoryToPackage directoryTokens : attributeFiles { - return [ AddDirectoryToContainer $(package) + return [ AddDirectoryToContainer $(HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE) : $(directoryTokens) : $(attributeFiles) ] ; } -rule AddFilesToPackage package : directory : targets : destName +rule AddFilesToPackage directory : targets : destName { - AddFilesToContainer $(package) : $(directory) : $(targets) : $(destName) ; + AddFilesToContainer $(HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE) : $(directory) + : $(targets) : $(destName) ; } -rule AddSymlinkToPackage package : directoryTokens : linkTarget : linkName +rule AddSymlinkToPackage directoryTokens : linkTarget : linkName { linkTarget = $(linkTarget:J=/) ; - AddSymlinkToContainer $(package) : $(directoryTokens) : $(linkTarget) - : $(linkName) ; + AddSymlinkToContainer $(HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE) + : $(directoryTokens) : $(linkTarget) : $(linkName) ; } -rule CopyDirectoryToPackage package : directoryTokens : sourceDirectory +rule CopyDirectoryToPackage directoryTokens : sourceDirectory : targetDirectoryName : excludePatterns : alwaysUpdate { - CopyDirectoryToContainer $(package) : $(directoryTokens) - : $(sourceDirectory) : $(targetDirectoryName) : $(excludePatterns) - : $(alwaysUpdate) ; + CopyDirectoryToContainer $(HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE) + : $(directoryTokens) : $(sourceDirectory) : $(targetDirectoryName) + : $(excludePatterns) : $(alwaysUpdate) ; } -rule AddHeaderDirectoryToPackage package : dirTokens : dirName : alwaysUpdate +rule AddHeaderDirectoryToPackage dirTokens : dirName : alwaysUpdate { - AddHeaderDirectoryToContainer $(package) : $(dirTokens) : $(dirName) - : $(alwaysUpdate) ; + AddHeaderDirectoryToContainer $(HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE) + : $(dirTokens) : $(dirName) : $(alwaysUpdate) ; } -rule AddWifiFirmwareToPackage package : driver : subDirToExtract : archive +rule AddWifiFirmwareToPackage driver : subDirToExtract : archive : extract { - AddWifiFirmwareToContainer $(package) : $(driver) : $(subDirToExtract) - : $(archive) : $(extract) ; + AddWifiFirmwareToContainer $(HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE) + : $(driver) : $(subDirToExtract) : $(archive) : $(extract) ; } -rule ExtractArchiveToPackage package : dirTokens : archiveFile : alwaysUpdate +rule ExtractArchiveToPackage dirTokens : archiveFile : alwaysUpdate : extractedSubDir { # TODO: Update support? - ExtractArchiveToContainer $(package) : $(dirTokens) : $(archiveFile) - : $(extractedSubDir) ; + ExtractArchiveToContainer $(HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE) + : $(dirTokens) : $(archiveFile) : $(extractedSubDir) ; } -rule AddDriversToPackage package : relativeDirectoryTokens : targets +rule AddDriversToPackage relativeDirectoryTokens : targets { - AddDriversToContainer $(package) : $(relativeDirectoryTokens) : $(targets) ; + AddDriversToContainer $(HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE) + : $(relativeDirectoryTokens) : $(targets) ; } -rule AddNewDriversToPackage package : relativeDirectoryTokens : targets +rule AddNewDriversToPackage relativeDirectoryTokens : targets { - AddNewDriversToContainer $(package) : $(relativeDirectoryTokens) + AddNewDriversToContainer $(HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE) + : $(relativeDirectoryTokens) : $(targets) ; +} + + +rule AddBootModuleSymlinksToPackage targets +{ + AddBootModuleSymlinksToContainer $(HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE) : $(targets) ; } -rule AddBootModuleSymlinksToPackage package : targets +rule AddLibrariesToPackage directory : libs { - AddBootModuleSymlinksToContainer $(package) : $(targets) ; -} - - -rule AddLibrariesToPackage package : directory : libs -{ - AddLibrariesToContainer $(package) : $(directory) : $(libs) ; + AddLibrariesToContainer $(HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE) + : $(directory) : $(libs) ; } From 624b7c8958748bfdbf85da86488c6f94d1370b7b Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 18 Jun 2011 02:48:38 +0200 Subject: [PATCH 0027/1170] Add system package to image --- build/jam/HaikuImage | 3 +++ 1 file changed, 3 insertions(+) diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 26d1af4565..32d3a04edb 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -195,8 +195,11 @@ SYSTEM_ADD_ONS_FILE_SYSTEMS = bfs bindfs btrfs cdda exfat ext2 fat iso9660 nfs attribute_overlay write_overlay ntfs packagefs reiserfs udf googlefs ; +# build the haiku system package and add it include [ FDirName $(HAIKU_BUILD_RULES_DIR) HaikuPackages ] ; +AddFilesToHaikuImage system packages : haiku.hpkg ; + # TODO: remove! # Add the files to be used by installoptionalpackage. From d11ea2b5edf78d1018b1149a57a593af50687920 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 18 Jun 2011 04:23:09 +0200 Subject: [PATCH 0028/1170] Introduce BootVolume abstraction class BootVolume is initialized from a root directory of a volume. It finds the system directory, and -- not implemented yet -- mounts the system package, if the system is packaged, replacing the system directory with it. Adjusted several functionality (main(), the loader functions, user_menu()) to use BootVolume instead of the root directory. --- headers/private/kernel/boot/vfs.h | 32 ++++++++- src/system/boot/loader/loader.cpp | 44 +++++++++--- src/system/boot/loader/loader.h | 6 +- src/system/boot/loader/main.cpp | 23 +++--- src/system/boot/loader/menu.cpp | 8 +-- src/system/boot/loader/menu.h | 3 +- src/system/boot/loader/vfs.cpp | 114 +++++++++++++++++++++++++----- 7 files changed, 182 insertions(+), 48 deletions(-) diff --git a/headers/private/kernel/boot/vfs.h b/headers/private/kernel/boot/vfs.h index b937582ee2..60d7d2bd4e 100644 --- a/headers/private/kernel/boot/vfs.h +++ b/headers/private/kernel/boot/vfs.h @@ -99,11 +99,41 @@ class MemoryDisk : public Node { }; +class BootVolume { +public: + BootVolume(); + ~BootVolume(); + + status_t SetTo(Directory* rootDirectory); + void Unset(); + + bool IsValid() const + { return fRootDirectory != NULL; } + + Directory* RootDirectory() const + { return fRootDirectory; } + Directory* SystemDirectory() const + { return fSystemDirectory; } + bool IsPackaged() const + { return fPackaged; } + +private: + Directory* fRootDirectory; + // root directory of the volume + Directory* fSystemDirectory; + // "system" directory of the volume; if packaged the root + // directory of the mounted packagefs + bool fPackaged; + // indicates whether the boot volume's system is packaged +}; + + /* function prototypes */ extern status_t vfs_init(stage2_args *args); extern status_t register_boot_file_system(Directory *directory); -extern Directory *get_boot_file_system(stage2_args *args); +extern status_t get_boot_file_system(stage2_args* args, + BootVolume& _bootVolume); extern status_t mount_file_systems(stage2_args *args); extern int open_node(Node *node, int mode); extern int open_from(Directory *directory, const char *path, int mode, diff --git a/src/system/boot/loader/loader.cpp b/src/system/boot/loader/loader.cpp index 1137285a16..0436908d33 100644 --- a/src/system/boot/loader/loader.cpp +++ b/src/system/boot/loader/loader.cpp @@ -24,8 +24,12 @@ # error BOOT_ARCH has to be defined to differentiate the kernel per platform #endif +#define SYSTEM_DIRECTORY_PREFIX "system/" #define KERNEL_IMAGE "kernel_" BOOT_ARCH -#define KERNEL_PATH "system/" KERNEL_IMAGE +#define KERNEL_PATH SYSTEM_DIRECTORY_PREFIX KERNEL_IMAGE + + +static const char* const kSystemDirectoryPrefix = SYSTEM_DIRECTORY_PREFIX; static const char *sPaths[] = { @@ -38,15 +42,32 @@ static const char *sPaths[] = { }; +static int +open_maybe_packaged(BootVolume& volume, const char* path, int openMode) +{ + if (strncmp(path, kSystemDirectoryPrefix, strlen(kSystemDirectoryPrefix)) + == 0) { + path += strlen(kSystemDirectoryPrefix); + return open_from(volume.SystemDirectory(), path, openMode); + } + + return open_from(volume.RootDirectory(), path, openMode); +} + + bool is_bootable(Directory *volume) { if (volume->IsEmpty()) return false; + BootVolume bootVolume; + if (bootVolume.SetTo(volume) != B_OK) + return false; + // check for the existance of a kernel (for our platform) - int fd = open_from(volume, KERNEL_PATH, O_RDONLY); - if (fd < B_OK) + int fd = open_maybe_packaged(bootVolume, KERNEL_PATH, O_RDONLY); + if (fd < 0) return false; close(fd); @@ -56,9 +77,9 @@ is_bootable(Directory *volume) status_t -load_kernel(stage2_args *args, Directory *volume) +load_kernel(stage2_args* args, BootVolume& volume) { - int fd = open_from(volume, KERNEL_PATH, O_RDONLY); + int fd = open_maybe_packaged(volume, KERNEL_PATH, O_RDONLY); if (fd < B_OK) return fd; @@ -87,11 +108,11 @@ load_kernel(stage2_args *args, Directory *volume) static status_t -load_modules_from(Directory *volume, const char *path) +load_modules_from(BootVolume& volume, const char* path) { // we don't have readdir() & co. (yet?)... - int fd = open_from(volume, path, O_RDONLY); + int fd = open_maybe_packaged(volume, path, O_RDONLY); if (fd < B_OK) return fd; @@ -125,7 +146,7 @@ load_modules_from(Directory *volume, const char *path) */ static status_t -load_module(Directory *volume, const char *name) +load_module(BootVolume& volume, const char* name) { char moduleName[B_FILE_NAME_LENGTH]; if (strlcpy(moduleName, name, sizeof(moduleName)) > sizeof(moduleName)) @@ -133,7 +154,7 @@ load_module(Directory *volume, const char *name) for (int32 i = 0; sPaths[i]; i++) { // get base path - int baseFD = open_from(volume, sPaths[i], O_RDONLY); + int baseFD = open_maybe_packaged(volume, sPaths[i], O_RDONLY); if (baseFD < B_OK) continue; @@ -174,7 +195,7 @@ load_module(Directory *volume, const char *name) status_t -load_modules(stage2_args *args, Directory *volume) +load_modules(stage2_args* args, BootVolume& volume) { int32 failed = 0; @@ -209,7 +230,8 @@ load_modules(stage2_args *args, Directory *volume) false)) { // iterate over the mounted volumes and load their file system Partition *partition; - if (gRoot->GetPartitionFor(volume, &partition) == B_OK) { + if (gRoot->GetPartitionFor(volume.RootDirectory(), &partition) + == B_OK) { while (partition != NULL) { load_module(volume, partition->ModuleName()); partition = partition->Parent(); diff --git a/src/system/boot/loader/loader.h b/src/system/boot/loader/loader.h index 126eec875a..ea441f3a34 100644 --- a/src/system/boot/loader/loader.h +++ b/src/system/boot/loader/loader.h @@ -9,8 +9,8 @@ #include -extern bool is_bootable(Directory *volume); -extern status_t load_kernel(stage2_args *args, Directory *volume); -extern status_t load_modules(stage2_args *args, Directory *volume); +extern bool is_bootable(Directory* volume); +extern status_t load_kernel(stage2_args* args, BootVolume& volume); +extern status_t load_modules(stage2_args* args, BootVolume& volume); #endif /* LOADER_H */ diff --git a/src/system/boot/loader/main.cpp b/src/system/boot/loader/main.cpp index bc67e3a9ab..309df34cd5 100644 --- a/src/system/boot/loader/main.cpp +++ b/src/system/boot/loader/main.cpp @@ -57,10 +57,11 @@ main(stage2_args *args) bool mountedAllVolumes = false; - Directory *volume = get_boot_file_system(args); + BootVolume bootVolume; - if (volume == NULL || (platform_boot_options() & BOOT_OPTION_MENU) != 0) { - if (volume == NULL) + if (get_boot_file_system(args, bootVolume) != B_OK + || (platform_boot_options() & BOOT_OPTION_MENU) != 0) { + if (!bootVolume.IsValid()) puts("\tno boot path found, scan for all partitions...\n"); if (mount_file_systems(args) < B_OK) { @@ -73,19 +74,19 @@ main(stage2_args *args) mountedAllVolumes = true; - if (user_menu(&volume) < B_OK) { + if (user_menu(bootVolume) < B_OK) { // user requested to quit the loader goto out; } } - if (volume != NULL) { + if (bootVolume.IsValid()) { // we got a volume to boot from! status_t status; - while ((status = load_kernel(args, volume)) < B_OK) { + while ((status = load_kernel(args, bootVolume)) < B_OK) { // loading the kernel failed, so let the user choose another // volume to boot from until it works - volume = NULL; + bootVolume.Unset(); if (!mountedAllVolumes) { // mount all other file systems, if not already happened @@ -95,7 +96,7 @@ main(stage2_args *args) mountedAllVolumes = true; } - if (user_menu(&volume) < B_OK || volume == NULL) { + if (user_menu(bootVolume) < B_OK || !bootVolume.IsValid()) { // user requested to quit the loader goto out; } @@ -105,13 +106,13 @@ main(stage2_args *args) // is already loaded at this point and we definitely // know our boot volume, too if (status == B_OK) { - register_boot_file_system(volume); + register_boot_file_system(bootVolume.RootDirectory()); if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) == 0) platform_switch_to_logo(); - load_modules(args, volume); - load_driver_settings(args, volume); + load_modules(args, bootVolume); + load_driver_settings(args, bootVolume.RootDirectory()); // apply boot settings apply_boot_settings(); diff --git a/src/system/boot/loader/menu.cpp b/src/system/boot/loader/menu.cpp index 3c2ae22df8..b2c8c19cfc 100644 --- a/src/system/boot/loader/menu.cpp +++ b/src/system/boot/loader/menu.cpp @@ -960,7 +960,7 @@ user_menu_reboot(Menu* menu, MenuItem* item) status_t -user_menu(Directory** _bootVolume) +user_menu(BootVolume& _bootVolume) { Menu* menu = new(std::nothrow) Menu(MAIN_MENU); Menu* safeModeMenu = NULL; @@ -973,7 +973,7 @@ user_menu(Directory** _bootVolume) // Add boot volume menu->AddItem(item = new(std::nothrow) MenuItem("Select boot volume", - add_boot_volume_menu(*_bootVolume))); + add_boot_volume_menu(_bootVolume.RootDirectory()))); // Add safe mode menu->AddItem(item = new(std::nothrow) MenuItem("Select safe mode options", @@ -993,7 +993,7 @@ user_menu(Directory** _bootVolume) item->SetShortcut('r'); menu->AddItem(item = new(std::nothrow) MenuItem("Continue booting")); - if (*_bootVolume == NULL) { + if (!_bootVolume.IsValid()) { item->SetEnabled(false); menu->ItemAt(0)->Select(true); } else @@ -1003,7 +1003,7 @@ user_menu(Directory** _bootVolume) // See if a new boot device has been selected, and propagate that back if (item->Data() != NULL) - *_bootVolume = (Directory*)item->Data(); + _bootVolume.SetTo((Directory*)item->Data()); apply_safe_mode_options(safeModeMenu); apply_safe_mode_options(debugMenu); diff --git a/src/system/boot/loader/menu.h b/src/system/boot/loader/menu.h index b6343e21ff..a400952fd1 100644 --- a/src/system/boot/loader/menu.h +++ b/src/system/boot/loader/menu.h @@ -9,6 +9,7 @@ #include -extern status_t user_menu(Directory **_bootVolume); +extern status_t user_menu(BootVolume& _bootVolume); + #endif /* MENU_H */ diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp index 2d532309c0..188df09b95 100644 --- a/src/system/boot/loader/vfs.cpp +++ b/src/system/boot/loader/vfs.cpp @@ -357,6 +357,77 @@ Descriptor::Release() // #pragma mark - +BootVolume::BootVolume() + : + fRootDirectory(NULL), + fSystemDirectory(NULL), + fPackaged(false) +{ +} + + +BootVolume::~BootVolume() +{ + Unset(); +} + + +status_t +BootVolume::SetTo(Directory* rootDirectory) +{ + Unset(); + + if (rootDirectory == NULL) + return B_BAD_VALUE; + + fRootDirectory = rootDirectory; + + // find the system directory + Node* systemNode = fRootDirectory->Lookup("system", true); + if (systemNode == NULL || !S_ISDIR(systemNode->Type())) { + if (systemNode != NULL) + systemNode->Release(); + Unset(); + return B_ENTRY_NOT_FOUND; + } + + fSystemDirectory = static_cast(systemNode); + + // check, if the system is packaged + int packageFD = open_from(fSystemDirectory, , + O_RDONLY); + fPackaged = packageFD >= 0; + if (!fPackaged) + return B_OK; + + // the system is packaged -- mount the packagefs +// TODO:... +Unset(); +dprintf("BootVolume::SetTo(): packagefs not supported yet!\n"); +return B_NOT_SUPPORTED; +} + + +void +BootVolume::Unset() +{ + if (fRootDirectory != NULL) { + fRootDirectory->Release(); + fRootDirectory = NULL; + } + + if (fSystemDirectory != NULL) { + fSystemDirectory->Release(); + fSystemDirectory = NULL; + } + + fPackaged = false; +} + + +// #pragma mark - + + status_t vfs_init(stage2_args *args) { @@ -393,41 +464,50 @@ register_boot_file_system(Directory *volume) } -/** Gets the boot device, scans all of its partitions, gets the - * boot partition, and mounts its file system. - * Returns the file system's root node or NULL for failure. - */ +/*! Gets the boot device, scans all of its partitions, gets the + boot partition, and mounts its file system. -Directory * -get_boot_file_system(stage2_args *args) + \param args The stage 2 arguments. + \param _bootVolume On success set to the boot volume. + \return \c B_OK on success, another error code otherwise. +*/ +status_t +get_boot_file_system(stage2_args* args, BootVolume& _bootVolume) { Node *device; - if (platform_add_boot_device(args, &gBootDevices) < B_OK) - return NULL; + status_t error = platform_add_boot_device(args, &gBootDevices); + if (error != B_OK) + return error; // the boot device must be the first device in the list device = gBootDevices.First(); - if (add_partitions_for(device, false, true) < B_OK) - return NULL; + error = add_partitions_for(device, false, true); + if (error != B_OK) + return error; Partition *partition; - if (platform_get_boot_partition(args, device, &gPartitions, &partition) < B_OK) - return NULL; + error = platform_get_boot_partition(args, device, &gPartitions, &partition); + if (error != B_OK) + return error; Directory *fileSystem; - status_t status = partition->Mount(&fileSystem, true); - - if (status < B_OK) { + error = partition->Mount(&fileSystem, true); + if (error != B_OK) { // this partition doesn't contain any known file system; we // don't need it anymore gPartitions.Remove(partition); delete partition; - return NULL; + return error; } + // init the BootVolume + error = _bootVolume.SetTo(fileSystem); + if (error != B_OK) + return error; + sBootDevice = device; - return fileSystem; + return B_OK; } From 8f583b27712d4c742f7d0f1123d968b8e8b868df Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 18 Jun 2011 05:13:25 +0200 Subject: [PATCH 0029/1170] Build fix --- src/system/boot/loader/vfs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp index 188df09b95..a3e2801719 100644 --- a/src/system/boot/loader/vfs.cpp +++ b/src/system/boot/loader/vfs.cpp @@ -394,7 +394,7 @@ BootVolume::SetTo(Directory* rootDirectory) fSystemDirectory = static_cast(systemNode); // check, if the system is packaged - int packageFD = open_from(fSystemDirectory, , + int packageFD = open_from(fSystemDirectory, "packages/haiku.hpkg", O_RDONLY); fPackaged = packageFD >= 0; if (!fPackaged) From 898396ef61056cb047741a3fbc5533b418a65666 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 13:41:05 +0200 Subject: [PATCH 0030/1170] Increase boot loader heap size We need more for packagefs support. --- src/system/boot/platform/bios_ia32/start.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/system/boot/platform/bios_ia32/start.cpp b/src/system/boot/platform/bios_ia32/start.cpp index 6af13dd6da..90dc88e3bd 100644 --- a/src/system/boot/platform/bios_ia32/start.cpp +++ b/src/system/boot/platform/bios_ia32/start.cpp @@ -28,7 +28,8 @@ #include "smp.h" -#define HEAP_SIZE (128 * 1024) +#define HEAP_SIZE (512 * 1024) + // GCC defined globals extern void (*__ctor_list)(void); From abc3c57ba68a10c5754a2dd2bc91a7e378e75f13 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 13:43:24 +0200 Subject: [PATCH 0031/1170] KernelLd rule: opt-out linking against libsupc++ Introduced HAIKU_NO_LIBSUPC++ variable on target to prevent linking against libsupc++. --- build/jam/KernelRules | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/build/jam/KernelRules b/build/jam/KernelRules index f0dba32319..25b2260bf1 100644 --- a/build/jam/KernelRules +++ b/build/jam/KernelRules @@ -44,8 +44,13 @@ rule KernelLd LINKFLAGS on $(1) = $(4) ; if $(3) { LINKFLAGS on $(1) += --script=$(3) ; } - # Remove any preset LINKLIBS, but link against libgcc.a - LINKLIBS on $(1) = $(TARGET_STATIC_LIBSUPC++) $(TARGET_GCC_LIBGCC) ; + # Remove any preset LINKLIBS, but link against libgcc.a. Linking against + # libsupc++ is opt-out. + local libs ; + if ! [ on $(1) return HAIKU_NO_LIBSUPC++ ] { + libs += $(TARGET_STATIC_LIBSUPC++) ; + } + LINKLIBS on $(1) = $(libs) $(TARGET_GCC_LIBGCC) ; # TODO: Do we really want to invoke SetupKernel here? The objects should # have been compiled with KernelObjects anyway, so we're doing that twice. From 9a8c1339ce802a820347b72eb509039affa9e96c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 13:46:51 +0200 Subject: [PATCH 0032/1170] Split package kit DataReader.cpp Pull AttributeDataReader and FDDataReader implementations out of DataReader.cpp into own source files. Thus we can avoid dependencies (e.g. to fs_attr code) we don't need/want. --- .../kernel/file_systems/packagefs/Jamfile | 1 + src/build/libpackage/Jamfile | 2 + src/kits/package/Jamfile | 2 + src/kits/package/hpkg/AttributeDataReader.cpp | 42 ++++++++++++++++ src/kits/package/hpkg/DataReader.cpp | 50 +------------------ src/kits/package/hpkg/FDDataReader.cpp | 37 ++++++++++++++ 6 files changed, 85 insertions(+), 49 deletions(-) create mode 100644 src/kits/package/hpkg/AttributeDataReader.cpp create mode 100644 src/kits/package/hpkg/FDDataReader.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index 48a331eab6..c38e91f350 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -35,6 +35,7 @@ HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES = DataOutput.cpp DataReader.cpp ErrorOutput.cpp + FDDataReader.cpp PackageContentHandler.cpp PackageData.cpp PackageDataReader.cpp diff --git a/src/build/libpackage/Jamfile b/src/build/libpackage/Jamfile index e0ef43b062..1e0a27919c 100644 --- a/src/build/libpackage/Jamfile +++ b/src/build/libpackage/Jamfile @@ -19,6 +19,7 @@ USES_BE_API on libpackage_build.so = true ; HPKG_SOURCES = + AttributeDataReader.cpp BlockBufferCache.cpp BlockBufferCacheImpl.cpp BufferCache.cpp @@ -26,6 +27,7 @@ HPKG_SOURCES = DataOutput.cpp DataReader.cpp ErrorOutput.cpp + FDDataReader.cpp PackageContentHandler.cpp PackageData.cpp PackageDataReader.cpp diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile index bf1df812cf..ab7a44ed93 100644 --- a/src/kits/package/Jamfile +++ b/src/kits/package/Jamfile @@ -9,6 +9,7 @@ UsePrivateHeaders SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ; HPKG_SOURCES = + AttributeDataReader.cpp BlockBufferCache.cpp BlockBufferCacheImpl.cpp BufferCache.cpp @@ -16,6 +17,7 @@ HPKG_SOURCES = DataOutput.cpp DataReader.cpp ErrorOutput.cpp + FDDataReader.cpp PackageContentHandler.cpp PackageData.cpp PackageDataReader.cpp diff --git a/src/kits/package/hpkg/AttributeDataReader.cpp b/src/kits/package/hpkg/AttributeDataReader.cpp new file mode 100644 index 0000000000..62911af847 --- /dev/null +++ b/src/kits/package/hpkg/AttributeDataReader.cpp @@ -0,0 +1,42 @@ +/* + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include + +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +BAttributeDataReader::BAttributeDataReader(int fd, const char* attribute, + uint32 type) + : + fFD(fd), + fType(type), + fAttribute(attribute) +{ +} + + +status_t +BAttributeDataReader::ReadData(off_t offset, void* buffer, size_t size) +{ + ssize_t bytesRead = fs_read_attr(fFD, fAttribute, fType, offset, buffer, + size); + if (bytesRead < 0) + return errno; + return (size_t)bytesRead == size ? B_OK : B_ERROR; +} + + +} // namespace BHPKG + +} // namespace BPackageKit diff --git a/src/kits/package/hpkg/DataReader.cpp b/src/kits/package/hpkg/DataReader.cpp index 2d2999c54d..cd7b0db4df 100644 --- a/src/kits/package/hpkg/DataReader.cpp +++ b/src/kits/package/hpkg/DataReader.cpp @@ -1,16 +1,12 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #include -#include #include -#include - -#include namespace BPackageKit { @@ -26,50 +22,6 @@ BDataReader::~BDataReader() } -// #pragma mark - BFDDataReader - - -BFDDataReader::BFDDataReader(int fd) - : - fFD(fd) -{ -} - - -status_t -BFDDataReader::ReadData(off_t offset, void* buffer, size_t size) -{ - ssize_t bytesRead = pread(fFD, buffer, size, offset); - if (bytesRead < 0) - return errno; - return (size_t)bytesRead == size ? B_OK : B_ERROR; -} - - -// #pragma mark - BAttributeDataReader - - -BAttributeDataReader::BAttributeDataReader(int fd, const char* attribute, - uint32 type) - : - fFD(fd), - fType(type), - fAttribute(attribute) -{ -} - - -status_t -BAttributeDataReader::ReadData(off_t offset, void* buffer, size_t size) -{ - ssize_t bytesRead = fs_read_attr(fFD, fAttribute, fType, offset, buffer, - size); - if (bytesRead < 0) - return errno; - return (size_t)bytesRead == size ? B_OK : B_ERROR; -} - - // #pragma mark - BBufferDataReader diff --git a/src/kits/package/hpkg/FDDataReader.cpp b/src/kits/package/hpkg/FDDataReader.cpp new file mode 100644 index 0000000000..c0ce13e921 --- /dev/null +++ b/src/kits/package/hpkg/FDDataReader.cpp @@ -0,0 +1,37 @@ +/* + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include + +#include +#include + + +namespace BPackageKit { + +namespace BHPKG { + + +BFDDataReader::BFDDataReader(int fd) + : + fFD(fd) +{ +} + + +status_t +BFDDataReader::ReadData(off_t offset, void* buffer, size_t size) +{ + ssize_t bytesRead = pread(fFD, buffer, size, offset); + if (bytesRead < 0) + return errno; + return (size_t)bytesRead == size ? B_OK : B_ERROR; +} + + +} // namespace BHPKG + +} // namespace BPackageKit From 2ef572b8fef32cd2a2201b4be563270858ae1b24 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 13:58:42 +0200 Subject: [PATCH 0033/1170] ReaderImplBase::ParseStrings(): Avoid new[0] --- src/kits/package/hpkg/ReaderImplBase.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/kits/package/hpkg/ReaderImplBase.cpp b/src/kits/package/hpkg/ReaderImplBase.cpp index d7cb3e95af..c10b5e0fda 100644 --- a/src/kits/package/hpkg/ReaderImplBase.cpp +++ b/src/kits/package/hpkg/ReaderImplBase.cpp @@ -569,7 +569,12 @@ ReaderImplBase::CheckCompression(const SectionInfo& section) const status_t ReaderImplBase::ParseStrings() { - // allocate table + // allocate table, if there are any strings + if (fCurrentSection->stringsCount == 0) { + fCurrentSection->currentOffset += fCurrentSection->stringsLength; + return B_OK; + } + fCurrentSection->strings = new(std::nothrow) char*[fCurrentSection->stringsCount]; if (fCurrentSection->strings == NULL) { From b232be5a4773acadb1957fc609f73430c13e4821 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 14:05:11 +0200 Subject: [PATCH 0034/1170] Boot loader build: add strerror,... * Don't link against libsupc++ anymore. We use kernel_cpp.* instead. * Link twice against boot_loader.a, so undefined symbols in FSs are resolved. --- src/system/boot/Jamfile | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/src/system/boot/Jamfile b/src/system/boot/Jamfile index ad8d151046..3845fd1313 100644 --- a/src/system/boot/Jamfile +++ b/src/system/boot/Jamfile @@ -17,6 +17,7 @@ local librootFunctions = strncmp.o strcat.o strcpy.o + strerror.o strlcat.o strlcpy.o strchr.o @@ -31,6 +32,9 @@ if $(HAIKU_BOARD_LOADER_BASE) { AddResources haiku_loader : boot_loader.rdef ; +# don't link against libsupc++ +HAIKU_NO_LIBSUPC++ on boot_loader_$(TARGET_BOOT_PLATFORM) = true ; + KernelLd boot_loader_$(TARGET_BOOT_PLATFORM) : boot_platform_$(TARGET_BOOT_PLATFORM).o boot_arch_$(TARGET_ARCH).o @@ -43,8 +47,13 @@ KernelLd boot_loader_$(TARGET_BOOT_PLATFORM) : boot_amiga_ffs.a boot_tarfs.a boot_fatfs.a + boot_packagefs.a - # needed by tarfs and video_splash.cpp + boot_loader.a + # a second time, so undefined references in the file systems can be + # resolved + + # needed by tarfs, packagefs, and video_splash.cpp boot_zlib.a # libroot functions needed by the stage2 boot loader (compiled for the From 305722379690bb207e9cfd76e8cf8d081bbaa5e9 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 14:07:53 +0200 Subject: [PATCH 0035/1170] Add BReferenceable to boot loader Also force include kernel_cpp.h, so it doesn't have to be included in every file (still is included in most, though). --- src/system/boot/loader/Jamfile | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/src/system/boot/loader/Jamfile b/src/system/boot/loader/Jamfile index 671ca94580..aaced732b2 100644 --- a/src/system/boot/loader/Jamfile +++ b/src/system/boot/loader/Jamfile @@ -10,7 +10,7 @@ UsePrivateHeaders [ FDirName kernel util ] ; UsePrivateHeaders shared storage ; { - local defines = + DEFINES += _BOOT_MODE BOOT_ARCH=\\\"$(TARGET_ARCH)\\\" KMESSAGE_CONTAINER_ONLY @@ -28,7 +28,7 @@ UsePrivateHeaders shared storage ; switch $(TARGET_ARCH) { case "ppc" : { - defines += + DEFINES += BOOT_SUPPORT_PARTITION_AMIGA BOOT_SUPPORT_PARTITION_APPLE @@ -37,7 +37,7 @@ UsePrivateHeaders shared storage ; } case "x86" : { - defines += + DEFINES += BOOT_SUPPORT_PARTITION_EFI #BOOT_SUPPORT_FILE_SYSTEM_FAT @@ -45,11 +45,13 @@ UsePrivateHeaders shared storage ; } } - defines = [ FDefines $(defines) ] ; - SubDirCcFlags $(defines) ; - SubDirC++Flags $(defines) -fno-rtti ; + local kernelC++Header = [ FDirName $(HAIKU_TOP) headers private kernel util + kernel_cpp.h ] ; + + SubDirC++Flags -fno-rtti -include $(kernelC++Header) ; } + KernelStaticLibrary boot_loader : elf.cpp heap.cpp @@ -75,6 +77,8 @@ KernelStaticLibrary boot_loader : ring_buffer.cpp safemode_settings.cpp + Referenceable.cpp + : -fno-pic ; @@ -120,6 +124,9 @@ SEARCH on [ FGristFiles intel.cpp PartitionMap.cpp PartitionMapParser.cpp ] SEARCH on [ FGristFiles stage2_crt0.S ] = [ FDirName $(HAIKU_TOP) src system boot arch $(TARGET_ARCH) ] ; +SEARCH on [ FGristFiles Referenceable.cpp ] + = [ FDirName $(HAIKU_TOP) src kits support ] ; + SubInclude HAIKU_TOP src system boot loader file_systems ; SubInclude HAIKU_TOP src system boot loader net ; From cbc85916fb5c35022ba6e52eb5b55a93271b1fb6 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 14:20:04 +0200 Subject: [PATCH 0036/1170] Add boot loader packagefs support * Add pread(). * Add Node::ReadLink() to read a symbolic link path. * Add Directory::LookupDontTraverse() and make Lookup() non-abstract. Lookup() is implemented via LookupDontTraverse() and Node::ReadLink(). * Adjust all FS implementations accordingly. * Add a packagefs implementation. Unlike other FS implementations it isn't a pseudo-module, but provides a function to explicitly mount a package file (packagefs_mount_file()). * Finish BootVolume::SetTo() implementation, mounting the package file and replacing fSystemDirectory. Now the boot loader can load the kernel and boot modules from a packaged system. The kernel boots up to the point where the boot volume is mounted. --- headers/private/kernel/boot/vfs.h | 11 +- src/system/boot/loader/RootFileSystem.cpp | 22 +- src/system/boot/loader/RootFileSystem.h | 2 +- src/system/boot/loader/file_systems/Jamfile | 1 + .../file_systems/amiga_ffs/Directory.cpp | 14 +- .../loader/file_systems/amiga_ffs/Directory.h | 2 +- .../loader/file_systems/bfs/Directory.cpp | 45 +- .../boot/loader/file_systems/bfs/Directory.h | 2 +- .../boot/loader/file_systems/bfs/Link.h | 3 +- .../loader/file_systems/fat/Directory.cpp | 6 +- .../boot/loader/file_systems/fat/Directory.h | 2 +- .../loader/file_systems/packagefs/Jamfile | 46 + .../file_systems/packagefs/packagefs.cpp | 807 ++++++++++++++++++ .../loader/file_systems/packagefs/packagefs.h | 27 + .../boot/loader/file_systems/tarfs/tarfs.cpp | 32 +- src/system/boot/loader/vfs.cpp | 67 +- 16 files changed, 1006 insertions(+), 83 deletions(-) create mode 100644 src/system/boot/loader/file_systems/packagefs/Jamfile create mode 100644 src/system/boot/loader/file_systems/packagefs/packagefs.cpp create mode 100644 src/system/boot/loader/file_systems/packagefs/packagefs.h diff --git a/headers/private/kernel/boot/vfs.h b/headers/private/kernel/boot/vfs.h index 60d7d2bd4e..e936160498 100644 --- a/headers/private/kernel/boot/vfs.h +++ b/headers/private/kernel/boot/vfs.h @@ -26,8 +26,12 @@ class Node : public DoublyLinkedListLinkImpl { virtual status_t Open(void **_cookie, int mode); virtual status_t Close(void *cookie); - virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize) = 0; - virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize) = 0; + virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, + size_t bufferSize) = 0; + virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, + size_t bufferSize) = 0; + + virtual status_t ReadLink(char* buffer, size_t bufferSize); virtual status_t GetName(char *nameBuffer, size_t bufferSize) const; virtual status_t GetFileMap(struct file_map_run *runs, int32 *count); @@ -55,7 +59,8 @@ class Directory : public Node { virtual int32 Type() const; - virtual Node *Lookup(const char *name, bool traverseLinks) = 0; + virtual Node* Lookup(const char* name, bool traverseLinks); + virtual Node* LookupDontTraverse(const char* name) = 0; virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize) = 0; virtual status_t GetNextNode(void *cookie, Node **_node) = 0; diff --git a/src/system/boot/loader/RootFileSystem.cpp b/src/system/boot/loader/RootFileSystem.cpp index 441f5a1765..955eb4f50b 100644 --- a/src/system/boot/loader/RootFileSystem.cpp +++ b/src/system/boot/loader/RootFileSystem.cpp @@ -29,7 +29,7 @@ RootFileSystem::~RootFileSystem() } -status_t +status_t RootFileSystem::Open(void **_cookie, int mode) { EntryIterator *iterator = new (std::nothrow) EntryIterator(&fList); @@ -42,7 +42,7 @@ RootFileSystem::Open(void **_cookie, int mode) } -status_t +status_t RootFileSystem::Close(void *cookie) { delete (EntryIterator *)cookie; @@ -50,8 +50,8 @@ RootFileSystem::Close(void *cookie) } -Node * -RootFileSystem::Lookup(const char *name, bool /*traverseLinks*/) +Node* +RootFileSystem::LookupDontTraverse(const char* name) { EntryIterator iterator = fLinks.GetIterator(); struct entry *entry; @@ -84,7 +84,7 @@ RootFileSystem::Lookup(const char *name, bool /*traverseLinks*/) } -status_t +status_t RootFileSystem::GetNextEntry(void *_cookie, char *name, size_t size) { EntryIterator *iterator = (EntryIterator *)_cookie; @@ -98,7 +98,7 @@ RootFileSystem::GetNextEntry(void *_cookie, char *name, size_t size) } -status_t +status_t RootFileSystem::GetNextNode(void *_cookie, Node **_node) { EntryIterator *iterator = (EntryIterator *)_cookie; @@ -113,24 +113,24 @@ RootFileSystem::GetNextNode(void *_cookie, Node **_node) } -status_t +status_t RootFileSystem::Rewind(void *_cookie) { EntryIterator *iterator = (EntryIterator *)_cookie; iterator->Rewind(); - return B_OK; + return B_OK; } -bool +bool RootFileSystem::IsEmpty() { return fList.IsEmpty(); } -status_t +status_t RootFileSystem::AddVolume(Directory *volume, Partition *partition) { struct entry *entry = new (std::nothrow) RootFileSystem::entry(); @@ -165,7 +165,7 @@ RootFileSystem::AddLink(const char *name, Directory *target) } -status_t +status_t RootFileSystem::GetPartitionFor(Directory *volume, Partition **_partition) { EntryIterator iterator = fList.GetIterator(); diff --git a/src/system/boot/loader/RootFileSystem.h b/src/system/boot/loader/RootFileSystem.h index e1adfc434e..6ce33de903 100644 --- a/src/system/boot/loader/RootFileSystem.h +++ b/src/system/boot/loader/RootFileSystem.h @@ -20,7 +20,7 @@ class RootFileSystem : public Directory { virtual status_t Open(void **_cookie, int mode); virtual status_t Close(void *cookie); - virtual Node *Lookup(const char *name, bool traverseLinks); + virtual Node* LookupDontTraverse(const char* name); virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize); virtual status_t GetNextNode(void *cookie, Node **_node); diff --git a/src/system/boot/loader/file_systems/Jamfile b/src/system/boot/loader/file_systems/Jamfile index 49109c75ec..9af1c649fb 100644 --- a/src/system/boot/loader/file_systems/Jamfile +++ b/src/system/boot/loader/file_systems/Jamfile @@ -4,4 +4,5 @@ SubInclude HAIKU_TOP src system boot loader file_systems amiga_ffs ; SubInclude HAIKU_TOP src system boot loader file_systems bfs ; SubInclude HAIKU_TOP src system boot loader file_systems fat ; SubInclude HAIKU_TOP src system boot loader file_systems hfs_plus ; +SubInclude HAIKU_TOP src system boot loader file_systems packagefs ; SubInclude HAIKU_TOP src system boot loader file_systems tarfs ; diff --git a/src/system/boot/loader/file_systems/amiga_ffs/Directory.cpp b/src/system/boot/loader/file_systems/amiga_ffs/Directory.cpp index c299717118..bec052fd93 100644 --- a/src/system/boot/loader/file_systems/amiga_ffs/Directory.cpp +++ b/src/system/boot/loader/file_systems/amiga_ffs/Directory.cpp @@ -45,14 +45,14 @@ Directory::~Directory() } -status_t +status_t Directory::InitCheck() { return fNode.ValidateCheckSum(); } -status_t +status_t Directory::Open(void **_cookie, int mode) { _inherited::Open(_cookie, mode); @@ -71,7 +71,7 @@ Directory::Open(void **_cookie, int mode) } -status_t +status_t Directory::Close(void *cookie) { _inherited::Close(cookie); @@ -81,8 +81,8 @@ Directory::Close(void *cookie) } -Node * -Directory::Lookup(const char *name, bool traverseLinks) +Node* +Directory::LookupDontTraverse(const char* name) { if (!strcmp(name, ".")) { Acquire(); @@ -113,7 +113,7 @@ Directory::Lookup(const char *name, bool traverseLinks) } -status_t +status_t Directory::GetNextEntry(void *cookie, char *name, size_t size) { HashIterator *iterator = (HashIterator *)cookie; @@ -127,7 +127,7 @@ Directory::GetNextEntry(void *cookie, char *name, size_t size) } -status_t +status_t Directory::GetNextNode(void *cookie, Node **_node) { return B_ERROR; diff --git a/src/system/boot/loader/file_systems/amiga_ffs/Directory.h b/src/system/boot/loader/file_systems/amiga_ffs/Directory.h index bed55f8f32..4ba2aeb7dc 100644 --- a/src/system/boot/loader/file_systems/amiga_ffs/Directory.h +++ b/src/system/boot/loader/file_systems/amiga_ffs/Directory.h @@ -27,7 +27,7 @@ class Directory : public ::Directory { virtual status_t Open(void **_cookie, int mode); virtual status_t Close(void *cookie); - virtual Node *Lookup(const char *name, bool traverseLinks); + virtual Node* LookupDontTraverse(const char* name); virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize); virtual status_t GetNextNode(void *cookie, Node **_node); diff --git a/src/system/boot/loader/file_systems/bfs/Directory.cpp b/src/system/boot/loader/file_systems/bfs/Directory.cpp index 91fe02ffab..705e598c81 100644 --- a/src/system/boot/loader/file_systems/bfs/Directory.cpp +++ b/src/system/boot/loader/file_systems/bfs/Directory.cpp @@ -52,14 +52,14 @@ Directory::~Directory() } -status_t +status_t Directory::InitCheck() { return fStream.InitCheck(); } -status_t +status_t Directory::Open(void **_cookie, int mode) { _inherited::Open(_cookie, mode); @@ -72,7 +72,7 @@ Directory::Open(void **_cookie, int mode) } -status_t +status_t Directory::Close(void *cookie) { _inherited::Close(cookie); @@ -82,43 +82,18 @@ Directory::Close(void *cookie) } -Node * -Directory::Lookup(const char *name, bool traverseLinks) +Node* +Directory::LookupDontTraverse(const char* name) { off_t id; if (fTree.Find((uint8 *)name, strlen(name), &id) < B_OK) return NULL; - Node *node = Stream::NodeFactory(fStream.GetVolume(), id); - if (!node) - return NULL; - - if (S_ISLNK(node->Type())) { - // the node is a symbolic link, so we have to resolve the path - char linkPath[B_PATH_NAME_LENGTH]; - ((Link *)node)->ReadLink(linkPath, sizeof(linkPath)); - - delete node; - // we don't need this one anymore - - int fd = open_from(this, linkPath, O_RDONLY); - if (fd >= 0) { - node = get_node_from(fd); - if (node != NULL) - node->Acquire(); - - close(fd); - return node; - } - - return NULL; - } - - return node; + return Stream::NodeFactory(fStream.GetVolume(), id); } -status_t +status_t Directory::GetNextEntry(void *cookie, char *name, size_t size) { TreeIterator *iterator = (TreeIterator *)cookie; @@ -129,7 +104,7 @@ Directory::GetNextEntry(void *cookie, char *name, size_t size) } -status_t +status_t Directory::GetNextNode(void *cookie, Node **_node) { TreeIterator *iterator = (TreeIterator *)cookie; @@ -149,7 +124,7 @@ Directory::GetNextNode(void *cookie, Node **_node) } -status_t +status_t Directory::Rewind(void *cookie) { TreeIterator *iterator = (TreeIterator *)cookie; @@ -158,7 +133,7 @@ Directory::Rewind(void *cookie) } -bool +bool Directory::IsEmpty() { TreeIterator iterator(&fTree); diff --git a/src/system/boot/loader/file_systems/bfs/Directory.h b/src/system/boot/loader/file_systems/bfs/Directory.h index 4645b8154c..8d625477fb 100644 --- a/src/system/boot/loader/file_systems/bfs/Directory.h +++ b/src/system/boot/loader/file_systems/bfs/Directory.h @@ -27,7 +27,7 @@ class Directory : public ::Directory { virtual status_t Open(void **_cookie, int mode); virtual status_t Close(void *cookie); - virtual Node *Lookup(const char *name, bool traverseLinks); + virtual Node* LookupDontTraverse(const char* name); virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize); virtual status_t GetNextNode(void *cookie, Node **_node); diff --git a/src/system/boot/loader/file_systems/bfs/Link.h b/src/system/boot/loader/file_systems/bfs/Link.h index 167bfa07d6..f648be0b8a 100644 --- a/src/system/boot/loader/file_systems/bfs/Link.h +++ b/src/system/boot/loader/file_systems/bfs/Link.h @@ -20,7 +20,8 @@ class Link : public File { Link(const Stream &stream); status_t InitCheck(); - status_t ReadLink(char *buffer, size_t bufferSize); + + virtual status_t ReadLink(char *buffer, size_t bufferSize); virtual ssize_t ReadAt(void *cookie, off_t pos, void *buffer, size_t bufferSize); virtual ssize_t WriteAt(void *cookie, off_t pos, const void *buffer, size_t bufferSize); diff --git a/src/system/boot/loader/file_systems/fat/Directory.cpp b/src/system/boot/loader/file_systems/fat/Directory.cpp index f1e56e6f5a..ff152d6384 100644 --- a/src/system/boot/loader/file_systems/fat/Directory.cpp +++ b/src/system/boot/loader/file_systems/fat/Directory.cpp @@ -351,10 +351,10 @@ Directory::Close(void *cookie) } -Node * -Directory::Lookup(const char *name, bool traverseLinks) +Node* +Directory::LookupDontTraverse(const char* name) { - TRACE(("FASFS::Directory::%s('%s', %d)\n", __FUNCTION__, name, traverseLinks)); + TRACE(("FASFS::Directory::%s('%s')\n", __FUNCTION__, name)); if (!strcmp(name, ".")) { Acquire(); return this; diff --git a/src/system/boot/loader/file_systems/fat/Directory.h b/src/system/boot/loader/file_systems/fat/Directory.h index 5bb10d560e..bb400420cd 100644 --- a/src/system/boot/loader/file_systems/fat/Directory.h +++ b/src/system/boot/loader/file_systems/fat/Directory.h @@ -31,7 +31,7 @@ class Directory : public ::Directory { virtual status_t Open(void **_cookie, int mode); virtual status_t Close(void *cookie); - virtual Node *Lookup(const char *name, bool traverseLinks); + virtual Node* LookupDontTraverse(const char* name); virtual status_t GetNextEntry(void *cookie, char *nameBuffer, size_t bufferSize); virtual status_t GetNextNode(void *cookie, Node **_node); diff --git a/src/system/boot/loader/file_systems/packagefs/Jamfile b/src/system/boot/loader/file_systems/packagefs/Jamfile new file mode 100644 index 0000000000..807c67c24e --- /dev/null +++ b/src/system/boot/loader/file_systems/packagefs/Jamfile @@ -0,0 +1,46 @@ +SubDir HAIKU_TOP src system boot loader file_systems packagefs ; + +UsePrivateHeaders [ FDirName kernel boot platform $(TARGET_BOOT_PLATFORM) ] ; +UsePrivateHeaders kernel shared ; +SubDirSysHdrs $(HAIKU_TOP) headers libs zlib ; + +DEFINES += _BOOT_MODE ; + +local kernelC++Header = [ FDirName $(HAIKU_TOP) headers private kernel util + kernel_cpp.h ] ; + +SubDirC++Flags -fno-rtti -include $(kernelC++Header) ; + +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package ] ; +SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ; + + +KernelStaticLibrary boot_packagefs : + packagefs.cpp + + # package kit + BlockBufferCacheNoLock.cpp + + # package kit/hpkg + BlockBufferCache.cpp + BlockBufferCacheImpl.cpp + BufferCache.cpp + CachedBuffer.cpp + DataOutput.cpp + DataReader.cpp + ErrorOutput.cpp + FDDataReader.cpp + PackageContentHandler.cpp + PackageData.cpp + PackageDataReader.cpp + PackageEntry.cpp + PackageEntryAttribute.cpp + PackageReaderImpl.cpp + ReaderImplBase.cpp + + # compression + ZlibCompressionBase.cpp + ZlibDecompressor.cpp + + : -fno-pic +; diff --git a/src/system/boot/loader/file_systems/packagefs/packagefs.cpp b/src/system/boot/loader/file_systems/packagefs/packagefs.cpp new file mode 100644 index 0000000000..eb6abc7f92 --- /dev/null +++ b/src/system/boot/loader/file_systems/packagefs/packagefs.cpp @@ -0,0 +1,807 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "packagefs.h" + +#include +#include + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include + +#include + + +#if 0 +# define RETURN_ERROR(error) return (error); +#else +# define RETURN_ERROR(err) \ + { \ + status_t _status = err; \ + if (_status < B_OK) \ + dprintf("%s:%d: %s\n", __FILE__, __LINE__, strerror(_status)); \ + return _status; \ + } +#endif + + +using namespace BPackageKit; +using namespace BPackageKit::BHPKG; +using BPackageKit::BHPKG::BPrivate::PackageReaderImpl; + + +namespace { + + +struct PackageDirectory; +struct PackageNode; +struct PackageVolume; + + +static status_t create_node(PackageNode* packageNode, ::Node*& _node); + + +// #pragma mark - PackageNode + + +struct PackageNode : DoublyLinkedListLinkImpl { + PackageNode(PackageVolume* volume, mode_t mode) + : + fVolume(volume), + fParentDirectory(NULL), + fName(NULL), + fMode(mode) + { + fModifiedTime.tv_sec = 0; + fModifiedTime.tv_nsec = 0; + } + + ~PackageNode() + { + free(fName); + } + + status_t Init(PackageDirectory* parentDir, const char* name) + { + fParentDirectory = parentDir; + fName = strdup(name); + + return fName != NULL ? B_OK : B_NO_MEMORY; + } + + PackageVolume* Volume() const + { + return fVolume; + } + + const char* Name() const + { + return fName; + } + + mode_t Mode() const + { + return fMode; + } + + void SetModifiedTime(const timespec& time) + { + fModifiedTime = time; + } + + const timespec& ModifiedTime() const + { + return fModifiedTime; + } + +protected: + PackageVolume* fVolume; + PackageDirectory* fParentDirectory; + char* fName; + mode_t fMode; + timespec fModifiedTime; +}; + + +// #pragma mark - PackageFile + + +struct PackageFile : PackageNode { + PackageFile(PackageVolume* volume, mode_t mode, const BPackageData& data) + : + PackageNode(volume, mode), + fData(data) + { + } + + const BPackageData& Data() const + { + return fData; + } + + off_t Size() const + { + return fData.UncompressedSize(); + } + +private: + BPackageData fData; +}; + + +// #pragma mark - PackageSymlink + + +struct PackageSymlink : PackageNode { + PackageSymlink(PackageVolume* volume, mode_t mode) + : + PackageNode(volume, mode), + fPath(NULL) + { + } + + ~PackageSymlink() + { + free(fPath); + } + + status_t SetSymlinkPath(const char* path) + { + fPath = strdup(path); + return fPath != NULL ? B_OK : B_NO_MEMORY; + } + + const char* SymlinkPath() const + { + return fPath; + } + +private: + char* fPath; +}; + + +// #pragma mark - PackageDirectory + + +struct PackageDirectory : PackageNode { + PackageDirectory(PackageVolume* volume, mode_t mode) + : + PackageNode(volume, mode) + { + } + + void AddChild(PackageNode* node) + { + fEntries.Add(node); + } + + PackageNode* FirstChild() const + { + return fEntries.Head(); + } + + PackageNode* NextChild(PackageNode* child) const + { + return fEntries.GetNext(child); + } + + PackageNode* Lookup(const char* name) const + { + for (NodeList::ConstIterator it = fEntries.GetIterator(); + PackageNode* child = it.Next();) { + if (strcmp(child->Name(), name) == 0) + return child; + } + + return NULL; + } + +private: + typedef DoublyLinkedList NodeList; + +private: + NodeList fEntries; +}; + + +// #pragma mark - FileDataReader + + +struct FileDataReader { + FileDataReader(int fd, const BPackageData& data) + : + fDataReader(fd), + fData(data), + fPackageDataReader(NULL) + { + } + + ~FileDataReader() + { + delete fPackageDataReader; + } + + status_t Init(BPackageDataReaderFactory* dataReaderFactory) + { + if (fData.IsEncodedInline()) + return B_OK; + + return dataReaderFactory->CreatePackageDataReader(&fDataReader, + fData, fPackageDataReader); + } + + status_t ReadData(off_t offset, void* buffer, size_t bufferSize) + { + if (fData.IsEncodedInline()) { + BBufferDataReader dataReader(fData.InlineData(), + fData.CompressedSize()); + return dataReader.ReadData(offset, buffer, bufferSize); + } + + return fPackageDataReader->ReadData(offset, buffer, bufferSize); + } + +private: + BFDDataReader fDataReader; + BPackageData fData; + BPackageDataReader* fPackageDataReader; +}; + + +// #pragma mark - PackageVolume + + +struct PackageVolume : BReferenceable { + PackageVolume() + : + fRootDirectory(this, S_IFDIR), + fBufferCache(B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB, 2), + fDataReaderFactory(&fBufferCache), + fFD(-1) + { + } + + ~PackageVolume() + { + if (fFD >= 0) + close(fFD); + } + + status_t Init(int fd) + { + status_t error = fBufferCache.Init(); + if (error != B_OK) + return error; + + fFD = dup(fd); + if (fFD < 0) + return errno; + + return B_OK; + } + + PackageDirectory* RootDirectory() + { + return &fRootDirectory; + } + + void AddNode(PackageNode* node) + { + fRootDirectory.AddChild(node); + } + + status_t CreateFileDataReader(const BPackageData& data, + FileDataReader*& _fileDataReader) + { + // create the file reader object + FileDataReader* fileDataReader = new(std::nothrow) FileDataReader(fFD, + data); + if (fileDataReader == NULL) + return B_NO_MEMORY; + ObjectDeleter fileDataReaderDeleter(fileDataReader); + + status_t error = fileDataReader->Init(&fDataReaderFactory); + if (error != B_OK) + return error; + + _fileDataReader = fileDataReaderDeleter.Detach(); + return B_OK; + } + +private: + PackageDirectory fRootDirectory; + BBlockBufferCacheNoLock fBufferCache; + BPackageDataReaderFactory fDataReaderFactory; + int fFD; +}; + + +// #pragma mark - PackageLoaderErrorOutput + + +struct PackageLoaderErrorOutput : BErrorOutput { + PackageLoaderErrorOutput() + { + } + + virtual void PrintErrorVarArgs(const char* format, va_list args) + { + } +}; + + +// #pragma mark - PackageLoaderContentHandler + + +struct PackageLoaderContentHandler : BPackageContentHandler { + PackageLoaderContentHandler(PackageVolume* volume) + : + fVolume(volume), + fErrorOccurred(false) + { + } + + status_t Init() + { + return B_OK; + } + + virtual status_t HandleEntry(BPackageEntry* entry) + { + if (fErrorOccurred) + return B_OK; + + PackageDirectory* parentDir = NULL; + if (const BPackageEntry* parentEntry = entry->Parent()) { + if (!S_ISDIR(parentEntry->Mode())) + RETURN_ERROR(B_BAD_DATA); + + parentDir = static_cast( + (PackageNode*)parentEntry->UserToken()); + } + + status_t error; + + // get the file mode -- filter out write permissions + mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH); + + // create the package node + PackageNode* node; + if (S_ISREG(mode)) { + // file + node = new(std::nothrow) PackageFile(fVolume, mode, entry->Data()); + } else if (S_ISLNK(mode)) { + // symlink + PackageSymlink* symlink = new(std::nothrow) PackageSymlink( + fVolume, mode); + if (symlink == NULL) + RETURN_ERROR(B_NO_MEMORY); + + error = symlink->SetSymlinkPath(entry->SymlinkPath()); + if (error != B_OK) { + delete symlink; + return error; + } + + node = symlink; + } else if (S_ISDIR(mode)) { + // directory + node = new(std::nothrow) PackageDirectory(fVolume, mode); + } else + RETURN_ERROR(B_BAD_DATA); + + if (node == NULL) + RETURN_ERROR(B_NO_MEMORY); + + error = node->Init(parentDir, entry->Name()); + if (error != B_OK) { + delete node; + RETURN_ERROR(error); + } + + node->SetModifiedTime(entry->ModifiedTime()); + + // add it to the parent directory + if (parentDir != NULL) + parentDir->AddChild(node); + else + fVolume->AddNode(node); + + entry->SetUserToken(node); + + return B_OK; + } + + virtual status_t HandleEntryAttribute(BPackageEntry* entry, + BPackageEntryAttribute* attribute) + { + // attributes aren't needed in the boot loader + return B_OK; + } + + virtual status_t HandleEntryDone(BPackageEntry* entry) + { + return B_OK; + } + + virtual status_t HandlePackageAttribute( + const BPackageInfoAttributeValue& value) + { + // TODO? + return B_OK; + } + + virtual void HandleErrorOccurred() + { + fErrorOccurred = true; + } + +private: + PackageVolume* fVolume; + bool fErrorOccurred; +}; + + +// #pragma mark - File + + +struct File : ::Node { + File(PackageFile* file) + : + fFile(file) + { + fFile->Volume()->AcquireReference(); + } + + ~File() + { + fFile->Volume()->ReleaseReference(); + } + + virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer, + size_t bufferSize) + { + off_t size = fFile->Size(); + if (pos < 0 || pos > size) + return B_BAD_VALUE; + if (pos + bufferSize > size) + bufferSize = size - pos; + + if (bufferSize > 0) { + FileDataReader* dataReader = (FileDataReader*)cookie; + status_t error = dataReader->ReadData(pos, buffer, bufferSize); + if (error != B_OK) + return error; + } + + return bufferSize; + } + + virtual ssize_t WriteAt(void* cookie, off_t pos, const void *buffer, + size_t bufferSize) + { + return B_READ_ONLY_DEVICE; + } + + virtual status_t GetName(char* nameBuffer, size_t bufferSize) const + { + strlcpy(nameBuffer, fFile->Name(), bufferSize); + return B_OK; + } + + virtual status_t Open(void** _cookie, int mode) + { + if ((mode & O_ACCMODE) != O_RDONLY && (mode & O_ACCMODE) != O_RDWR) + return B_NOT_ALLOWED; + + FileDataReader* dataReader; + status_t error = fFile->Volume()->CreateFileDataReader(fFile->Data(), + dataReader); + if (error != B_OK) + return error; + + *_cookie = dataReader; + Acquire(); + return B_OK; + } + + virtual status_t Close(void* cookie) + { + FileDataReader* dataReader = (FileDataReader*)cookie; + delete dataReader; + Release(); + return B_OK; + } + + + virtual int32 Type() const + { + return fFile->Mode() & S_IFMT; + } + + virtual off_t Size() const + { + return fFile->Size(); + } + +private: + PackageFile* fFile; +}; + + +// #pragma mark - Symlink + + +struct Symlink : ::Node { + Symlink(PackageSymlink* symlink) + : + fSymlink(symlink) + { + fSymlink->Volume()->AcquireReference(); + } + + ~Symlink() + { + fSymlink->Volume()->ReleaseReference(); + } + + virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer, + size_t bufferSize) + { + return B_BAD_VALUE; + } + + virtual ssize_t WriteAt(void* cookie, off_t pos, const void *buffer, + size_t bufferSize) + { + return B_READ_ONLY_DEVICE; + } + + virtual status_t ReadLink(char* buffer, size_t bufferSize) + { + const char* path = fSymlink->SymlinkPath(); + size_t size = strlen(path) + 1; + + if (size > bufferSize) + return B_BUFFER_OVERFLOW; + + memcpy(buffer, path, size); + return B_OK; + } + + virtual status_t GetName(char* nameBuffer, size_t bufferSize) const + { + strlcpy(nameBuffer, fSymlink->Name(), bufferSize); + return B_OK; + } + + virtual int32 Type() const + { + return fSymlink->Mode() & S_IFMT; + } + + virtual off_t Size() const + { + return strlen(fSymlink->SymlinkPath()) + 1; + } + +private: + PackageSymlink* fSymlink; +}; + + +// #pragma mark - Directory + + +struct Directory : ::Directory { + Directory(PackageDirectory* symlink) + : + fDirectory(symlink) + { + fDirectory->Volume()->AcquireReference(); + } + + ~Directory() + { + fDirectory->Volume()->ReleaseReference(); + } + + virtual ssize_t ReadAt(void* cookie, off_t pos, void* buffer, + size_t bufferSize) + { + return B_IS_A_DIRECTORY; + } + + virtual ssize_t WriteAt(void* cookie, off_t pos, const void *buffer, + size_t bufferSize) + { + return B_IS_A_DIRECTORY; + } + + virtual status_t GetName(char* nameBuffer, size_t bufferSize) const + { + strlcpy(nameBuffer, fDirectory->Name(), bufferSize); + return B_OK; + } + + virtual int32 Type() const + { + return fDirectory->Mode() & S_IFMT; + } + + virtual status_t Open(void** _cookie, int mode) + { + if ((mode & O_ACCMODE) != O_RDONLY && (mode & O_ACCMODE) != O_RDWR) + return B_NOT_ALLOWED; + + Cookie* cookie = new(std::nothrow) Cookie; + if (cookie == NULL) + return B_NO_MEMORY; + + cookie->nextChild = fDirectory->FirstChild(); + + Acquire(); + *_cookie = cookie; + return B_OK; + } + + virtual status_t Close(void* _cookie) + { + Cookie* cookie = (Cookie*)_cookie; + delete cookie; + Release(); + return B_OK; + } + + virtual Node* LookupDontTraverse(const char* name) + { + // look up the child + PackageNode* child = fDirectory->Lookup(name); + if (child == NULL) + return NULL; + + // create the node + ::Node* node; + return create_node(child, node) == B_OK ? node : NULL; + } + + virtual status_t GetNextEntry(void* _cookie, char* nameBuffer, + size_t bufferSize) + { + Cookie* cookie = (Cookie*)_cookie; + PackageNode* child = cookie->nextChild; + if (child == NULL) + return B_ENTRY_NOT_FOUND; + + cookie->nextChild = fDirectory->NextChild(child); + + strlcpy(nameBuffer, child->Name(), bufferSize); + return B_OK; + } + + virtual status_t GetNextNode(void* _cookie, Node** _node) + { + Cookie* cookie = (Cookie*)_cookie; + PackageNode* child = cookie->nextChild; + if (child == NULL) + return B_ENTRY_NOT_FOUND; + + cookie->nextChild = fDirectory->NextChild(child); + + return create_node(child, *_node); + } + + virtual status_t Rewind(void* _cookie) + { + Cookie* cookie = (Cookie*)_cookie; + cookie->nextChild = NULL; + return B_OK; + } + + virtual bool IsEmpty() + { + return fDirectory->FirstChild() == NULL; + } + +private: + struct Cookie { + PackageNode* nextChild; + }; + + +private: + PackageDirectory* fDirectory; +}; + + +// #pragma mark - + + +static status_t +create_node(PackageNode* packageNode, ::Node*& _node) +{ + if (packageNode == NULL) + return B_BAD_VALUE; + + ::Node* node; + switch (packageNode->Mode() & S_IFMT) { + case S_IFREG: + node = new(std::nothrow) File( + static_cast(packageNode)); + break; + case S_IFLNK: + node = new(std::nothrow) Symlink( + static_cast(packageNode)); + break; + case S_IFDIR: + node = new(std::nothrow) Directory( + static_cast(packageNode)); + break; + default: + return B_BAD_VALUE; + } + + if (node == NULL) + return B_NO_MEMORY; + + _node = node; + return B_OK; +} + + +} // unnamed namespace + + +status_t +packagefs_mount_file(int fd, ::Directory*& _mountedDirectory) +{ + PackageLoaderErrorOutput errorOutput; + PackageReaderImpl packageReader(&errorOutput); + status_t error = packageReader.Init(fd, false); + if (error != B_OK) + RETURN_ERROR(error); + + // create the volume + PackageVolume* volume = new(std::nothrow) PackageVolume; + if (volume == NULL) + return B_NO_MEMORY; + BReference volumeReference(volume, true); + + error = volume->Init(fd); + if (error != B_OK) + RETURN_ERROR(error); + + // parse content -- this constructs the entry/node tree + PackageLoaderContentHandler handler(volume); + error = handler.Init(); + if (error != B_OK) + RETURN_ERROR(error); + + error = packageReader.ParseContent(&handler); + if (error != B_OK) + RETURN_ERROR(error); + + // create a VFS node for the root node + ::Node* rootNode; + error = create_node(volume->RootDirectory(), rootNode); + if (error != B_OK) + RETURN_ERROR(error); + + _mountedDirectory = static_cast< ::Directory*>(rootNode); + return B_OK; +} diff --git a/src/system/boot/loader/file_systems/packagefs/packagefs.h b/src/system/boot/loader/file_systems/packagefs/packagefs.h new file mode 100644 index 0000000000..1ae18a0abe --- /dev/null +++ b/src/system/boot/loader/file_systems/packagefs/packagefs.h @@ -0,0 +1,27 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef BOOT_LOADER_FILE_SYSTEMS_PACKAGEFS_H +#define BOOT_LOADER_FILE_SYSTEMS_PACKAGEFS_H + + +#include + +#include + + +class Directory; +class Node; + + +__BEGIN_DECLS + + +status_t packagefs_mount_file(int fd, Directory*& _mountedDirectory); + + +__END_DECLS + + +#endif // BOOT_LOADER_FILE_SYSTEMS_PACKAGEFS_H diff --git a/src/system/boot/loader/file_systems/tarfs/tarfs.cpp b/src/system/boot/loader/file_systems/tarfs/tarfs.cpp index c85cb896a3..de71e8c0c1 100644 --- a/src/system/boot/loader/file_systems/tarfs/tarfs.cpp +++ b/src/system/boot/loader/file_systems/tarfs/tarfs.cpp @@ -119,7 +119,7 @@ public: size_t bufferSize) const; virtual TarFS::Entry* LookupEntry(const char* name); - virtual ::Node* Lookup(const char* name, bool traverseLinks); + virtual ::Node* LookupDontTraverse(const char* name); virtual status_t GetNextEntry(void* cookie, char* nameBuffer, size_t bufferSize); @@ -153,6 +153,8 @@ public: virtual ssize_t WriteAt(void* cookie, off_t pos, const void* buffer, size_t bufferSize); + virtual status_t ReadLink(char* buffer, size_t bufferSize); + virtual status_t GetName(char* nameBuffer, size_t bufferSize) const; @@ -392,25 +394,13 @@ TarFS::Directory::LookupEntry(const char* name) ::Node* -TarFS::Directory::Lookup(const char* name, bool traverseLinks) +TarFS::Directory::LookupDontTraverse(const char* name) { TarFS::Entry* entry = LookupEntry(name); if (!entry) return NULL; Node* node = entry->ToNode(); - - if (traverseLinks) { - if (S_ISLNK(node->Type())) { - Symlink* symlink = static_cast(node); - int fd = open_from(this, symlink->LinkPath(), O_RDONLY); - if (fd >= 0) { - node = get_node_from(fd); - close(fd); - } - } - } - if (node) node->Acquire(); @@ -587,6 +577,20 @@ TarFS::Symlink::WriteAt(void* cookie, off_t pos, const void* buffer, } +status_t +TarFS::Symlink::ReadLink(char* buffer, size_t bufferSize) +{ + const char* path = fHeader->linkname; + size_t size = strlen(path) + 1; + + if (size > bufferSize) + return B_BUFFER_OVERFLOW; + + memcpy(buffer, path, size); + return B_OK; +} + + status_t TarFS::Symlink::GetName(char* nameBuffer, size_t bufferSize) const { diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp index a3e2801719..eeb6e6c979 100644 --- a/src/system/boot/loader/vfs.cpp +++ b/src/system/boot/loader/vfs.cpp @@ -22,6 +22,7 @@ #include #include "RootFileSystem.h" +#include "file_systems/packagefs/packagefs.h" using namespace boot; @@ -98,6 +99,13 @@ Node::Close(void *cookie) } +status_t +Node::ReadLink(char* buffer, size_t bufferSize) +{ + return B_BAD_VALUE; +} + + status_t Node::GetName(char *nameBuffer, size_t bufferSize) const { @@ -209,6 +217,40 @@ Directory::Type() const } +Node* +Directory::Lookup(const char* name, bool traverseLinks) +{ + Node* node = LookupDontTraverse(name); + if (node == NULL) + return NULL; + + if (!traverseLinks || !S_ISLNK(node->Type())) + return node; + + // the node is a symbolic link, so we have to resolve the path + char linkPath[B_PATH_NAME_LENGTH]; + status_t error = node->ReadLink(linkPath, sizeof(linkPath)); + + node->Release(); + // we don't need this one anymore + + if (error != B_OK) + return NULL; + + // let open_from() do the real work + int fd = open_from(this, linkPath, O_RDONLY); + if (fd < 0) + return NULL; + + node = get_node_from(fd); + if (node != NULL) + node->Acquire(); + + close(fd); + return node; +} + + status_t Directory::CreateFile(const char *name, mode_t permissions, Node **_node) { @@ -393,7 +435,7 @@ BootVolume::SetTo(Directory* rootDirectory) fSystemDirectory = static_cast(systemNode); - // check, if the system is packaged + // try opening the system package int packageFD = open_from(fSystemDirectory, "packages/haiku.hpkg", O_RDONLY); fPackaged = packageFD >= 0; @@ -401,10 +443,18 @@ BootVolume::SetTo(Directory* rootDirectory) return B_OK; // the system is packaged -- mount the packagefs -// TODO:... -Unset(); -dprintf("BootVolume::SetTo(): packagefs not supported yet!\n"); -return B_NOT_SUPPORTED; + Directory* packageRootDirectory; + status_t error = packagefs_mount_file(packageFD, packageRootDirectory); + close(packageFD); + if (error != B_OK) { + Unset(); + return error; + } + + fSystemDirectory->Release(); + fSystemDirectory = packageRootDirectory; + + return B_OK; } @@ -725,6 +775,13 @@ read_pos(int fd, off_t offset, void *buffer, size_t bufferSize) } +ssize_t +pread(int fd, void* buffer, size_t bufferSize, off_t offset) +{ + return read_pos(fd, offset, buffer, bufferSize); +} + + ssize_t read(int fd, void *buffer, size_t bufferSize) { From 533833f646106f4d14f8329ea7773b42c7e45682 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 14:34:24 +0200 Subject: [PATCH 0037/1170] Add kernel args boot volume "packaged" flag * Add BOOT_VOLUME_PACKAGED boot volume message field name constant. * register_boot_file_system(): - Now takes a BootVolume& parameter. - If the boot volume is packaged, add that info to the boot volume message. --- headers/private/kernel/boot/kernel_args.h | 1 + headers/private/kernel/boot/vfs.h | 2 +- src/system/boot/loader/main.cpp | 2 +- src/system/boot/loader/vfs.cpp | 12 ++++++++---- 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/headers/private/kernel/boot/kernel_args.h b/headers/private/kernel/boot/kernel_args.h index 5d226e5aa1..78d2d2fc8a 100644 --- a/headers/private/kernel/boot/kernel_args.h +++ b/headers/private/kernel/boot/kernel_args.h @@ -27,6 +27,7 @@ #define BOOT_METHOD "boot method" #define BOOT_VOLUME_USER_SELECTED "user selected" #define BOOT_VOLUME_BOOTED_FROM_IMAGE "booted from image" +#define BOOT_VOLUME_PACKAGED "packaged" #define BOOT_VOLUME_PARTITION_OFFSET "partition offset" #define BOOT_VOLUME_DISK_IDENTIFIER "disk identifier" diff --git a/headers/private/kernel/boot/vfs.h b/headers/private/kernel/boot/vfs.h index e936160498..f00e282686 100644 --- a/headers/private/kernel/boot/vfs.h +++ b/headers/private/kernel/boot/vfs.h @@ -136,7 +136,7 @@ private: /* function prototypes */ extern status_t vfs_init(stage2_args *args); -extern status_t register_boot_file_system(Directory *directory); +extern status_t register_boot_file_system(BootVolume& bootVolume); extern status_t get_boot_file_system(stage2_args* args, BootVolume& _bootVolume); extern status_t mount_file_systems(stage2_args *args); diff --git a/src/system/boot/loader/main.cpp b/src/system/boot/loader/main.cpp index 309df34cd5..3c310c1144 100644 --- a/src/system/boot/loader/main.cpp +++ b/src/system/boot/loader/main.cpp @@ -106,7 +106,7 @@ main(stage2_args *args) // is already loaded at this point and we definitely // know our boot volume, too if (status == B_OK) { - register_boot_file_system(bootVolume.RootDirectory()); + register_boot_file_system(bootVolume); if ((platform_boot_options() & BOOT_OPTION_DEBUG_OUTPUT) == 0) platform_switch_to_logo(); diff --git a/src/system/boot/loader/vfs.cpp b/src/system/boot/loader/vfs.cpp index eeb6e6c979..a0bed30fa5 100644 --- a/src/system/boot/loader/vfs.cpp +++ b/src/system/boot/loader/vfs.cpp @@ -490,19 +490,23 @@ vfs_init(stage2_args *args) status_t -register_boot_file_system(Directory *volume) +register_boot_file_system(BootVolume& bootVolume) { - gRoot->AddLink("boot", volume); + Directory* rootDirectory = bootVolume.RootDirectory(); + gRoot->AddLink("boot", rootDirectory); Partition *partition; - status_t status = gRoot->GetPartitionFor(volume, &partition); + status_t status = gRoot->GetPartitionFor(rootDirectory, &partition); if (status != B_OK) { - dprintf("register_boot_file_system(): could not locate boot volume in root!\n"); + dprintf("register_boot_file_system(): could not locate boot volume in " + "root!\n"); return status; } gKernelArgs.boot_volume.SetInt64(BOOT_VOLUME_PARTITION_OFFSET, partition->offset); + if (bootVolume.IsPackaged()) + gKernelArgs.boot_volume.SetBool(BOOT_VOLUME_PACKAGED, true); Node *device = get_node_from(partition->FD()); if (device == NULL) { From 441b85e1cc56ed04ee4dedbd37d98186ad0a1e74 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 15:29:22 +0200 Subject: [PATCH 0038/1170] Assign node IDs to packagefs nodes Fixes module loading. elf_load_image() checks the node ID to verify whether an image was already loaded, so giving all nodes the same ID only gets one image loaded. The IDs don't necessarily match the ones the kernel packagefs assigns, which could be a problem later on. --- .../file_systems/packagefs/packagefs.cpp | 41 +++++++++++++++++-- 1 file changed, 38 insertions(+), 3 deletions(-) diff --git a/src/system/boot/loader/file_systems/packagefs/packagefs.cpp b/src/system/boot/loader/file_systems/packagefs/packagefs.cpp index eb6abc7f92..067d6596ec 100644 --- a/src/system/boot/loader/file_systems/packagefs/packagefs.cpp +++ b/src/system/boot/loader/file_systems/packagefs/packagefs.cpp @@ -64,6 +64,7 @@ struct PackageNode : DoublyLinkedListLinkImpl { fVolume(volume), fParentDirectory(NULL), fName(NULL), + fNodeID(0), fMode(mode) { fModifiedTime.tv_sec = 0; @@ -75,10 +76,11 @@ struct PackageNode : DoublyLinkedListLinkImpl { free(fName); } - status_t Init(PackageDirectory* parentDir, const char* name) + status_t Init(PackageDirectory* parentDir, const char* name, ino_t nodeID) { fParentDirectory = parentDir; fName = strdup(name); + fNodeID = nodeID; return fName != NULL ? B_OK : B_NO_MEMORY; } @@ -93,6 +95,11 @@ struct PackageNode : DoublyLinkedListLinkImpl { return fName; } + ino_t NodeID() const + { + return fNodeID; + } + mode_t Mode() const { return fMode; @@ -112,6 +119,7 @@ protected: PackageVolume* fVolume; PackageDirectory* fParentDirectory; char* fName; + ino_t fNodeID; mode_t fMode; timespec fModifiedTime; }; @@ -269,6 +277,7 @@ private: struct PackageVolume : BReferenceable { PackageVolume() : + fNextNodeID(1), fRootDirectory(this, S_IFDIR), fBufferCache(B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB, 2), fDataReaderFactory(&fBufferCache), @@ -284,7 +293,12 @@ struct PackageVolume : BReferenceable { status_t Init(int fd) { - status_t error = fBufferCache.Init(); + status_t error = fRootDirectory.Init(&fRootDirectory, ".", + NextNodeID()); + if (error != B_OK) + return error; + + error = fBufferCache.Init(); if (error != B_OK) return error; @@ -300,6 +314,11 @@ struct PackageVolume : BReferenceable { return &fRootDirectory; } + ino_t NextNodeID() + { + return fNextNodeID++; + } + void AddNode(PackageNode* node) { fRootDirectory.AddChild(node); @@ -324,6 +343,7 @@ struct PackageVolume : BReferenceable { } private: + ino_t fNextNodeID; PackageDirectory fRootDirectory; BBlockBufferCacheNoLock fBufferCache; BPackageDataReaderFactory fDataReaderFactory; @@ -408,7 +428,7 @@ struct PackageLoaderContentHandler : BPackageContentHandler { if (node == NULL) RETURN_ERROR(B_NO_MEMORY); - error = node->Init(parentDir, entry->Name()); + error = node->Init(parentDir, entry->Name(), fVolume->NextNodeID()); if (error != B_OK) { delete node; RETURN_ERROR(error); @@ -539,6 +559,11 @@ struct File : ::Node { return fFile->Size(); } + virtual ino_t Inode() const + { + return fFile->NodeID(); + } + private: PackageFile* fFile; }; @@ -600,6 +625,11 @@ struct Symlink : ::Node { return strlen(fSymlink->SymlinkPath()) + 1; } + virtual ino_t Inode() const + { + return fSymlink->NodeID(); + } + private: PackageSymlink* fSymlink; }; @@ -644,6 +674,11 @@ struct Directory : ::Directory { return fDirectory->Mode() & S_IFMT; } + virtual ino_t Inode() const + { + return fDirectory->NodeID(); + } + virtual status_t Open(void** _cookie, int mode) { if ((mode & O_ACCMODE) != O_RDONLY && (mode & O_ACCMODE) != O_RDWR) From 02b57b32a3ee6a799bc265d95d50f57ebc0886d9 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 16:44:43 +0200 Subject: [PATCH 0039/1170] Bump boot loader heap size --- src/system/boot/platform/bios_ia32/start.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/boot/platform/bios_ia32/start.cpp b/src/system/boot/platform/bios_ia32/start.cpp index 90dc88e3bd..bda4b1065f 100644 --- a/src/system/boot/platform/bios_ia32/start.cpp +++ b/src/system/boot/platform/bios_ia32/start.cpp @@ -28,7 +28,7 @@ #include "smp.h" -#define HEAP_SIZE (512 * 1024) +#define HEAP_SIZE (1024 * 1024) // GCC defined globals From cb89356142930e4357e2419538cbc67751a331b4 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 16:50:39 +0200 Subject: [PATCH 0040/1170] Boot loader packagefs: Fix ".." lookups * PackageDirectory::Lookup(): Support "." and ".." lookups. * PackageLoaderContentHandler::HandleEntry(): If the entry doesn't have a parent directory, use the volume's root directory directly. This makes PackageVolume::AddNode() superfluous and also always passes a non-NULL parent directory to PackageNode::Init(). --- .../file_systems/packagefs/packagefs.cpp | 22 +++++++++---------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/src/system/boot/loader/file_systems/packagefs/packagefs.cpp b/src/system/boot/loader/file_systems/packagefs/packagefs.cpp index 067d6596ec..34eabd987e 100644 --- a/src/system/boot/loader/file_systems/packagefs/packagefs.cpp +++ b/src/system/boot/loader/file_systems/packagefs/packagefs.cpp @@ -208,9 +208,14 @@ struct PackageDirectory : PackageNode { return fEntries.GetNext(child); } - PackageNode* Lookup(const char* name) const + PackageNode* Lookup(const char* name) { - for (NodeList::ConstIterator it = fEntries.GetIterator(); + if (strcmp(name, ".") == 0) + return this; + if (strcmp(name, "..") == 0) + return fParentDirectory; + + for (NodeList::Iterator it = fEntries.GetIterator(); PackageNode* child = it.Next();) { if (strcmp(child->Name(), name) == 0) return child; @@ -319,11 +324,6 @@ struct PackageVolume : BReferenceable { return fNextNodeID++; } - void AddNode(PackageNode* node) - { - fRootDirectory.AddChild(node); - } - status_t CreateFileDataReader(const BPackageData& data, FileDataReader*& _fileDataReader) { @@ -395,6 +395,9 @@ struct PackageLoaderContentHandler : BPackageContentHandler { (PackageNode*)parentEntry->UserToken()); } + if (parentDir == NULL) + parentDir = fVolume->RootDirectory(); + status_t error; // get the file mode -- filter out write permissions @@ -437,10 +440,7 @@ struct PackageLoaderContentHandler : BPackageContentHandler { node->SetModifiedTime(entry->ModifiedTime()); // add it to the parent directory - if (parentDir != NULL) - parentDir->AddChild(node); - else - fVolume->AddNode(node); + parentDir->AddChild(node); entry->SetUserToken(node); From 6d7953ef0a99b6de4c11ebe85cc56691f82e664c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 16:53:20 +0200 Subject: [PATCH 0041/1170] Add boot module symlink for packagefs --- build/jam/HaikuPackages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages index d26edfc785..672b099568 100644 --- a/build/jam/HaikuPackages +++ b/build/jam/HaikuPackages @@ -220,7 +220,7 @@ AddBootModuleSymlinksToPackage uhci ohci ehci scsi_cd scsi_disk usb_disk intel - bfs + bfs packagefs ; # add-ons From ba65f946679a3171d2f7525a7a3be131e7f701c9 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 17:01:23 +0200 Subject: [PATCH 0042/1170] Fix image rules wrt system/ relative entries * Introduce on-container jam variable HAIKU_CONTAINER_SYSTEM_DIR_TOKENS containing the directory tokens relative to the container root to refer to system. * Use the variable in *ToContainer rules that need to put something in system. * AddFilesToContainer: Fix overlooked reference to AddFilesToHaikuImage. * AddBootModuleSymlinksToContainer: Use relative symlinks. This avoids special-casing in the boot loader for packagefs. --- build/jam/BuildSetup | 12 +++++++++++- build/jam/ImageRules | 39 ++++++++++++++++++++++++++++----------- build/jam/PackageRules | 1 + 3 files changed, 40 insertions(+), 12 deletions(-) diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index b416107de4..e36f954a56 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -20,6 +20,7 @@ HAIKU_INCLUDE_IN_CONTAINER_VAR on $(HAIKU_IMAGE_CONTAINER_NAME) = HAIKU_INCLUDE_IN_IMAGE ; HAIKU_INSTALL_TARGETS_VAR on $(HAIKU_IMAGE_CONTAINER_NAME) = HAIKU_IMAGE_INSTALL_TARGETS ; +HAIKU_CONTAINER_SYSTEM_DIR_TOKENS on $(HAIKU_IMAGE_CONTAINER_NAME) = system ; # network boot archive HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME = haiku-netboot-archive-container ; @@ -28,6 +29,8 @@ HAIKU_CONTAINER_GRIST on $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME) # HAIKU_INCLUDE_IN_CONTAINER_VAR -- update only mode not supported HAIKU_INSTALL_TARGETS_VAR on $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME) = HAIKU_NET_BOOT_ARCHIVE_INSTALL_TARGETS ; +HAIKU_CONTAINER_SYSTEM_DIR_TOKENS on $(HAIKU_NET_BOOT_ARCHIVE_CONTAINER_NAME) + = system ; # boot floppy HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME = haiku-boot-floppy-container ; @@ -36,6 +39,8 @@ HAIKU_CONTAINER_GRIST on $(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME) # HAIKU_INCLUDE_IN_CONTAINER_VAR -- update only mode not supported HAIKU_INSTALL_TARGETS_VAR on $(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME) = HAIKU_FLOPPY_BOOT_IMAGE_INSTALL_TARGETS ; +HAIKU_CONTAINER_SYSTEM_DIR_TOKENS on $(HAIKU_FLOPPY_BOOT_IMAGE_CONTAINER_NAME) + = system ; # boot CD image HAIKU_CD_BOOT_IMAGE_CONTAINER_NAME = haiku-boot-cd-container ; @@ -43,13 +48,18 @@ HAIKU_CONTAINER_GRIST on $(HAIKU_CD_BOOT_IMAGE_CONTAINER_NAME) = CDBootImage ; # HAIKU_INCLUDE_IN_CONTAINER_VAR -- update only mode not supported HAIKU_INSTALL_TARGETS_VAR on $(HAIKU_CD_BOOT_IMAGE_CONTAINER_NAME) = HAIKU_CD_BOOT_IMAGE_INSTALL_TARGETS ; +HAIKU_CONTAINER_SYSTEM_DIR_TOKENS on $(HAIKU_CD_BOOT_IMAGE_CONTAINER_NAME) + = system ; # boot CD for PPC image HAIKU_CD_BOOT_PPC_IMAGE_CONTAINER_NAME = haiku-boot-cd-ppc-container ; -HAIKU_CONTAINER_GRIST on $(HAIKU_CD_BOOT_PPC_IMAGE_CONTAINER_NAME) = CDBootPPCImage ; +HAIKU_CONTAINER_GRIST on $(HAIKU_CD_BOOT_PPC_IMAGE_CONTAINER_NAME) + = CDBootPPCImage ; # HAIKU_INCLUDE_IN_CONTAINER_VAR -- update only mode not supported HAIKU_INSTALL_TARGETS_VAR on $(HAIKU_CD_BOOT_PPC_IMAGE_CONTAINER_NAME) = HAIKU_CD_BOOT_PPC_IMAGE_INSTALL_TARGETS ; +HAIKU_CONTAINER_SYSTEM_DIR_TOKENS on $(HAIKU_CD_BOOT_PPC_IMAGE_CONTAINER_NAME) + = system ; # Haiku image/install defaults HAIKU_DEFAULT_IMAGE_NAME = haiku.image ; diff --git a/build/jam/ImageRules b/build/jam/ImageRules index fd3f30758c..5b4975bc98 100644 --- a/build/jam/ImageRules +++ b/build/jam/ImageRules @@ -165,6 +165,8 @@ rule AddFilesToContainer container : directoryTokens : targets : destName local directory = [ AddDirectoryToContainer $(container) : $(directoryTokens) ] ; local containerGrist = [ on $(container) return $(HAIKU_CONTAINER_GRIST) ] ; + local systemDirTokens + = [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ; # If the image shall only be updated, we filter out all targets not marked # accordingly. @@ -201,8 +203,8 @@ rule AddFilesToContainer container : directoryTokens : targets : destName if $(catalogs) { local signature = [ on $(target) return $(HAIKU_CATALOG_SIGNATURE) ] ; - AddFilesToHaikuImage - system data locale catalogs $(signature) + AddFilesToContainer $(container) + : $(systemDirTokens) data locale catalogs $(signature) : $(catalogs) ; } } @@ -296,7 +298,10 @@ rule AddHeaderDirectoryToContainer container : dirTokens : dirName # AddHeaderDirectoryToContainer : : [ ] # : ; - CopyDirectoryToContainer $(container) : system develop headers + local systemDirTokens + = [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ; + + CopyDirectoryToContainer $(container) : $(systemDirTokens) develop headers : [ FDirName $(HAIKU_TOP) headers $(dirTokens) ] : $(dirName) : -x .svn : $(alwaysUpdate) ; } @@ -311,7 +316,10 @@ rule AddWifiFirmwareToContainer container : driver : package : archive : extract local firmwareArchive = [ FDirName $(HAIKU_TOP) data system data firmware $(driver) $(archive) ] ; - local dirTokens = system data firmware $(driver) ; + local systemDirTokens + = [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ; + + local dirTokens = $(systemDirTokens) data firmware $(driver) ; if $(extract) = true || $(extract) = 1 { ExtractArchiveToContainer $(container) : $(dirTokens) : $(firmwareArchive) : $(package) ; @@ -338,11 +346,13 @@ rule AddDriversToContainer container : relativeDirectoryTokens : targets { # AddDriversToContainer : : ; # - local directoryTokens = system add-ons kernel drivers dev + local systemDirTokens + = [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ; + local directoryTokens = $(systemDirTokens) add-ons kernel drivers dev $(relativeDirectoryTokens) ; AddFilesToContainer $(container) - : system add-ons kernel drivers bin + : $(systemDirTokens) add-ons kernel drivers bin : $(targets) ; # If the image shall only be updated, we don't add any symlinks. @@ -371,7 +381,9 @@ rule AddNewDriversToContainer container : relativeDirectoryTokens { # AddNewDriversToContainer : : ; # - local directoryTokens = system add-ons kernel drivers + local systemDirTokens + = [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ; + local directoryTokens = $(systemDirTokens) add-ons kernel drivers $(relativeDirectoryTokens) ; AddFilesToContainer $(container) : $(directoryTokens) @@ -390,6 +402,9 @@ rule AddBootModuleSymlinksToContainer container : targets return ; } + local systemDirTokens + = [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ; + # add the symlinks local installTargetsVar = [ on $(container) return $(HAIKU_INSTALL_TARGETS_VAR) ] ; @@ -406,10 +421,10 @@ rule AddBootModuleSymlinksToContainer container : targets } local name = $(target:BS) ; - local linkTarget = [ FDirName /boot $(installDir:G=) $(name) ] ; + local linkTarget = [ FDirName ../../.. $(installDir:G=) $(name) ] ; AddSymlinkToContainer $(container) - : system add-ons kernel boot + : $(systemDirTokens) add-ons kernel boot : $(linkTarget) : $(name) ; } } @@ -1017,8 +1032,10 @@ rule AddLicenseToHaikuImage file : name : searchPath name = ; } - AddFilesToHaikuImage system data licenses : $(file) - : $(name) ; + local systemDirTokens + = [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ; + + AddFilesToHaikuImage $(systemDirTokens) data licenses : $(file) : $(name) ; } diff --git a/build/jam/PackageRules b/build/jam/PackageRules index 00a998bbe8..b6bf583e35 100644 --- a/build/jam/PackageRules +++ b/build/jam/PackageRules @@ -272,6 +272,7 @@ rule HaikuPackage package = $(grist)_HAIKU_INCLUDE_IN_PACKAGE ; HAIKU_INSTALL_TARGETS_VAR on $(package) = $(grist)_HAIKU_PACKAGE_INSTALL_TARGETS ; + HAIKU_CONTAINER_SYSTEM_DIR_TOKENS on $(package) = ; HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE = $(package) ; } From 18e7d26c8d6e4cc9aba4efa9f7ff7ddf44335620 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 19:27:34 +0200 Subject: [PATCH 0043/1170] Mount the /boot/system packagefs on boot --- src/system/kernel/fs/vfs_boot.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/system/kernel/fs/vfs_boot.cpp b/src/system/kernel/fs/vfs_boot.cpp index 677be1e11e..9dd854f0d8 100644 --- a/src/system/kernel/fs/vfs_boot.cpp +++ b/src/system/kernel/fs/vfs_boot.cpp @@ -508,6 +508,19 @@ vfs_mount_boot_file_system(kernel_args* args) _kern_create_symlink(-1, path, "/boot", 0); } + // If we're booting off a packaged system, mount packagefs. + if (args->boot_volume.GetBool(BOOT_VOLUME_PACKAGED, false)) { + static const char* const kPackageFSName = "packagefs"; + + dev_t systemPackageMount = _kern_mount("/boot/system", + NULL, kPackageFSName, 0, "packages /boot/system/packages", + 0 /* unused argument length */); + if (systemPackageMount < 0) { + panic("Failed to mount system packagefs: %s", + strerror(systemPackageMount)); + } + } + // Do post-boot-volume module initialization. The module code wants to know // whether the module images the boot loader has pre-loaded are the same as // on the boot volume. That is the case when booting from hard disk or CD, From 8ba02058b949cc9b6145cefe22d9c7a8f55a2f44 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 21:15:20 +0200 Subject: [PATCH 0044/1170] Add atomic_*() functions to boot loader --- src/system/boot/Jamfile | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/system/boot/Jamfile b/src/system/boot/Jamfile index 3845fd1313..4f13a06693 100644 --- a/src/system/boot/Jamfile +++ b/src/system/boot/Jamfile @@ -25,6 +25,10 @@ local librootFunctions = strtol.o ; +local librootArchFunctions = + atomic.o +; + local extraLinkerArgs = ; if $(HAIKU_BOARD_LOADER_BASE) { extraLinkerArgs += --defsym BOARD_LOADER_BASE=$(HAIKU_BOARD_LOADER_BASE) ; @@ -59,6 +63,7 @@ KernelLd boot_loader_$(TARGET_BOOT_PLATFORM) : # libroot functions needed by the stage2 boot loader (compiled for the # kernel) $(librootFunctions:G=src!system!kernel!lib) + $(librootArchFunctions:G=src!system!kernel!lib!arch!$(TARGET_ARCH)) : $(HAIKU_TOP)/src/system/ldscripts/$(TARGET_ARCH)/boot_loader_$(TARGET_BOOT_PLATFORM).ld : -Bstatic $(extraLinkerArgs) From 55a34b69f3a3c438254657da49205158793e21e3 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 22:14:09 +0200 Subject: [PATCH 0045/1170] fs_write_attr(): Allow 0-length NULL buffer --- src/build/libroot/fs_attr_untyped.cpp | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/build/libroot/fs_attr_untyped.cpp b/src/build/libroot/fs_attr_untyped.cpp index 6276dcff26..02ea2af095 100644 --- a/src/build/libroot/fs_attr_untyped.cpp +++ b/src/build/libroot/fs_attr_untyped.cpp @@ -566,7 +566,7 @@ fs_write_attr(int fd, const char *_attribute, uint32 type, off_t pos, { // check params if (pos < 0 || pos + writeBytes > kMaxAttributeLength - || !_attribute || !buffer) { + || _attribute == NULL || (writeBytes > 0 && buffer == NULL)) { errno = B_BAD_VALUE; return -1; } @@ -587,7 +587,10 @@ fs_write_attr(int fd, const char *_attribute, uint32 type, off_t pos, AttributeHeader* header = (AttributeHeader*)attributeBuffer; header->type = type; memset(attributeBuffer + sizeof(AttributeHeader), 0, pos); - memcpy(attributeBuffer + sizeof(AttributeHeader) + pos, buffer, writeBytes); + if (writeBytes > 0) { + memcpy(attributeBuffer + sizeof(AttributeHeader) + pos, buffer, + writeBytes); + } // write the attribute ssize_t toWrite = sizeof(AttributeHeader) + pos + writeBytes; From 52e079692f1a43765ea6892b48cafcff96b88f37 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 22:15:02 +0200 Subject: [PATCH 0046/1170] write_pos(): Fix return value for attribute writes --- src/build/libroot/fs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/build/libroot/fs.cpp b/src/build/libroot/fs.cpp index f8c0af2798..d1f7e8bfbf 100644 --- a/src/build/libroot/fs.cpp +++ b/src/build/libroot/fs.cpp @@ -979,7 +979,7 @@ write_pos(int fd, off_t pos, const void *buffer, size_t bufferSize) return -1; } - return 0; + return bufferSize; } // seek From d971dfb68840b285396d046c1d116a3759997ce8 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 22:16:51 +0200 Subject: [PATCH 0047/1170] Nicer error output --- src/bin/package/command_extract.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/bin/package/command_extract.cpp b/src/bin/package/command_extract.cpp index 49d7562d63..7c8b19c517 100644 --- a/src/bin/package/command_extract.cpp +++ b/src/bin/package/command_extract.cpp @@ -285,7 +285,8 @@ private: return errno; } if ((size_t)bytesWritten != toCopy) { - fprintf(stderr, "Error: Failed to write all data\n"); + fprintf(stderr, "Error: Failed to write all data (%zd of " + "%zu)\n", bytesWritten, toCopy); return B_ERROR; } From 05384d694451618fcd24512e23e5248da8715742 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 22:17:32 +0200 Subject: [PATCH 0048/1170] Changed architecture to x86_gcc2 This needs to be created dynamically somehow, but for the time being we want things to work for gcc2 and x86 at least. --- src/data/package_infos/haiku | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku index 4c2db1e64f..d1ed521a69 100644 --- a/src/data/package_infos/haiku +++ b/src/data/package_infos/haiku @@ -1,6 +1,6 @@ name = Haiku version = 1-1 -architecture = x86 +architecture = x86_gcc2 summary = "The Haiku base system" description = "The Haiku base system includes all system core software, like boot loader, kernel, the system libraries, servers, and applications." From f724ec0e1ee8b5420fa5df8c1660f029c570809d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 22:18:55 +0200 Subject: [PATCH 0049/1170] ExtractArchive: Add hpkg support --- build/jam/FileRules | 30 ++++++++++++++++++++++++------ 1 file changed, 24 insertions(+), 6 deletions(-) diff --git a/build/jam/FileRules b/build/jam/FileRules index 788dcfcd3b..c2193840fc 100644 --- a/build/jam/FileRules +++ b/build/jam/FileRules @@ -235,12 +235,20 @@ rule ExtractArchive directory : entries : archiveFile : grist Depends $(directory) : $(archiveFile) ; switch $(archiveFile:S) { - case .zip : ExtractZipArchive1 $(targets) : $(directory) - $(archiveFile) ; - case .tgz : ExtractTarArchive1 $(targets) : $(directory) - $(archiveFile) ; - case * : Exit "ExtractArchive: Unhandled archive extension: - $(archiveFile:S)" ; + case .zip : + ExtractZipArchive1 $(targets) : $(directory) $(archiveFile) ; + + case .tgz : + ExtractTarArchive1 $(targets) : $(directory) $(archiveFile) ; + + case .hpkg : + Depends $(targets) : package ; + ExtractHPKGArchive1 $(targets) + : package $(directory) $(archiveFile) ; + + case * : + Exit "ExtractArchive: Unhandled archive extension:" + "$(archiveFile:S)" ; } INITIALIZED on $(directory) = 1 ; } @@ -252,6 +260,7 @@ rule ExtractArchive directory : entries : archiveFile : grist return $(targets) ; } + actions ExtractZipArchive1 { mkdir -p $(2[1]) @@ -264,6 +273,15 @@ actions ExtractTarArchive1 tar -C $(2[1]) -xf $(2[2]) } + +actions ExtractHPKGArchive1 +{ + mkdir -p "$(2[2])" + $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) + $(2[1]) extract -C "$(2[2])" "$(2[3])" +} + + actions ExtractArchiveDummy { } From fdc30d62ceed10e2d68e8f14fdc43b2c2c27059d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 22:34:39 +0200 Subject: [PATCH 0050/1170] Fix gcc2 and ICU optional packages * InstallOptionalHaikuImagePackage: In case of hpkg packages, copy them to the target directory, instead of extracting them. * Correct gcc 2 package download URL. * The ICU gcc 2 optional packages has been repackaged as hpkg. Use that. For gcc 4 things are broken, now. --- build/jam/ImageRules | 5 ++++- build/jam/OptionalBuildFeatures | 26 ++++++++++++++------------ build/jam/OptionalPackages | 7 ++++--- 3 files changed, 22 insertions(+), 16 deletions(-) diff --git a/build/jam/ImageRules b/build/jam/ImageRules index 5b4975bc98..813517e899 100644 --- a/build/jam/ImageRules +++ b/build/jam/ImageRules @@ -900,7 +900,10 @@ rule InstallOptionalHaikuImagePackage package : url : dirTokens : isCDPackage # download archive file local archiveFile = [ DownloadFile $(package) : $(url) ] ; - if ( $(isCDPackage) = true || $(isCDPackage) = 1 ) && $(HAIKU_CD_NAME) { + if $(package:S) = .hpkg { + AddFilesToHaikuImage $(dirTokens) : $(archiveFile) ; + } else if ( $(isCDPackage) = true || $(isCDPackage) = 1 ) + && $(HAIKU_CD_NAME) { # TODO: If HAIKU_CD_NAME is set, that doesn't mean we're building a CD # image! # copy onto image diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures index 122163e9f8..c0af75f3fa 100644 --- a/build/jam/OptionalBuildFeatures +++ b/build/jam/OptionalBuildFeatures @@ -56,8 +56,9 @@ if $(HAIKU_BUILD_FEATURE_SSL) { # ICU # Note ICU isn't actually optional, but is still an external package -HAIKU_ICU_GCC_2_PACKAGE = icu-4.4.1-r1a3-x86-gcc2-2011-05-29.zip ; +HAIKU_ICU_GCC_2_PACKAGE = icu-4.4.1-r1a3-x86-gcc2-2011-05-29.hpkg ; HAIKU_ICU_GCC_4_PACKAGE = icu-4.4.1-r1a3-x86-gcc4-2011-05-29.zip ; + # TODO: Make hpkg! HAIKU_ICU_PPC_PACKAGE = icu-4.4.1-ppc-2010-08-17.zip ; HAIKU_ICU_DEVEL_PACKAGE = icu-devel-4.4.1-2010-07-26.zip ; @@ -94,25 +95,25 @@ if $(TARGET_ARCH) = ppc { icu_package = $(HAIKU_ICU_GCC_4_PACKAGE) ; } - local zipFile = [ DownloadFile $(icu_package) - : $(baseURL)/$(icu_package) ] ; + local packageFile = [ DownloadFile $(icu_package) + : $(hpkgBaseURL)/$(icu_package) ] ; # zip file and output directory - HAIKU_ICU_ZIP_FILE = $(zipFile) ; + HAIKU_ICU_PACKAGE_FILE = $(packageFile) ; HAIKU_ICU_DIR = [ FDirName $(HAIKU_OPTIONAL_BUILD_PACKAGES_DIR) $(icu_package:B) ] ; # extract libraries HAIKU_ICU_LIBS = [ ExtractArchive $(HAIKU_ICU_DIR) : - libicudata.so.44 - libicui18n.so.44 - libicuio.so.44 - libicule.so.44 - libiculx.so.44 - libicutu.so.44 - libicuuc.so.44 - : $(zipFile) + lib/libicudata.so.44 + lib/libicui18n.so.44 + lib/libicuio.so.44 + lib/libicule.so.44 + lib/libiculx.so.44 + lib/libicutu.so.44 + lib/libicuuc.so.44 + : $(packageFile) : extracted-icu ] ; } @@ -142,6 +143,7 @@ if [ IsOptionalHaikuImagePackageAdded CLucene ] { } local baseURL = http://haiku-files.org/files/optional-packages ; +local hpkgBaseURL = http://haiku-files.org/files/hpkg ; HAIKU_CLUCENE_PACKAGE = clucene-0.9.21-x86-gcc4-haiku-2009-08-11.zip ; HAIKU_CLUCENE_URL = $(baseURL)/$(HAIKU_CLUCENE_PACKAGE) ; diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 2a33a3dd6f..a1ccbb7648 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -86,6 +86,7 @@ # Yasm - the assembler utility local baseURL = http://haiku-files.org/files/optional-packages ; +local hpkgBaseURL = http://haiku-files.org/files/hpkg ; local baseSourceURL = http://haiku-files.org/files/sources ; # ABI-compliance-checker @@ -515,7 +516,7 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ] # gcc and binutils if $(HAIKU_GCC_VERSION[1]) = 2 { InstallCommonPackage gcc-2.95.3_110304-1.hpkg - : $(baseURL)/gcc-2.95.3_110304.hpkg ; + : $(hpkgBaseURL)/gcc-2.95.3_110304-1.hpkg ; # TODO: remove this when we have a mechanism to switch gcc via PATH AddSymlinkToHaikuImage common settings develop tools @@ -856,8 +857,8 @@ if [ IsOptionalHaikuImagePackageAdded ICU ] { if $(HAIKU_GCC_VERSION[1]) = 2 { # unzip gcc2 InstallOptionalHaikuImagePackage $(HAIKU_ICU_GCC_2_PACKAGE) - : $(baseURL)/$(HAIKU_ICU_GCC_2_PACKAGE) - : system lib ; + : $(hpkgBaseURL)/$(HAIKU_ICU_GCC_2_PACKAGE) + : system packages ; } else { # unzip gcc4 InstallOptionalHaikuImagePackage $(HAIKU_ICU_GCC_4_PACKAGE) From 0d792bb3bb4b2009a9cdb1e07de63441522f0aca Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 19 Jun 2011 23:55:14 +0200 Subject: [PATCH 0051/1170] Fixed input server start fallback After failing to start the input server by signature, the fallback didn't append the input server name to the servers directory returned by find_directory(). --- src/servers/app/Desktop.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index f0b4b040b6..a2918c06ef 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -2351,10 +2351,11 @@ Desktop::_LaunchInputServer() // Could not load input_server by signature, try well-known location BEntry entry; - BPath systemServersDir; - if (find_directory(B_SYSTEM_SERVERS_DIRECTORY, &systemServersDir) == B_OK) - entry.SetTo(systemServersDir.Path()); - else + BPath inputServerPath; + if (find_directory(B_SYSTEM_SERVERS_DIRECTORY, &inputServerPath) == B_OK + && inputServerPath.Append("input_server") == B_OK) { + entry.SetTo(inputServerPath.Path()); + } else entry.SetTo("/system/servers/input_server"); entry_ref ref; status_t entryStatus = entry.GetRef(&ref); From d00bcc16079d008ee89ee4644a009d53e3798a8d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 20 Jun 2011 01:56:41 +0200 Subject: [PATCH 0052/1170] Hard code "Public Domain" as acceptable license --- src/kits/package/hpkg/PackageWriterImpl.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp index feccb880a9..86893eca91 100644 --- a/src/kits/package/hpkg/PackageWriterImpl.cpp +++ b/src/kits/package/hpkg/PackageWriterImpl.cpp @@ -38,6 +38,9 @@ using BPrivate::FileDescriptorCloser; +static const char* const kPublicDomainLicenseName = "Public Domain"; + + // We need to remap a few file operations on non-Haiku platforms, so dealing // with symlinks works correctly. #ifndef __HAIKU__ @@ -425,6 +428,9 @@ PackageWriterImpl::_CheckLicenses() const BObjectList& licenseList = fPackageInfo.LicenseList(); for (int i = 0; i < licenseList.CountItems(); ++i) { const BString& licenseName = *licenseList.ItemAt(i); + if (licenseName == kPublicDomainLicenseName) + continue; + BEntry license; if (systemLicenseDir.FindEntry(licenseName.String(), &license) == B_OK) continue; From 3f6ca2fdcab8c6c90a34dffc7a770e5ccc417c4d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 20 Jun 2011 02:00:36 +0200 Subject: [PATCH 0053/1170] Move remaining /boot/system contents into packages * Build system: Create packages haiku-devel, haiku-welcome, haiku-userguide, and makefile-engine. * The TimGMSoundFont and BeBook zip files have been repackaged as hpkg files. * Adjust the optional package definitions accordingly. --- build/jam/HaikuPackages | 127 +++++++++++++++++++++++++ build/jam/OptionalPackages | 105 ++------------------ src/data/package_infos/haiku-devel | 21 ++++ src/data/package_infos/haiku-userguide | 18 ++++ src/data/package_infos/haiku-welcome | 18 ++++ src/data/package_infos/makefile-engine | 19 ++++ 6 files changed, 213 insertions(+), 95 deletions(-) create mode 100644 src/data/package_infos/haiku-devel create mode 100644 src/data/package_infos/haiku-userguide create mode 100644 src/data/package_infos/haiku-welcome create mode 100644 src/data/package_infos/makefile-engine diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages index 672b099568..bc0cd80b3b 100644 --- a/build/jam/HaikuPackages +++ b/build/jam/HaikuPackages @@ -1,3 +1,6 @@ +#pragma mark - haiku.hpkg + + local haikuPackage = haiku.hpkg ; HaikuPackage $(haikuPackage) ; @@ -298,3 +301,127 @@ CopyDirectoryToPackage documentation BuildHaikuPackage $(haikuPackage) : haiku ; + + +#pragma mark - haiku-devel.hpkg + + +local haikuDevelPackage = haiku-devel.hpkg ; +HaikuPackage $(haikuDevelPackage) ; + +local arch = $(TARGET_ARCH) ; +local developDirTokens = develop ; + +# glue code +AddFilesToPackage $(developDirTokens) lib : + crti.o + crtn.o + init_term_dyn.o + start_dyn.o + haiku_version_glue.o +; + +# kernel +AddFilesToPackage $(developDirTokens) lib : kernel.so : _KERNEL_ ; + +# additional libraries +local developmentLibs = libroot_debug.so ; +AddFilesToPackage lib : $(developmentLibs) ; + +# library symlinks +local lib ; +for lib in $(SYSTEM_LIBS) $(SYSTEM_LIBS_LIBGL_ALIASES) $(developmentLibs) { + AddSymlinkToPackage $(developDirTokens) lib : /system/lib $(lib:BS) ; + local abiVersion = [ on $(lib) return $(HAIKU_LIB_ABI_VERSION) ] ; + if $(abiVersion) { + local abiVersionedLib = $(lib:BS).$(abiVersion) ; + AddSymlinkToPackage $(developDirTokens) lib + : /system/lib $(abiVersionedLib) ; + } +} + +# static libraries +AddFilesToPackage $(developDirTokens) lib : libncurses.a ; +AddFilesToPackage $(developDirTokens) lib : liblocalestub.a ; + +# the POSIX error code mapper library +AddFilesToPackage $(developDirTokens) lib : libposix_error_mapper.a ; + +# ABI independent stuff + +# scripts: cc and c++ wrapper, freetype-config, setgcc +local scripts = cc c++ freetype-config setgcc ; +SEARCH on $(scripts) = [ FDirName $(HAIKU_TOP) data bin ] ; +AddFilesToPackage bin : $(scripts) ; + +# headers +AddHeaderDirectoryToPackage config ; +AddHeaderDirectoryToPackage glibc ; +AddHeaderDirectoryToPackage os ; +AddHeaderDirectoryToPackage posix ; + +# create be -> os symlink for now +AddSymlinkToPackage $(developDirTokens) headers : os : be ; + +# BSD and GNU compatibility headers +AddHeaderDirectoryToPackage compatibility bsd : bsd ; +AddHeaderDirectoryToPackage compatibility gnu : gnu ; + +# third party libs headers +AddHeaderDirectoryToPackage libs freetype2 : 3rdparty ; +AddHeaderDirectoryToPackage libs jpeg : 3rdparty ; +AddHeaderDirectoryToPackage libs ncurses : 3rdparty ; +AddHeaderDirectoryToPackage libs png : 3rdparty ; +AddHeaderDirectoryToPackage libs termcap : 3rdparty ; +AddHeaderDirectoryToPackage libs tiff : 3rdparty ; +AddHeaderDirectoryToPackage libs zlib : 3rdparty ; + +# cpp headers +if $(HAIKU_GCC_VERSION[1]) = 2 { + # GCC 2 only -- for GCC 4 they come with the DevelopmentBase package + CopyDirectoryToPackage $(developDirTokens) headers c++ + : [ FDirName $(HAIKU_TOP) headers cpp ] : 2.95.3 : -x .svn ; +} + +BuildHaikuPackage $(haikuDevelPackage) : haiku-devel ; + + +#pragma mark - haiku-userguide.hpkg + + +local haikuUserGuidePackage = haiku-userguide.hpkg ; +HaikuPackage $(haikuUserGuidePackage) ; + +CopyDirectoryToPackage documentation : [ FDirName $(HAIKU_TOP) docs userguide ] + : userguide : -x .svn ; + +BuildHaikuPackage $(haikuUserGuidePackage) : haiku-userguide ; + + +#pragma mark - haiku-welcome.hpkg + + +local haikuWelcomePackage = haiku-welcome.hpkg ; +HaikuPackage $(haikuWelcomePackage) ; + +CopyDirectoryToPackage documentation : [ FDirName $(HAIKU_TOP) docs welcome ] + : welcome : -x .svn ; + +BuildHaikuPackage $(haikuWelcomePackage) : haiku-welcome ; + + +#pragma mark - makefile-engine.hpkg + + +local makefileEnginePackage = makefile-engine.hpkg ; +HaikuPackage $(makefileEnginePackage) ; + +# skeleton makefile and makefile-engine +local makefileEngineFiles = + makefile + makefile-engine +; +SEARCH on $(makefileEngineFiles) = [ FDirName $(HAIKU_TOP) data develop ] ; +AddFilesToPackage develop etc : $(makefileEngineFiles) ; + +BuildHaikuPackage $(makefileEnginePackage) : makefile-engine ; diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index a1ccbb7648..1e940c0c07 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -204,9 +204,9 @@ if [ IsOptionalHaikuImagePackageAdded Beam ] { # BeBook if [ IsOptionalHaikuImagePackageAdded BeBook ] { - InstallOptionalHaikuImagePackage bebook_20081026.zip - : $(baseURL)/bebook_20081026.zip - : system documentation ; + InstallOptionalHaikuImagePackage bebook-2008-10-26-1.hpkg + : $(hpkgBaseURL)/bebook-2008-10-26-1.hpkg + : system packages ; AddSymlinkToHaikuImage home Desktop : /boot/system/documentation/bebook/index.html : BeBook ; @@ -602,90 +602,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentMin ] && $(TARGET_ARCH) = x86 { $(HAIKU_GCC_VERSION[1]) ; } - local arch = $(TARGET_ARCH) ; - local developDirTokens = system develop ; - - # glue code - AddFilesToHaikuImage $(developDirTokens) lib : - crti.o - crtn.o - init_term_dyn.o - start_dyn.o - haiku_version_glue.o - ; - - # kernel - AddFilesToHaikuImage $(developDirTokens) lib : kernel.so : _KERNEL_ ; - - # additional libraries - local developmentLibs = libroot_debug.so ; - AddFilesToHaikuImage system lib : $(developmentLibs) ; - - # library symlinks - local lib ; - for lib in $(SYSTEM_LIBS) $(SYSTEM_LIBS_LIBGL_ALIASES) $(developmentLibs) { - AddSymlinkToHaikuImage $(developDirTokens) lib - : /system/lib $(lib:BS) ; - local abiVersion = [ on $(lib) return $(HAIKU_LIB_ABI_VERSION) ] ; - if $(abiVersion) { - local abiVersionedLib = $(lib:BS).$(abiVersion) ; - AddSymlinkToHaikuImage $(developDirTokens) lib - : /system/lib $(abiVersionedLib) ; - } - } - - # static libraries - AddFilesToHaikuImage $(developDirTokens) lib : libncurses.a ; - AddFilesToHaikuImage $(developDirTokens) lib : liblocalestub.a ; - - # the POSIX error code mapper library - AddFilesToHaikuImage $(developDirTokens) lib : libposix_error_mapper.a ; - - # ABI independent stuff - - # scripts: cc and c++ wrapper, freetype-config, setgcc - local scripts = cc c++ freetype-config setgcc ; - SEARCH on $(scripts) = [ FDirName $(HAIKU_TOP) data bin ] ; - AddFilesToHaikuImage system bin : $(scripts) ; - - # skeleton makefile and makefile-engine - local makefileEngineFiles = - makefile - makefile-engine - ; - SEARCH on $(makefileEngineFiles) - = [ FDirName $(HAIKU_TOP) data develop ] ; - AddFilesToHaikuImage common develop etc - : $(makefileEngineFiles) ; - - # headers - AddHeaderDirectoryToHaikuImage config ; - AddHeaderDirectoryToHaikuImage glibc ; - AddHeaderDirectoryToHaikuImage os ; - AddHeaderDirectoryToHaikuImage posix ; - - # create be -> os symlink for now - AddSymlinkToHaikuImage $(developDirTokens) headers : os : be ; - - # BSD and GNU compatibility headers - AddHeaderDirectoryToHaikuImage compatibility bsd : bsd ; - AddHeaderDirectoryToHaikuImage compatibility gnu : gnu ; - - # third party libs headers - AddHeaderDirectoryToHaikuImage libs freetype2 : 3rdparty ; - AddHeaderDirectoryToHaikuImage libs jpeg : 3rdparty ; - AddHeaderDirectoryToHaikuImage libs ncurses : 3rdparty ; - AddHeaderDirectoryToHaikuImage libs png : 3rdparty ; - AddHeaderDirectoryToHaikuImage libs termcap : 3rdparty ; - AddHeaderDirectoryToHaikuImage libs tiff : 3rdparty ; - AddHeaderDirectoryToHaikuImage libs zlib : 3rdparty ; - - # cpp headers - if $(HAIKU_GCC_VERSION[1]) = 2 { - # GCC 2 only -- for GCC 4 they come with the DevelopmentBase package - CopyDirectoryToHaikuImage $(developDirTokens) headers c++ - : [ FDirName $(HAIKU_TOP) headers cpp ] : 2.95.3 : -x .svn ; - } + AddFilesToHaikuImage system packages : haiku-devel.hpkg ; + AddFilesToHaikuImage common packages : makefile-engine.hpkg ; } @@ -1492,8 +1410,8 @@ if [ IsOptionalHaikuImagePackageAdded Tar ] { # TimGMSoundFont if [ IsOptionalHaikuImagePackageAdded TimGMSoundFont ] { - InstallOptionalHaikuImagePackage TimGMSoundFont-2010-06-16.zip - : $(baseURL)/TimGMSoundFont-2010-06-16.zip ; + InstallOptionalHaikuImagePackage TimGMSoundFont-2010-06-16.hpkg + : $(hpkgBaseURL)/TimGMSoundFont-2010-06-16.hpkg ; } @@ -1637,12 +1555,9 @@ if [ IsOptionalHaikuImagePackageAdded WebPositive ] { # Welcome if [ IsOptionalHaikuImagePackageAdded Welcome ] { - CopyDirectoryToHaikuImage system documentation - : [ FDirName $(HAIKU_TOP) docs welcome ] - : welcome : -x .svn ; - CopyDirectoryToHaikuImage system documentation - : [ FDirName $(HAIKU_TOP) docs userguide ] - : userguide : -x .svn ; + AddFilesToHaikuImage system packages : haiku-userguide.hpkg ; + AddFilesToHaikuImage system packages : haiku-welcome.hpkg ; + AddSymlinkToHaikuImage home Desktop : /boot/system/documentation/welcome/welcome_en.html : Welcome ; diff --git a/src/data/package_infos/haiku-devel b/src/data/package_infos/haiku-devel new file mode 100644 index 0000000000..b3b5b8e3a0 --- /dev/null +++ b/src/data/package_infos/haiku-devel @@ -0,0 +1,21 @@ +name = haiku-devel +version = 1-1 +architecture = x86_gcc2 +summary = "The Haiku base system development files" +description = "The package contains all files associated with the base system +needed for development, like static libraries, glue code, library symlinks, +header files, etc." + +packager = "The Haiku build system" +vendor = "Haiku Project" + +copyright = "2001-2011 Haiku, Inc. et al" +licenses = [ "MIT" ] + +provides = [ + haiku-devel +] + +requires = [ + haiku +] diff --git a/src/data/package_infos/haiku-userguide b/src/data/package_infos/haiku-userguide new file mode 100644 index 0000000000..6a24f6c236 --- /dev/null +++ b/src/data/package_infos/haiku-userguide @@ -0,0 +1,18 @@ +name = haiku-userguide +version = 1-1 +architecture = any +summary = "The Haiku user documentation" +description = "The Haiku user documentation." + +packager = "The Haiku build system" +vendor = "Haiku Project" + +copyright = "2001-2011 Haiku, Inc. et al" +licenses = [ "MIT" ] + +provides = [ + haiku-welcome +] + +requires = [ +] diff --git a/src/data/package_infos/haiku-welcome b/src/data/package_infos/haiku-welcome new file mode 100644 index 0000000000..23fcf51329 --- /dev/null +++ b/src/data/package_infos/haiku-welcome @@ -0,0 +1,18 @@ +name = haiku-welcome +version = 1-1 +architecture = any +summary = "The Haiku welcome documentation" +description = "The Haiku welcome documentation for new users." + +packager = "The Haiku build system" +vendor = "Haiku Project" + +copyright = "2001-2011 Haiku, Inc. et al" +licenses = [ "MIT" ] + +provides = [ + haiku-welcome +] + +requires = [ +] diff --git a/src/data/package_infos/makefile-engine b/src/data/package_infos/makefile-engine new file mode 100644 index 0000000000..ac2c65f3bd --- /dev/null +++ b/src/data/package_infos/makefile-engine @@ -0,0 +1,19 @@ +name = makefile-engine +version = 1-1 +architecture = any +summary = "The makefile engine" +description = "A simple generic makefile engine and makefile template." + +packager = "The Haiku build system" +vendor = "Be Inc., Haiku Project" + +copyright = "? Be Inc. 2001-2011 Haiku, Inc." +licenses = [ "MIT" ] + +provides = [ + makefile-engine +] + +requires = [ + cmd:make +] From 253e6eeb6a6f2de15c965f9eca18ea941cec84c7 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 20 Jun 2011 02:01:36 +0200 Subject: [PATCH 0054/1170] Ignore build/user_config_headers --- .gitignore | 1 + 1 file changed, 1 insertion(+) diff --git a/.gitignore b/.gitignore index f853046791..0770a5253b 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ generated* build/jam/UserBuildConfig +build/user_config_headers From 9280379a7bf876ccde70040d6b7448b85c1e48f5 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 20 Jun 2011 23:41:05 +0200 Subject: [PATCH 0055/1170] Comment typo fixes --- src/system/kernel/fs/vfs.cpp | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index e1e1d0609c..d991e252ed 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -234,12 +234,12 @@ static recursive_lock sMountOpLock; private_node, mount) to which only read-only access is allowed. The mutable fields advisory_locking, mandatory_locked_by, and ref_count, as well as the busy, removed, unused flags, and the vnode's type can also be - write access when holding a read lock to sVnodeLock *and* having the vnode - locked. Writing access to covered_by requires to write lock sVnodeLock. + write accessed when holding a read lock to sVnodeLock *and* having the vnode + locked. Write access to covered_by requires to write lock sVnodeLock. The thread trying to acquire the lock must not hold sMountMutex. - You must not have this lock held when calling create_sem(), as this - might call vfs_free_unused_vnodes() and thus cause a deadlock. + You must not hold this lock when calling create_sem(), as this might call + vfs_free_unused_vnodes() and thus cause a deadlock. */ static rw_lock sVnodeLock = RW_LOCK_INITIALIZER("vfs_vnode_lock"); From 3cc710798baa42c155dd2e5c4c75306755ae2fd7 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 00:43:30 +0200 Subject: [PATCH 0056/1170] Replaced fs_mount::covers_vnode by Vnode::covers Introduce a Vnode::covers field. It is currently only used for the root node of an fs_mount, replacing fs_mount::covers_vnode. --- src/system/kernel/fs/Vnode.h | 1 + src/system/kernel/fs/vfs.cpp | 66 +++++++++++++++++++----------------- 2 files changed, 35 insertions(+), 32 deletions(-) diff --git a/src/system/kernel/fs/Vnode.h b/src/system/kernel/fs/Vnode.h index 610b8c3cee..f31561fe8b 100644 --- a/src/system/kernel/fs/Vnode.h +++ b/src/system/kernel/fs/Vnode.h @@ -28,6 +28,7 @@ struct vnode : fs_vnode, DoublyLinkedListLinkImpl { VMCache* cache; struct fs_mount* mount; struct vnode* covered_by; + struct vnode* covers; struct advisory_locking* advisory_locking; struct file_descriptor* mandatory_locked_by; list_link unused_link; diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index d991e252ed..1eafad29ef 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -121,15 +121,15 @@ typedef DoublyLinkedList VnodeList; /*! \brief Structure to manage a mounted file system - Note: The root_vnode and covers_vnode fields (what others?) are + Note: The root_vnode and root_vnode->covers fields (what others?) are initialized in fs_mount() and not changed afterwards. That is as soon as the mount is mounted and it is made sure it won't be unmounted (e.g. by holding a reference to a vnode of that mount) (read) access to those fields is always safe, even without additional locking. Morever - while mounted the mount holds a reference to the covers_vnode, and thus - making the access path vnode->mount->covers_vnode->mount->... safe if a - reference to vnode is held (note that for the root mount covers_vnode - is NULL, though). + while mounted the mount holds a reference to the root_vnode->covers vnode, + and thus making the access path vnode->mount->root_vnode->covers->mount->... + safe if a reference to vnode is held (note that for the root mount + root_vnode->covers is NULL, though). */ struct fs_mount { fs_mount() @@ -164,7 +164,6 @@ struct fs_mount { recursive_lock rlock; // guards the vnodes list // TODO: Make this a mutex! It is never used recursively. struct vnode* root_vnode; - struct vnode* covers_vnode; KPartition* partition; VnodeList vnodes; EntryCache entry_cache; @@ -1737,7 +1736,7 @@ replace_vnode_if_disconnected(struct fs_mount* mount, if (vnode == mount->root_vnode) { // redirect the vnode to the covered vnode - vnode = mount->covers_vnode; + vnode = mount->root_vnode->covers; } else vnode = fallBack; @@ -1933,8 +1932,8 @@ resolve_volume_root_to_mount_point(struct vnode* vnode) struct vnode* mountPoint = NULL; struct fs_mount* mount = vnode->mount; - if (vnode == mount->root_vnode && mount->covers_vnode) { - mountPoint = mount->covers_vnode; + if (vnode == mount->root_vnode && mount->root_vnode->covers != NULL) { + mountPoint = mount->root_vnode->covers; inc_vnode_ref_count(mountPoint); } @@ -2119,8 +2118,8 @@ vnode_path_to_vnode(struct vnode* vnode, char* path, bool traverseLeafLink, path = nextPath; continue; } else if (vnode->mount->root_vnode == vnode - && vnode->mount->covers_vnode) { - nextVnode = vnode->mount->covers_vnode; + && vnode->mount->root_vnode->covers != NULL) { + nextVnode = vnode->mount->root_vnode->covers; inc_vnode_ref_count(nextVnode); put_vnode(vnode); vnode = nextVnode; @@ -2427,8 +2426,8 @@ get_vnode_name(struct vnode* vnode, struct vnode* parent, struct dirent* buffer, // vnode so we get the underlying file system VNodePutter vnodePutter; if (vnode->mount->root_vnode == vnode - && vnode->mount->covers_vnode != NULL) { - vnode = vnode->mount->covers_vnode; + && vnode->mount->root_vnode->covers != NULL) { + vnode = vnode->mount->root_vnode->covers; inc_vnode_ref_count(vnode); vnodePutter.SetTo(vnode); } @@ -2938,7 +2937,7 @@ _dump_mount(struct fs_mount* mount) kprintf(" id: %ld\n", mount->id); kprintf(" device_name: %s\n", mount->device_name); kprintf(" root_vnode: %p\n", mount->root_vnode); - kprintf(" covers_vnode: %p\n", mount->covers_vnode); + kprintf(" covers: %p\n", mount->root_vnode->covers); kprintf(" partition: %p\n", mount->partition); kprintf(" lock: %p\n", &mount->rlock); kprintf(" flags: %s%s\n", mount->unmounting ? " unmounting" : "", @@ -2957,7 +2956,7 @@ _dump_mount(struct fs_mount* mount) set_debug_variable("_volume", (addr_t)mount->volume->private_volume); set_debug_variable("_root", (addr_t)mount->root_vnode); - set_debug_variable("_covers", (addr_t)mount->covers_vnode); + set_debug_variable("_covers", (addr_t)mount->root_vnode->covers); set_debug_variable("_partition", (addr_t)mount->partition); } @@ -3018,8 +3017,8 @@ debug_resolve_vnode_path(struct vnode* vnode, char* buffer, size_t bufferSize, while (true) { while (vnode->mount->root_vnode == vnode - && vnode->mount->covers_vnode != NULL) { - vnode = vnode->mount->covers_vnode; + && vnode->mount->root_vnode->covers != NULL) { + vnode = vnode->mount->root_vnode->covers; } if (vnode == sRoot) { @@ -3146,7 +3145,7 @@ dump_mounts(int argc, char** argv) while ((mount = (struct fs_mount*)hash_next(sMountsTable, &iterator)) != NULL) { kprintf("%p%4ld %p %p %p %s\n", mount, mount->id, mount->root_vnode, - mount->covers_vnode, mount->volume->private_volume, + mount->root_vnode->covers, mount->volume->private_volume, mount->volume->file_system_name); fs_volume* volume = mount->volume; @@ -5682,7 +5681,7 @@ fix_dirent(struct vnode* parent, struct dirent* entry, // we need to replace d_dev and d_ino with the actual values. if (strcmp(entry->d_name, "..") == 0 && parent->mount->root_vnode == parent - && parent->mount->covers_vnode) { + && parent->mount->root_vnode->covers != NULL) { inc_vnode_ref_count(parent); // vnode_path_to_vnode() puts the node @@ -6978,6 +6977,7 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, status_t status = B_OK; fs_volume* volume = NULL; int32 layer = 0; + Vnode* coveredNode = NULL; FUNCTION(("fs_mount: entry. path = '%s', fs_name = '%s'\n", path, fsName)); @@ -7105,7 +7105,6 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, mount->id = sNextMountID++; mount->partition = NULL; mount->root_vnode = NULL; - mount->covers_vnode = NULL; mount->unmounting = false; mount->owns_file_device = false; mount->volume = NULL; @@ -7185,17 +7184,17 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, if (status != 0) goto err2; } else { - status = path_to_vnode(path, true, &mount->covers_vnode, NULL, kernel); + status = path_to_vnode(path, true, &coveredNode, NULL, kernel); if (status != B_OK) goto err2; // make sure covered_vnode is a directory - if (!S_ISDIR(mount->covers_vnode->Type())) { + if (!S_ISDIR(coveredNode->Type())) { status = B_NOT_A_DIRECTORY; goto err3; } - if (mount->covers_vnode->mount->root_vnode == mount->covers_vnode) { + if (coveredNode->mount->root_vnode == coveredNode) { // this is already a mount point status = B_BUSY; goto err3; @@ -7233,10 +7232,12 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, } // No race here, since fs_mount() is the only function changing - // covers_vnode (and holds sMountOpLock at that time). + // root_vnode->covers (and holds sMountOpLock at that time). rw_lock_write_lock(&sVnodeLock); - if (mount->covers_vnode) - mount->covers_vnode->covered_by = mount->root_vnode; + if (coveredNode != NULL) { + mount->root_vnode->covers = coveredNode; + coveredNode->covered_by = mount->root_vnode; + } rw_lock_write_unlock(&sVnodeLock); if (!sRoot) { @@ -7260,16 +7261,16 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, } notify_mount(mount->id, - mount->covers_vnode ? mount->covers_vnode->device : -1, - mount->covers_vnode ? mount->covers_vnode->id : -1); + coveredNode != NULL ? coveredNode->device : -1, + coveredNode ? coveredNode->id : -1); return mount->id; err4: FS_MOUNT_CALL_NO_PARAMS(mount, unmount); err3: - if (mount->covers_vnode != NULL) - put_vnode(mount->covers_vnode); + if (coveredNode != NULL) + put_vnode(coveredNode); err2: mutex_lock(&sMountMutex); hash_remove(sMountsTable, mount); @@ -7413,11 +7414,12 @@ fs_unmount(char* path, dev_t mountID, uint32 flags, bool kernel) mount->root_vnode->ref_count--; vnode_to_be_freed(mount->root_vnode); - mount->covers_vnode->covered_by = NULL; + Vnode* coveredNode = mount->root_vnode->covers; + coveredNode->covered_by = NULL; vnodesWriteLocker.Unlock(); - put_vnode(mount->covers_vnode); + put_vnode(coveredNode); // Free all vnodes associated with this mount. // They will be removed from the mount list by free_vnode(), so From 2e21fc543649e665507240f0803de9dddc26f152 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 03:51:50 +0200 Subject: [PATCH 0057/1170] Generalize use of Vnode::covered_by/covers * Introduce Vnode flags for covered and covering. Can be used as a quick check when one doesn't already hold sVnodeLock. * Rename resolve_mount_point_to_volume_root() to resolve_vnode_to_covering_vnode(). * Adjust all code that deals with transitions between mount points and volume root vnodes to generally support covered/covering vnodes. --- headers/private/kernel/vfs.h | 2 +- src/system/kernel/fs/Vnode.h | 44 ++++ src/system/kernel/fs/node_monitor.cpp | 2 +- src/system/kernel/fs/vfs.cpp | 296 +++++++++++++++----------- 4 files changed, 219 insertions(+), 125 deletions(-) diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h index eed16d95df..b4533eb54d 100644 --- a/headers/private/kernel/vfs.h +++ b/headers/private/kernel/vfs.h @@ -143,7 +143,7 @@ status_t vfs_create_special_node(const char *path, fs_vnode *subVnode, struct vnode **_createdVnode); /* service call for the node monitor */ -status_t resolve_mount_point_to_volume_root(dev_t mountID, ino_t nodeID, +status_t resolve_vnode_to_covering_vnode(dev_t mountID, ino_t nodeID, dev_t *resolvedMountID, ino_t *resolvedNodeID); /* calls the syscall dispatcher should use for user file I/O */ diff --git a/src/system/kernel/fs/Vnode.h b/src/system/kernel/fs/Vnode.h index f31561fe8b..a40cf65059 100644 --- a/src/system/kernel/fs/Vnode.h +++ b/src/system/kernel/fs/Vnode.h @@ -52,6 +52,14 @@ public: inline bool IsHot() const; inline void SetHot(bool hot); + // setter requires sVnodeLock write-locked, getter is lockless + inline bool IsCovered() const; + inline void SetCovered(bool covered); + + // setter requires sVnodeLock write-locked, getter is lockless + inline bool IsCovering() const; + inline void SetCovering(bool covering); + inline uint32 Type() const; inline void SetType(uint32 type); @@ -68,6 +76,8 @@ private: static const uint32 kFlagsUnpublished = 0x00000010; static const uint32 kFlagsUnused = 0x00000020; static const uint32 kFlagsHot = 0x00000040; + static const uint32 kFlagsCovered = 0x00000080; + static const uint32 kFlagsCovering = 0x00000100; static const uint32 kFlagsType = 0xfffff000; static const uint32 kBucketCount = 32; @@ -185,6 +195,40 @@ vnode::SetHot(bool hot) } +bool +vnode::IsCovered() const +{ + return (fFlags & kFlagsCovered) != 0; +} + + +void +vnode::SetCovered(bool covered) +{ + if (covered) + atomic_or(&fFlags, kFlagsCovered); + else + atomic_and(&fFlags, ~kFlagsCovered); +} + + +bool +vnode::IsCovering() const +{ + return (fFlags & kFlagsCovering) != 0; +} + + +void +vnode::SetCovering(bool covering) +{ + if (covering) + atomic_or(&fFlags, kFlagsCovering); + else + atomic_and(&fFlags, ~kFlagsCovering); +} + + uint32 vnode::Type() const { diff --git a/src/system/kernel/fs/node_monitor.cpp b/src/system/kernel/fs/node_monitor.cpp index 02b0715ab2..08311a8937 100644 --- a/src/system/kernel/fs/node_monitor.cpp +++ b/src/system/kernel/fs/node_monitor.cpp @@ -687,7 +687,7 @@ NodeMonitorService::NotifyEntryMoved(dev_t device, ino_t fromDirectory, // If node is a mount point, we need to resolve it to the mounted // volume's root node. dev_t nodeDevice = device; - resolve_mount_point_to_volume_root(device, node, &nodeDevice, &node); + resolve_vnode_to_covering_vnode(device, node, &nodeDevice, &node); RecursiveLocker locker(fRecursiveLock); diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 1eafad29ef..1827254c2b 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -219,7 +219,6 @@ static mutex sMountMutex = MUTEX_INITIALIZER("vfs_mount_lock"); - sMountsTable will not be modified, - the fields immutable after initialization of the fs_mount structures in sMountsTable will not be modified, - - vnode::covered_by of any vnode in sVnodeTable will not be modified. The thread trying to lock the lock must not hold sVnodeLock or sMountMutex. @@ -234,7 +233,8 @@ static recursive_lock sMountOpLock; The mutable fields advisory_locking, mandatory_locked_by, and ref_count, as well as the busy, removed, unused flags, and the vnode's type can also be write accessed when holding a read lock to sVnodeLock *and* having the vnode - locked. Write access to covered_by requires to write lock sVnodeLock. + locked. Write access to covered_by and covers requires to write lock + sVnodeLock. The thread trying to acquire the lock must not hold sMountMutex. You must not hold this lock when calling create_sem(), as this might call @@ -1320,6 +1320,104 @@ free_unused_vnodes(int32 level) } +/*! Gets the vnode the given vnode is covering. + + The caller must have \c sVnodeLock read-locked at least. + + The function returns a reference to the retrieved vnode (if any), the caller + is responsible to free. + + \param vnode The vnode whose covered node shall be returned. + \return The covered vnode, or \c NULL if the given vnode doesn't cover any + vnode. +*/ +static inline Vnode* +get_covered_vnode_locked(Vnode* vnode) +{ + if (Vnode* coveredNode = vnode->covers) { + while (coveredNode->covers != NULL) + coveredNode = coveredNode->covers; + + inc_vnode_ref_count(coveredNode); + return coveredNode; + } + + return NULL; +} + + +/*! Gets the vnode the given vnode is covering. + + The caller must not hold \c sVnodeLock. Note that this implies a race + condition, since the situation can change at any time. + + The function returns a reference to the retrieved vnode (if any), the caller + is responsible to free. + + \param vnode The vnode whose covered node shall be returned. + \return The covered vnode, or \c NULL if the given vnode doesn't cover any + vnode. +*/ +static inline Vnode* +get_covered_vnode(Vnode* vnode) +{ + if (!vnode->IsCovering()) + return NULL; + + ReadLocker vnodeReadLocker(sVnodeLock); + return get_covered_vnode_locked(vnode); +} + + +/*! Gets the vnode the given vnode is covered by. + + The caller must have \c sVnodeLock read-locked at least. + + The function returns a reference to the retrieved vnode (if any), the caller + is responsible to free. + + \param vnode The vnode whose covering node shall be returned. + \return The covering vnode, or \c NULL if the given vnode isn't covered by + any vnode. +*/ +static Vnode* +get_covering_vnode_locked(Vnode* vnode) +{ + if (Vnode* coveringNode = vnode->covered_by) { + while (coveringNode->covered_by != NULL) + coveringNode = coveringNode->covered_by; + + inc_vnode_ref_count(coveringNode); + return coveringNode; + } + + return NULL; +} + + +/*! Gets the vnode the given vnode is covered by. + + The caller must not hold \c sVnodeLock. Note that this implies a race + condition, since the situation can change at any time. + + The function returns a reference to the retrieved vnode (if any), the caller + is responsible to free. + + \param vnode The vnode whose covering node shall be returned. + \return The covering vnode, or \c NULL if the given vnode isn't covered by + any vnode. +*/ +static inline Vnode* +get_covering_vnode(Vnode* vnode) +{ + if (!vnode->IsCovered()) + return NULL; + + ReadLocker vnodeReadLocker(sVnodeLock); + return get_covering_vnode_locked(vnode); +} + + static void free_unused_vnodes() { @@ -1725,30 +1823,36 @@ replace_vnode_if_disconnected(struct fs_mount* mount, struct vnode* vnodeToDisconnect, struct vnode*& vnode, struct vnode* fallBack, bool lockRootLock) { + struct vnode* givenVnode = vnode; + bool vnodeReplaced = false; + + ReadLocker vnodeReadLocker(sVnodeLock); + if (lockRootLock) mutex_lock(&sIOContextRootLock); - struct vnode* obsoleteVnode = NULL; - - if (vnode != NULL && vnode->mount == mount + while (vnode != NULL && vnode->mount == mount && (vnodeToDisconnect == NULL || vnodeToDisconnect == vnode)) { - obsoleteVnode = vnode; - - if (vnode == mount->root_vnode) { + if (vnode->covers != NULL) { // redirect the vnode to the covered vnode - vnode = mount->root_vnode->covers; + vnode = vnode->covers; } else vnode = fallBack; - if (vnode != NULL) - inc_vnode_ref_count(vnode); + vnodeReplaced = true; } + // If we've replaced the node, grab a reference for the new one. + if (vnodeReplaced && vnode != NULL) + inc_vnode_ref_count(vnode); + if (lockRootLock) mutex_unlock(&sIOContextRootLock); - if (obsoleteVnode != NULL) - put_vnode(obsoleteVnode); + vnodeReadLocker.Unlock(); + + if (vnodeReplaced) + put_vnode(givenVnode); } @@ -1834,44 +1938,11 @@ get_root_vnode(bool kernel) } -/*! \brief Resolves a mount point vnode to the volume root vnode it is covered - by. - - Given an arbitrary vnode, the function checks, whether the node is covered - by the root of a volume. If it is the function obtains a reference to the - volume root node and returns it. - - \param vnode The vnode in question. - \return The volume root vnode the vnode cover is covered by, if it is - indeed a mount point, or \c NULL otherwise. -*/ -static struct vnode* -resolve_mount_point_to_volume_root(struct vnode* vnode) -{ - if (!vnode) - return NULL; - - struct vnode* volumeRoot = NULL; - - rw_lock_read_lock(&sVnodeLock); - - if (vnode->covered_by) { - volumeRoot = vnode->covered_by; - inc_vnode_ref_count(volumeRoot); - } - - rw_lock_read_unlock(&sVnodeLock); - - return volumeRoot; -} - - -/*! \brief Resolves a mount point vnode to the volume root vnode it is covered - by. +/*! \brief Resolves a vnode to the vnode it is covered by, if any. Given an arbitrary vnode (identified by mount and node ID), the function - checks, whether the node is covered by the root of a volume. If it is the - function returns the mount and node ID of the volume root node. Otherwise + checks, whether the vnode is covered by another vnode. If it is, the + function returns the mount and node ID of the covering vnode. Otherwise it simply returns the supplied mount and node ID. In case of error (e.g. the supplied node could not be found) the variables @@ -1887,7 +1958,7 @@ resolve_mount_point_to_volume_root(struct vnode* vnode) - another error code, if something went wrong. */ status_t -resolve_mount_point_to_volume_root(dev_t mountID, ino_t nodeID, +resolve_vnode_to_covering_vnode(dev_t mountID, ino_t nodeID, dev_t* resolvedMountID, ino_t* resolvedNodeID) { // get the node @@ -1897,10 +1968,9 @@ resolve_mount_point_to_volume_root(dev_t mountID, ino_t nodeID, return error; // resolve the node - struct vnode* resolvedNode = resolve_mount_point_to_volume_root(node); - if (resolvedNode) { + if (Vnode* coveringNode = get_covering_vnode(node)) { put_vnode(node); - node = resolvedNode; + node = coveringNode; } // set the return values @@ -1913,34 +1983,6 @@ resolve_mount_point_to_volume_root(dev_t mountID, ino_t nodeID, } -/*! \brief Resolves a volume root vnode to the underlying mount point vnode. - - Given an arbitrary vnode, the function checks, whether the node is the - root of a volume. If it is (and if it is not "/"), the function obtains - a reference to the underlying mount point node and returns it. - - \param vnode The vnode in question (caller must have a reference). - \return The mount point vnode the vnode covers, if it is indeed a volume - root and not "/", or \c NULL otherwise. -*/ -static struct vnode* -resolve_volume_root_to_mount_point(struct vnode* vnode) -{ - if (!vnode) - return NULL; - - struct vnode* mountPoint = NULL; - - struct fs_mount* mount = vnode->mount; - if (vnode == mount->root_vnode && mount->root_vnode->covers != NULL) { - mountPoint = mount->root_vnode->covers; - inc_vnode_ref_count(mountPoint); - } - - return mountPoint; -} - - /*! \brief Gets the directory path and leaf name for a given path. The supplied \a path is transformed to refer to the directory part of @@ -2109,7 +2151,7 @@ vnode_path_to_vnode(struct vnode* vnode, char* path, bool traverseLeafLink, while (*nextPath == '/'); } - // See if the '..' is at the root of a mount and move to the covered + // See if the '..' is at a covering vnode move to the covered // vnode so we pass the '..' path to the underlying filesystem. // Also prevent breaking the root of the IO context. if (strcmp("..", path) == 0) { @@ -2117,10 +2159,10 @@ vnode_path_to_vnode(struct vnode* vnode, char* path, bool traverseLeafLink, // Attempted prison break! Keep it contained. path = nextPath; continue; - } else if (vnode->mount->root_vnode == vnode - && vnode->mount->root_vnode->covers != NULL) { - nextVnode = vnode->mount->root_vnode->covers; - inc_vnode_ref_count(nextVnode); + } + + if (Vnode* coveredVnode = get_covered_vnode(vnode)) { + nextVnode = coveredVnode; put_vnode(vnode); vnode = nextVnode; } @@ -2235,11 +2277,10 @@ vnode_path_to_vnode(struct vnode* vnode, char* path, bool traverseLeafLink, path = nextPath; vnode = nextVnode; - // see if we hit a mount point - struct vnode* mountPoint = resolve_mount_point_to_volume_root(vnode); - if (mountPoint) { + // see if we hit a covered node + if (Vnode* coveringNode = get_covering_vnode(vnode)) { put_vnode(vnode); - vnode = mountPoint; + vnode = coveringNode; } } @@ -2422,13 +2463,11 @@ get_vnode_name(struct vnode* vnode, struct vnode* parent, struct dirent* buffer, if (bufferSize < sizeof(struct dirent)) return B_BAD_VALUE; - // See if vnode is the root of a mount and move to the covered + // See if the vnode is convering another vnode and move to the covered // vnode so we get the underlying file system VNodePutter vnodePutter; - if (vnode->mount->root_vnode == vnode - && vnode->mount->root_vnode->covers != NULL) { - vnode = vnode->mount->root_vnode->covers; - inc_vnode_ref_count(vnode); + if (Vnode* coveredVnode = get_covered_vnode(vnode)) { + vnode = coveredVnode; vnodePutter.SetTo(vnode); } @@ -2532,11 +2571,10 @@ dir_vnode_to_path(struct vnode* vnode, char* buffer, size_t bufferSize, if (vnode != ioContext->root) { // we don't hit the IO context root - // resolve a volume root to its mount point - struct vnode* mountPoint = resolve_volume_root_to_mount_point(vnode); - if (mountPoint) { + // resolve a vnode to its covered vnode + if (Vnode* coveredVnode = get_covered_vnode(vnode)) { put_vnode(vnode); - vnode = mountPoint; + vnode = coveredVnode; } } @@ -2567,12 +2605,10 @@ dir_vnode_to_path(struct vnode* vnode, char* buffer, size_t bufferSize, if (vnode != ioContext->root) { // we don't hit the IO context root - // resolve a volume root to its mount point - struct vnode* mountPoint - = resolve_volume_root_to_mount_point(parentVnode); - if (mountPoint) { + // resolve a vnode to its covered vnode + if (Vnode* coveredVnode = get_covered_vnode(parentVnode)) { put_vnode(parentVnode); - parentVnode = mountPoint; + parentVnode = coveredVnode; parentID = parentVnode->id; } } @@ -3016,10 +3052,8 @@ debug_resolve_vnode_path(struct vnode* vnode, char* buffer, size_t bufferSize, buffer[--bufferSize] = '\0'; while (true) { - while (vnode->mount->root_vnode == vnode - && vnode->mount->root_vnode->covers != NULL) { - vnode = vnode->mount->root_vnode->covers; - } + while (vnode->covers != NULL) + vnode = vnode->covers; if (vnode == sRoot) { _truncated = bufferSize == 0; @@ -3068,6 +3102,7 @@ _dump_vnode(struct vnode* vnode, bool printPath) kprintf(" private_node: %p\n", vnode->private_node); kprintf(" mount: %p\n", vnode->mount); kprintf(" covered_by: %p\n", vnode->covered_by); + kprintf(" covers: %p\n", vnode->covers); kprintf(" cache: %p\n", vnode->cache); kprintf(" type: %#" B_PRIx32 "\n", vnode->Type()); kprintf(" flags: %s%s%s\n", vnode->IsRemoved() ? "r" : "-", @@ -3099,6 +3134,7 @@ _dump_vnode(struct vnode* vnode, bool printPath) set_debug_variable("_node", (addr_t)vnode->private_node); set_debug_variable("_mount", (addr_t)vnode->mount); set_debug_variable("_covered_by", (addr_t)vnode->covered_by); + set_debug_variable("_covers", (addr_t)vnode->covers); set_debug_variable("_adv_lock", (addr_t)vnode->advisory_locking); } @@ -5677,11 +5713,9 @@ fix_dirent(struct vnode* parent, struct dirent* entry, entry->d_pdev = parent->device; entry->d_pino = parent->id; - // If this is the ".." entry and the directory is the root of a FS, + // If this is the ".." entry and the directory covering another vnode, // we need to replace d_dev and d_ino with the actual values. - if (strcmp(entry->d_name, "..") == 0 - && parent->mount->root_vnode == parent - && parent->mount->root_vnode->covers != NULL) { + if (strcmp(entry->d_name, "..") == 0 && parent->IsCovering()) { inc_vnode_ref_count(parent); // vnode_path_to_vnode() puts the node @@ -5701,15 +5735,17 @@ fix_dirent(struct vnode* parent, struct dirent* entry, } } } else { - // resolve mount points + // resolve covered vnodes ReadLocker _(&sVnodeLock); struct vnode* vnode = lookup_vnode(entry->d_dev, entry->d_ino); - if (vnode != NULL) { - if (vnode->covered_by != NULL) { - entry->d_dev = vnode->covered_by->device; - entry->d_ino = vnode->covered_by->id; - } + if (vnode != NULL && vnode->covered_by != NULL) { + do { + vnode = vnode->covered_by; + } while (vnode->covered_by != NULL); + + entry->d_dev = vnode->device; + entry->d_ino = vnode->id; } } @@ -7194,8 +7230,8 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, goto err3; } - if (coveredNode->mount->root_vnode == coveredNode) { - // this is already a mount point + if (coveredNode->IsCovered()) { + // this is already a covered vnode status = B_BUSY; goto err3; } @@ -7231,12 +7267,21 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, goto err4; } - // No race here, since fs_mount() is the only function changing - // root_vnode->covers (and holds sMountOpLock at that time). + // set up the links between the root vnode and the vnode it covers rw_lock_write_lock(&sVnodeLock); if (coveredNode != NULL) { + if (coveredNode->IsCovered()) { + // the vnode is covered now + status = B_BUSY; + rw_lock_write_unlock(&sVnodeLock); + goto err4; + } + mount->root_vnode->covers = coveredNode; + mount->root_vnode->SetCovering(true); + coveredNode->covered_by = mount->root_vnode; + coveredNode->SetCovered(true); } rw_lock_write_unlock(&sVnodeLock); @@ -7415,7 +7460,12 @@ fs_unmount(char* path, dev_t mountID, uint32 flags, bool kernel) vnode_to_be_freed(mount->root_vnode); Vnode* coveredNode = mount->root_vnode->covers; - coveredNode->covered_by = NULL; + coveredNode->covered_by = mount->root_vnode->covered_by; + coveredNode->SetCovered(coveredNode->covered_by != NULL); + + mount->root_vnode->covered_by = NULL; + mount->root_vnode->SetCovered(false); + mount->root_vnode->SetCovering(false); vnodesWriteLocker.Unlock(); From 313e1e37f229242df626cb34f466d388590d62d9 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 15:37:54 +0200 Subject: [PATCH 0058/1170] Add vfs_ prefix to resolve_vnode_to_covering_vnode() --- headers/private/kernel/vfs.h | 2 +- src/system/kernel/fs/node_monitor.cpp | 2 +- src/system/kernel/fs/vfs.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h index b4533eb54d..0047cbe02e 100644 --- a/headers/private/kernel/vfs.h +++ b/headers/private/kernel/vfs.h @@ -143,7 +143,7 @@ status_t vfs_create_special_node(const char *path, fs_vnode *subVnode, struct vnode **_createdVnode); /* service call for the node monitor */ -status_t resolve_vnode_to_covering_vnode(dev_t mountID, ino_t nodeID, +status_t vfs_resolve_vnode_to_covering_vnode(dev_t mountID, ino_t nodeID, dev_t *resolvedMountID, ino_t *resolvedNodeID); /* calls the syscall dispatcher should use for user file I/O */ diff --git a/src/system/kernel/fs/node_monitor.cpp b/src/system/kernel/fs/node_monitor.cpp index 08311a8937..07bcb75851 100644 --- a/src/system/kernel/fs/node_monitor.cpp +++ b/src/system/kernel/fs/node_monitor.cpp @@ -687,7 +687,7 @@ NodeMonitorService::NotifyEntryMoved(dev_t device, ino_t fromDirectory, // If node is a mount point, we need to resolve it to the mounted // volume's root node. dev_t nodeDevice = device; - resolve_vnode_to_covering_vnode(device, node, &nodeDevice, &node); + vfs_resolve_vnode_to_covering_vnode(device, node, &nodeDevice, &node); RecursiveLocker locker(fRecursiveLock); diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 1827254c2b..a5631924f0 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -1958,7 +1958,7 @@ get_root_vnode(bool kernel) - another error code, if something went wrong. */ status_t -resolve_vnode_to_covering_vnode(dev_t mountID, ino_t nodeID, +vfs_resolve_vnode_to_covering_vnode(dev_t mountID, ino_t nodeID, dev_t* resolvedMountID, ino_t* resolvedNodeID) { // get the node From d61a8548f9d5efd322004bfd62c57e5a3891cdbf Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 19:23:15 +0200 Subject: [PATCH 0059/1170] Add support for bind-mounting directories * Add support function vfs_get_mount_point(), so a file system can get its own mount point (i.e. the node it covers). Re-added fs_mount::covers_vnode for that purpose -- the root node isn't know to the VFS before the mount() hook returns. * Add function vfs_bind_mount_directory() which bind-mounts a directory to another. The Vnode::covers/covered_by mechanism is used, so this isn't true bind-mounting, but sufficient for what we need ATM and cheaper as well. The vnodes connected thus aren't tracked yet, which is needed for undoing the connection when unmounting. * get_vnode_name(): Don't use dir_read() to read the directory. Since we have already resolved vnode to the covered vnode, we don't want the dirents to be "fixed" to refer to the covering nodes. Such a vnode simply wouldn't be found. --- headers/private/kernel/vfs.h | 6 +++ src/system/kernel/fs/vfs.cpp | 73 ++++++++++++++++++++++++++++++++++-- 2 files changed, 76 insertions(+), 3 deletions(-) diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h index 0047cbe02e..e5fb875b46 100644 --- a/headers/private/kernel/vfs.h +++ b/headers/private/kernel/vfs.h @@ -146,6 +146,12 @@ status_t vfs_create_special_node(const char *path, fs_vnode *subVnode, status_t vfs_resolve_vnode_to_covering_vnode(dev_t mountID, ino_t nodeID, dev_t *resolvedMountID, ino_t *resolvedNodeID); +/* service calls for private file systems */ +status_t vfs_get_mount_point(dev_t mountID, dev_t* _mountPointMountID, + ino_t* _mountPointNodeID); +status_t vfs_bind_mount_directory(dev_t mountID, ino_t nodeID, + dev_t coveredMountID, ino_t coveredNodeID); + /* calls the syscall dispatcher should use for user file I/O */ dev_t _user_mount(const char *path, const char *device, const char *fs_name, uint32 flags, const char *args, diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index a5631924f0..27a2c8bf4c 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -164,6 +164,7 @@ struct fs_mount { recursive_lock rlock; // guards the vnodes list // TODO: Make this a mutex! It is never used recursively. struct vnode* root_vnode; + struct vnode* covers_vnode; // immutable KPartition* partition; VnodeList vnodes; EntryCache entry_cache; @@ -2481,7 +2482,7 @@ get_vnode_name(struct vnode* vnode, struct vnode* parent, struct dirent* buffer, // The FS doesn't support getting the name of a vnode. So we search the // parent directory for the vnode, if the caller let us. - if (parent == NULL) + if (parent == NULL || !HAS_FS_CALL(parent, read_dir)) return B_NOT_SUPPORTED; void* cookie; @@ -2490,7 +2491,10 @@ get_vnode_name(struct vnode* vnode, struct vnode* parent, struct dirent* buffer, if (status >= B_OK) { while (true) { uint32 num = 1; - status = dir_read(ioContext, parent, cookie, buffer, bufferSize, + // We use the FS hook directly instead of dir_read(), since we don't + // want the entries to be fixed. We have already resolved vnode to + // the covered node. + status = FS_CALL(parent, read_dir, cookie, buffer, bufferSize, &num); if (status != B_OK) break; @@ -4974,6 +4978,66 @@ out: } +status_t +vfs_get_mount_point(dev_t mountID, dev_t* _mountPointMountID, + ino_t* _mountPointNodeID) +{ + ReadLocker nodeLocker(sVnodeLock); + MutexLocker mountLocker(sMountMutex); + + struct fs_mount* mount = find_mount(mountID); + if (mount == NULL) + return B_BAD_VALUE; + + Vnode* mountPoint = mount->covers_vnode; + + *_mountPointMountID = mountPoint->device; + *_mountPointNodeID = mountPoint->id; + + return B_OK; +} + + +status_t +vfs_bind_mount_directory(dev_t mountID, ino_t nodeID, dev_t coveredMountID, + ino_t coveredNodeID) +{ + // get the vnodes + Vnode* vnode; + status_t error = get_vnode(mountID, nodeID, &vnode, true, false); + if (error != B_OK) + return B_BAD_VALUE; + VNodePutter vnodePutter(vnode); + + Vnode* coveredVnode; + error = get_vnode(coveredMountID, coveredNodeID, &coveredVnode, true, + false); + if (error != B_OK) + return B_BAD_VALUE; + VNodePutter coveredVnodePutter(coveredVnode); + + // establish the covered/covering links + WriteLocker locker(sVnodeLock); + + if (vnode->covers != NULL || coveredVnode->covered_by != NULL) + return B_BUSY; + + vnode->covers = coveredVnode; + vnode->SetCovering(true); + + coveredVnode->covered_by = vnode; + coveredVnode->SetCovered(true); + + // the vnodes do now reference each other + inc_vnode_ref_count(vnode); + inc_vnode_ref_count(coveredVnode); + +// TODO: This relationship must be tracked, so it can be dissolved on unmount. + + return B_OK; +} + + int vfs_getrlimit(int resource, struct rlimit* rlp) { @@ -7141,6 +7205,7 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, mount->id = sNextMountID++; mount->partition = NULL; mount->root_vnode = NULL; + mount->covers_vnode = NULL; mount->unmounting = false; mount->owns_file_device = false; mount->volume = NULL; @@ -7224,6 +7289,8 @@ fs_mount(char* path, const char* device, const char* fsName, uint32 flags, if (status != B_OK) goto err2; + mount->covers_vnode = coveredNode; + // make sure covered_vnode is a directory if (!S_ISDIR(coveredNode->Type())) { status = B_NOT_A_DIRECTORY; @@ -8718,7 +8785,7 @@ _user_open_dir(int fd, const char* userPath) /*! \brief Opens a directory's parent directory and returns the entry name of the former. - Aside from that is returns the directory's entry name, this method is + Aside from that it returns the directory's entry name, this method is equivalent to \code _user_open_dir(fd, "..") \endcode. It really is equivalent, if \a userName is \c NULL. From 314cb5f13e717b5e4a7552a8ddbd18b5a66858d2 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 19:30:47 +0200 Subject: [PATCH 0060/1170] Add support for shine-through directories * packagefs_mount(): Initialize the fs_volume earlier, so it is more usuable in Volume::Mount(). * The new mount parameter "shine-through" can be used to specify which shine-through mode shall be used. Can be "system", "common", "home", and "none". Depending on the setting it is decided which directories of the underlying file system are bind-mounted on top of ours. * Fix infinite loop in Volume::_RemovePackageContent(). * Use the RETURN_ERROR() macro in more places to help with debugging. --- .../kernel/file_systems/packagefs/Volume.cpp | 167 +++++++++++++++--- .../kernel/file_systems/packagefs/Volume.h | 2 + .../packagefs/kernel_interface.cpp | 7 +- 3 files changed, 150 insertions(+), 26 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index c6b1fe01eb..3eded145f3 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -22,6 +22,7 @@ #include #include +#include #include #include @@ -44,6 +45,16 @@ using BPackageKit::BHPKG::BPrivate::PackageReaderImpl; // node ID of the root directory static const ino_t kRootDirectoryID = 1; +// shine-through directories +const char* const kSystemShineThroughDirectories[] = { + "packages", NULL +}; +const char* const kCommonShineThroughDirectories[] = { + "non-packaged", "packages", "settings", "var", NULL +}; +const char* const* kHomeShineThroughDirectories + = kCommonShineThroughDirectories; + // #pragma mark - Job @@ -355,14 +366,21 @@ Volume::Mount(const char* parameterString) const char* packages = NULL; const char* volumeName = NULL; + const char* shineThrough = NULL; + void* parameterHandle = parse_driver_settings_string(parameterString); if (parameterHandle != NULL) { - packages - = get_driver_parameter(parameterHandle, "packages", NULL, NULL); - volumeName - = get_driver_parameter(parameterHandle, "volume-name", NULL, NULL); - delete_driver_settings(parameterHandle); + packages = get_driver_parameter(parameterHandle, "packages", NULL, + NULL); + volumeName = get_driver_parameter(parameterHandle, "volume-name", NULL, + NULL); + shineThrough = get_driver_parameter(parameterHandle, "shine-through", + NULL, NULL); } + + CObjectDeleter parameterHandleDeleter(parameterHandle, + &delete_driver_settings); + if (packages == NULL || packages[0] == '\0') { ERROR("need package folder ('packages' parameter)!\n"); RETURN_ERROR(B_BAD_VALUE); @@ -396,11 +414,23 @@ Volume::Mount(const char* parameterString) error = PublishVNode(fRootDirectory); if (error != B_OK) { fRootDirectory->ReleaseReference(); - return error; + RETURN_ERROR(error); } + // establish shine-through directories + error = _CreateShineThroughDirectories(shineThrough); + if (error != B_OK) + RETURN_ERROR(error); + // run the package loader resume_thread(fPackageLoader); +dprintf("mounted packagefs successfully!\n"); +{ + for (Node* node = fRootDirectory->FirstChild(); node != NULL; + node = fRootDirectory->NextChild(node)) { + dprintf(" node %lld: \"%s\"\n", node->ID(), node->Name()); + } +} return B_OK; } @@ -452,7 +482,7 @@ Volume::AddPackageDomain(const char* path) status_t error = packageDomain->Init(path); if (error != B_OK) - return error; + RETURN_ERROR(error); Job* job = new(std::nothrow) AddPackageDomainJob(this, packageDomain); if (job == NULL) @@ -536,7 +566,7 @@ Volume::_AddInitialPackageDomain(const char* path) status_t error = domain->Init(path); if (error != B_OK) - return error; + RETURN_ERROR(error); return _AddPackageDomain(domain, false); } @@ -556,7 +586,7 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify) if (error != B_OK) { ERROR("Failed to prepare package domain \"%s\": %s\n", domain->Path(), strerror(errno)); - return errno; + RETURN_ERROR(errno); } // iterate through the dir and create packages @@ -564,7 +594,7 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify) if (dir == NULL) { ERROR("Failed to open package domain directory \"%s\": %s\n", domain->Path(), strerror(errno)); - return errno; + RETURN_ERROR(errno); } CObjectDeleter dirCloser(dir, closedir); @@ -589,7 +619,7 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify) break; _RemovePackageContent(activePackage, NULL, notify); } - return error; + RETURN_ERROR(error); } } @@ -614,17 +644,17 @@ Volume::_LoadPackage(Package* package) PackageReaderImpl packageReader(&errorOutput); status_t error = packageReader.Init(fd, false); if (error != B_OK) - return error; + RETURN_ERROR(error); // parse content PackageLoaderContentHandler handler(package); error = handler.Init(); if (error != B_OK) - return error; + RETURN_ERROR(error); error = packageReader.ParseContent(&handler); if (error != B_OK) - return error; + RETURN_ERROR(error); return B_OK; } @@ -641,7 +671,7 @@ Volume::_AddPackageContent(Package* package, bool notify) status_t error = _AddPackageContentRootNode(package, node, notify); if (error != B_OK) { _RemovePackageContent(package, node, notify); - return error; + RETURN_ERROR(error); } } @@ -658,12 +688,12 @@ Volume::_RemovePackageContent(Package* package, PackageNode* endNode, if (node == endNode) break; - // skip over ".PackageInfo" file, it isn't part of the package content - if (strcmp(node->Name(), B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) - continue; - PackageNode* nextNode = package->Nodes().GetNext(node); - _RemovePackageContentRootNode(package, node, NULL, notify); + + // skip over ".PackageInfo" file, it isn't part of the package content + if (strcmp(node->Name(), B_HPKG_PACKAGE_INFO_FILE_NAME) != 0) + _RemovePackageContentRootNode(package, node, NULL, notify); + node = nextNode; } } @@ -696,7 +726,7 @@ Volume::_AddPackageContentRootNode(Package* package, // remove the added package nodes _RemovePackageContentRootNode(package, rootPackageNode, packageNode, notify); - return error; + RETURN_ERROR(error); } // recursive into directory @@ -798,7 +828,7 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode, status_t error = _CreateNode(packageNode->Mode(), directory, packageNode->Name(), node); if (error != B_OK) - return error; + RETURN_ERROR(error); newNode = true; } BReference nodeReference(node); @@ -808,7 +838,7 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode, // remove the node, if created before if (newNode) _RemoveNode(node); - return error; + RETURN_ERROR(error); } if (notify) { @@ -911,7 +941,7 @@ Volume::_CreateNode(mode_t mode, Directory* parent, const char* name, status_t error = node->Init(parent, name); if (error != B_OK) - return error; + RETURN_ERROR(error); parent->AddChild(node); @@ -1084,3 +1114,92 @@ Volume::_DomainEntryMoved(PackageDomain* domain, dev_t deviceID, _DomainEntryCreated(domain, deviceID, toDirectoryID, nodeID, name, true, notify); } + + +status_t +Volume::_CreateShineThroughDirectories(const char* shineThroughSetting) +{ + if (shineThroughSetting == NULL) + return B_OK; + + // get the directories to map + const char* const* directories = NULL; + + if (strcmp(shineThroughSetting, "system") == 0) + directories = kSystemShineThroughDirectories; + else if (strcmp(shineThroughSetting, "common") == 0) + directories = kCommonShineThroughDirectories; + else if (strcmp(shineThroughSetting, "home") == 0) + directories = kHomeShineThroughDirectories; + else if (strcmp(shineThroughSetting, "none") == 0) + directories = NULL; + else + RETURN_ERROR(B_BAD_VALUE); + + if (directories == NULL) + return B_OK; + + // get our mount point + dev_t mountPointDevice; + ino_t mountPointNode; + status_t error = vfs_get_mount_point(fFSVolume->id, &mountPointDevice, + &mountPointNode); + if (error != B_OK) + RETURN_ERROR(error); + + // iterate through the directory list, create the directories, and bind them + // to the mount point subdirectories + while (const char* directoryName = *(directories++)) { + // look up the mount point subdirectory + struct vnode* vnode; + error = vfs_entry_ref_to_vnode(mountPointDevice, mountPointNode, + directoryName, &vnode); + if (error != B_OK) { + dprintf("packagefs: Failed to get shine-through directory \"%s\": " + "%s\n", directoryName, strerror(error)); + continue; + } + CObjectDeleter vnodePutter(vnode, &vfs_put_vnode); + + // stat it + struct stat st; + error = vfs_stat_vnode(vnode, &st); + if (error != B_OK) { + dprintf("packagefs: Failed to stat shine-through directory \"%s\": " + "%s\n", directoryName, strerror(error)); + continue; + } + + if (!S_ISDIR(st.st_mode)) { + dprintf("packagefs: Shine-through entry \"%s\" is not a " + "directory\n", directoryName); + continue; + } + + // create the directory + Node* directory; + error = _CreateNode(S_IFDIR, fRootDirectory, directoryName, directory); + if (error != B_OK) + RETURN_ERROR(error); + + // publish its vnode, so the VFS will find it without asking us + error = PublishVNode(directory); + if (error != B_OK) { + _RemoveNode(directory); + RETURN_ERROR(error); + } + + // bind the directory + error = vfs_bind_mount_directory(st.st_dev, st.st_ino, fFSVolume->id, + directory->ID()); + + PutVNode(directory->ID()); + // release our reference again -- on success + // vfs_bind_mount_directory() got one + + if (error != B_OK) + RETURN_ERROR(error); + } + + return B_OK; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h index 28894ead69..a5acba3016 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h @@ -118,6 +118,8 @@ private: ino_t nodeID, const char* fromName, const char* name, bool notify); + status_t _CreateShineThroughDirectories( + const char* shineThroughSetting); private: rw_lock fLock; fs_volume* fFSVolume; diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp index 0478c25f92..d0f82e322b 100644 --- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp @@ -117,14 +117,17 @@ packagefs_mount(fs_volume* fsVolume, const char* device, uint32 flags, RETURN_ERROR(B_NO_MEMORY); ObjectDeleter volumeDeleter(volume); + // Initialize the fs_volume now already, so it is mostly usable in during + // mounting. + fsVolume->private_volume = volumeDeleter.Detach(); + fsVolume->ops = &gPackageFSVolumeOps; + status_t error = volume->Mount(parameters); if (error != B_OK) return error; // set return values *_rootID = volume->RootDirectory()->ID(); - fsVolume->private_volume = volumeDeleter.Detach(); - fsVolume->ops = &gPackageFSVolumeOps; return B_OK; } From 51191b1d4c58624a8e3bf9846b2da88ff0b58315 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 19:31:17 +0200 Subject: [PATCH 0061/1170] Remove debug output --- src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 3eded145f3..447c21e69d 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -424,13 +424,6 @@ Volume::Mount(const char* parameterString) // run the package loader resume_thread(fPackageLoader); -dprintf("mounted packagefs successfully!\n"); -{ - for (Node* node = fRootDirectory->FirstChild(); node != NULL; - node = fRootDirectory->NextChild(node)) { - dprintf(" node %lld: \"%s\"\n", node->ID(), node->Name()); - } -} return B_OK; } From 60043152eb2bd423a94fd780c15276027cbe5c6c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 19:31:40 +0200 Subject: [PATCH 0062/1170] Mount packagefs with "system" shine-through mode --- src/system/kernel/fs/vfs_boot.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/system/kernel/fs/vfs_boot.cpp b/src/system/kernel/fs/vfs_boot.cpp index 9dd854f0d8..f603239e79 100644 --- a/src/system/kernel/fs/vfs_boot.cpp +++ b/src/system/kernel/fs/vfs_boot.cpp @@ -513,7 +513,8 @@ vfs_mount_boot_file_system(kernel_args* args) static const char* const kPackageFSName = "packagefs"; dev_t systemPackageMount = _kern_mount("/boot/system", - NULL, kPackageFSName, 0, "packages /boot/system/packages", + NULL, kPackageFSName, 0, + "packages /boot/system/packages; shine-through system", 0 /* unused argument length */); if (systemPackageMount < 0) { panic("Failed to mount system packagefs: %s", From b478cc3fc5a9c5dbccc0da1ec450cbcf75d7b9b1 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 19:32:21 +0200 Subject: [PATCH 0063/1170] Put TimGMSoundFont package in the right directory --- build/jam/OptionalPackages | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 1e940c0c07..11f396e54c 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -1411,7 +1411,8 @@ if [ IsOptionalHaikuImagePackageAdded Tar ] { # TimGMSoundFont if [ IsOptionalHaikuImagePackageAdded TimGMSoundFont ] { InstallOptionalHaikuImagePackage TimGMSoundFont-2010-06-16.hpkg - : $(hpkgBaseURL)/TimGMSoundFont-2010-06-16.hpkg ; + : $(hpkgBaseURL)/TimGMSoundFont-2010-06-16.hpkg + : system packages ; } From 4ef5b631e77e9bca75a71c75f3eb06bd02920430 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 20:31:16 +0200 Subject: [PATCH 0064/1170] Implement packagefs_get_vnode_name() hook --- .../packagefs/kernel_interface.cpp | 18 +++++++++++++++++- 1 file changed, 17 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp index d0f82e322b..fbf46b1dce 100644 --- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp @@ -208,6 +208,22 @@ packagefs_lookup(fs_volume* fsVolume, fs_vnode* fsDir, const char* entryName, } +static status_t +packagefs_get_vnode_name(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer, + size_t bufferSize) +{ + Node* node = (Node*)fsNode->private_node; + + FUNCTION("volume: %p, node: %p (%" B_PRIdINO "), %p, %zu\n", + fsVolume->private_volume, node, node->ID(), buffer, bufferSize); + + if (strlcpy(buffer, node->Name(), bufferSize) >= bufferSize) + return B_BUFFER_OVERFLOW; + + return B_OK; +} + + static status_t packagefs_get_vnode(fs_volume* fsVolume, ino_t vnid, fs_vnode* fsNode, int* _type, uint32* _flags, bool reenter) @@ -1103,7 +1119,7 @@ fs_volume_ops gPackageFSVolumeOps = { fs_vnode_ops gPackageFSVnodeOps = { // vnode operations &packagefs_lookup, - NULL, // get_vnode_name, + &packagefs_get_vnode_name, &packagefs_put_vnode, &packagefs_put_vnode, // remove_vnode -- same as put_vnode From 9561ddca0f8e80582cd352f8f80b187bce7195ed Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 23:20:00 +0200 Subject: [PATCH 0065/1170] remove_vnode(): Also consider covering vnode busy --- src/system/kernel/fs/vfs.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index 27a2c8bf4c..e6bdb00175 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -3808,7 +3808,7 @@ remove_vnode(fs_volume* volume, ino_t vnodeID) if (vnode == NULL) return B_ENTRY_NOT_FOUND; - if (vnode->covered_by != NULL) { + if (vnode->covered_by != NULL || vnode->covers != NULL) { // this vnode is in use return B_BUSY; } From 19c48aa4ae39e2b2ff84224e66b9f8e7b0280c3f Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 23:24:23 +0200 Subject: [PATCH 0066/1170] fix_dirent(): Fix ref count leaks * Only get an additional parent reference, when going to call vnode_path_to_vnode(). * Put the reference of the vnode vnode_path_to_vnode() returns. --- src/system/kernel/fs/vfs.cpp | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index e6bdb00175..d4c14f85de 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -5780,14 +5780,14 @@ fix_dirent(struct vnode* parent, struct dirent* entry, // If this is the ".." entry and the directory covering another vnode, // we need to replace d_dev and d_ino with the actual values. if (strcmp(entry->d_name, "..") == 0 && parent->IsCovering()) { - inc_vnode_ref_count(parent); - // vnode_path_to_vnode() puts the node - // Make sure the IO context root is not bypassed. if (parent == ioContext->root) { entry->d_dev = parent->device; entry->d_ino = parent->id; } else { + inc_vnode_ref_count(parent); + // vnode_path_to_vnode() puts the node + // ".." is guaranteed not to be clobbered by this call struct vnode* vnode; status_t status = vnode_path_to_vnode(parent, (char*)"..", false, 0, @@ -5796,6 +5796,7 @@ fix_dirent(struct vnode* parent, struct dirent* entry, if (status == B_OK) { entry->d_dev = vnode->device; entry->d_ino = vnode->id; + put_vnode(vnode); } } } else { From 0be138ab2f4098d3910880c92f94de8f4c2ea0df Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 23:26:23 +0200 Subject: [PATCH 0067/1170] vfs_bind_mount_directory(): Fail if unmounting --- src/system/kernel/fs/vfs.cpp | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index d4c14f85de..b0433883c4 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -5019,8 +5019,10 @@ vfs_bind_mount_directory(dev_t mountID, ino_t nodeID, dev_t coveredMountID, // establish the covered/covering links WriteLocker locker(sVnodeLock); - if (vnode->covers != NULL || coveredVnode->covered_by != NULL) + if (vnode->covers != NULL || coveredVnode->covered_by != NULL + || vnode->mount->unmounting || coveredVnode->mount->unmounting) { return B_BUSY; + } vnode->covers = coveredVnode; vnode->SetCovering(true); From fe5928847a347b3a46eea68628388e60796e71db Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 21 Jun 2011 23:31:48 +0200 Subject: [PATCH 0068/1170] Completed vfs_bind_mount_directory() support We don't need to explicitly track the covered/covering nodes per mount after all. In fs_unmount() we iterate through all vnodes multiple times anyway and can deal with the covers/covered_by vnodes there. Also, the root vnode doesn't need to be handled specially anymore. --- src/system/kernel/fs/vfs.cpp | 93 ++++++++++++++++++++++++++---------- 1 file changed, 69 insertions(+), 24 deletions(-) diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp index b0433883c4..f070eed822 100644 --- a/src/system/kernel/fs/vfs.cpp +++ b/src/system/kernel/fs/vfs.cpp @@ -5034,8 +5034,6 @@ vfs_bind_mount_directory(dev_t mountID, ino_t nodeID, dev_t coveredMountID, inc_vnode_ref_count(vnode); inc_vnode_ref_count(coveredVnode); -// TODO: This relationship must be tracked, so it can be dissolved on unmount. - return B_OK; } @@ -7473,11 +7471,20 @@ fs_unmount(char* path, dev_t mountID, uint32 flags, bool kernel) // make sure all of them are not busy or have refs on them VnodeList::Iterator iterator = mount->vnodes.GetIterator(); while (struct vnode* vnode = iterator.Next()) { - // The root vnode ref_count needs to be 1 here (the mount has a - // reference). - if (vnode->IsBusy() - || ((vnode->ref_count != 0 && mount->root_vnode != vnode) - || (vnode->ref_count != 1 && mount->root_vnode == vnode))) { + if (vnode->IsBusy()) { + busy = true; + break; + } + + // check the vnode's ref count -- subtract additional references for + // covering + int32 refCount = vnode->ref_count; + if (vnode->covers != NULL) + refCount--; + if (vnode->covered_by != NULL) + refCount--; + + if (refCount != 0) { // there are still vnodes in use on this mount, so we cannot // unmount yet busy = true; @@ -7515,37 +7522,75 @@ fs_unmount(char* path, dev_t mountID, uint32 flags, bool kernel) vnodesWriteLocker.Lock(); } - // we can safely continue, mark all of the vnodes busy and this mount - // structure in unmounting state + // We can safely continue. Mark all of the vnodes busy and this mount + // structure in unmounting state. Also undo the vnode covers/covered_by + // links. mount->unmounting = true; VnodeList::Iterator iterator = mount->vnodes.GetIterator(); while (struct vnode* vnode = iterator.Next()) { + // Remove all covers/covered_by links from other mounts' nodes to this + // vnode and adjust the node ref count accordingly. We will release the + // references to the external vnodes below. + if (Vnode* coveredNode = vnode->covers) { + if (Vnode* coveringNode = vnode->covered_by) { + // We have both covered and covering vnodes, so just remove us + // from the chain. + coveredNode->covered_by = coveringNode; + coveringNode->covers = coveredNode; + vnode->ref_count -= 2; + + vnode->covered_by = NULL; + vnode->covers = NULL; + vnode->SetCovering(false); + vnode->SetCovered(false); + } else { + // We only have a covered vnode. Remove its link to us. + coveredNode->covered_by = NULL; + coveredNode->SetCovered(false); + vnode->ref_count--; + + // If the other node is an external vnode, we keep its link + // link around so we can put the reference later on. Otherwise + // we get rid of it right now. + if (coveredNode->mount == mount) { + vnode->covers = NULL; + coveredNode->ref_count--; + } + } + } else if (Vnode* coveringNode = vnode->covered_by) { + // We only have a covering vnode. Remove its link to us. + coveringNode->covers = NULL; + coveringNode->SetCovering(false); + vnode->ref_count--; + + // If the other node is an external vnode, we keep its link + // link around so we can put the reference later on. Otherwise + // we get rid of it right now. + if (coveringNode->mount == mount) { + vnode->covered_by = NULL; + coveringNode->ref_count--; + } + } + vnode->SetBusy(true); vnode_to_be_freed(vnode); } - // The ref_count of the root node is 1 at this point, see above why this is - mount->root_vnode->ref_count--; - vnode_to_be_freed(mount->root_vnode); - - Vnode* coveredNode = mount->root_vnode->covers; - coveredNode->covered_by = mount->root_vnode->covered_by; - coveredNode->SetCovered(coveredNode->covered_by != NULL); - - mount->root_vnode->covered_by = NULL; - mount->root_vnode->SetCovered(false); - mount->root_vnode->SetCovering(false); - vnodesWriteLocker.Unlock(); - put_vnode(coveredNode); - // Free all vnodes associated with this mount. // They will be removed from the mount list by free_vnode(), so // we don't have to do this. - while (struct vnode* vnode = mount->vnodes.Head()) + while (struct vnode* vnode = mount->vnodes.Head()) { + // Put the references to external covered/covering vnodes we kept above. + if (Vnode* coveredNode = vnode->covers) + put_vnode(coveredNode); + if (Vnode* coveringNode = vnode->covered_by) + put_vnode(coveringNode); + free_vnode(vnode, false); + } // remove the mount structure from the hash table mutex_lock(&sMountMutex); From 5957270c72c705a132afc6280943f92297b34cc3 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 22 Jun 2011 01:29:21 +0200 Subject: [PATCH 0069/1170] Print the package version nicely --- src/bin/package/command_list.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp index c7ba11284b..9bd831c727 100644 --- a/src/bin/package/command_list.cpp +++ b/src/bin/package/command_list.cpp @@ -150,7 +150,9 @@ struct PackageContentListHandler : BPackageContentHandler { break; case B_PACKAGE_INFO_VERSION: + printf("\tversion: "); _PrintPackageVersion(value.version); + printf("\n"); break; case B_PACKAGE_INFO_COPYRIGHTS: From 6e6ca8c530399ac66a4ec670f34b32e39c0f2de3 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 22 Jun 2011 01:31:35 +0200 Subject: [PATCH 0070/1170] Fix resolvable name --- src/data/package_infos/haiku-userguide | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/data/package_infos/haiku-userguide b/src/data/package_infos/haiku-userguide index 6a24f6c236..9829a15477 100644 --- a/src/data/package_infos/haiku-userguide +++ b/src/data/package_infos/haiku-userguide @@ -11,7 +11,7 @@ copyright = "2001-2011 Haiku, Inc. et al" licenses = [ "MIT" ] provides = [ - haiku-welcome + haiku-userguide ] requires = [ From ddabac20deacc7bef7a526d53a9856ec7c9d3d3a Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 22 Jun 2011 01:59:24 +0200 Subject: [PATCH 0071/1170] Rename Package "name" property to "fileName" --- .../kernel/file_systems/packagefs/Package.cpp | 18 ++++++------ .../kernel/file_systems/packagefs/Package.h | 28 +++++++++---------- .../file_systems/packagefs/PackageDomain.cpp | 6 ++-- .../file_systems/packagefs/PackageDomain.h | 8 +++--- .../kernel/file_systems/packagefs/Volume.cpp | 4 +-- 5 files changed, 32 insertions(+), 32 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.cpp b/src/add-ons/kernel/file_systems/packagefs/Package.cpp index e0123a6926..dd170dbe21 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Package.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Package.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -21,7 +21,7 @@ Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID) : fDomain(domain), - fName(NULL), + fFileName(NULL), fFD(-1), fOpenCount(0), fNodeID(nodeID), @@ -36,17 +36,17 @@ Package::~Package() while (PackageNode* node = fNodes.RemoveHead()) node->ReleaseReference(); - free(fName); + free(fFileName); mutex_destroy(&fLock); } status_t -Package::Init(const char* name) +Package::Init(const char* fileName) { - fName = strdup(name); - if (fName == NULL) + fFileName = strdup(fileName); + if (fFileName == NULL) RETURN_ERROR(B_NO_MEMORY); return B_OK; @@ -71,16 +71,16 @@ Package::Open() } // open the file - fFD = openat(fDomain->DirectoryFD(), fName, O_RDONLY); + fFD = openat(fDomain->DirectoryFD(), fFileName, O_RDONLY); if (fFD < 0) { - ERROR("Failed to open package file \"%s\"\n", fName); + ERROR("Failed to open package file \"%s\"\n", fFileName); return errno; } // stat it to verify that it's still the same file struct stat st; if (fstat(fFD, &st) < 0) { - ERROR("Failed to stat package file \"%s\"\n", fName); + ERROR("Failed to stat package file \"%s\"\n", fFileName); close(fFD); fFD = -1; return errno; diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.h b/src/add-ons/kernel/file_systems/packagefs/Package.h index 17f76633ec..a784accd2b 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Package.h +++ b/src/add-ons/kernel/file_systems/packagefs/Package.h @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef PACKAGE_H @@ -25,28 +25,28 @@ public: ino_t nodeID); ~Package(); - status_t Init(const char* name); + status_t Init(const char* fileName); - PackageDomain* Domain() const { return fDomain; } - const char* Name() const { return fName; } + PackageDomain* Domain() const { return fDomain; } + const char* FileName() const { return fFileName; } - Package*& HashTableNext() { return fHashTableNext; } + Package*& FileNameHashTableNext() + { return fFileNameHashTableNext; } void AddNode(PackageNode* node); int Open(); void Close(); - const PackageNodeList& Nodes() const - { return fNodes; } + const PackageNodeList& Nodes() const { return fNodes; } private: mutex fLock; PackageDomain* fDomain; - char* fName; + char* fFileName; int fFD; uint32 fOpenCount; - Package* fHashTableNext; + Package* fFileNameHashTableNext; ino_t fNodeID; dev_t fDeviceID; PackageNodeList fNodes; @@ -76,7 +76,7 @@ private: }; -struct PackageHashDefinition { +struct PackageFileNameHashDefinition { typedef const char* KeyType; typedef Package ValueType; @@ -87,22 +87,22 @@ struct PackageHashDefinition { size_t Hash(const Package* value) const { - return HashKey(value->Name()); + return HashKey(value->FileName()); } bool Compare(const char* key, const Package* value) const { - return strcmp(value->Name(), key) == 0; + return strcmp(value->FileName(), key) == 0; } Package*& GetLink(Package* value) const { - return value->HashTableNext(); + return value->FileNameHashTableNext(); } }; -typedef BOpenHashTable PackageHashTable; +typedef BOpenHashTable PackageFileNameHashTable; #endif // PACKAGE_H diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp index f060f2e89d..a44786f2ff 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp @@ -41,7 +41,7 @@ PackageDomain::~PackageDomain() Package* package = fPackages.Clear(true); while (package != NULL) { - Package* next = package->HashTableNext(); + Package* next = package->FileNameHashTableNext(); package->ReleaseReference(); package = next; } @@ -113,7 +113,7 @@ PackageDomain::RemovePackage(Package* package) Package* -PackageDomain::FindPackage(const char* name) const +PackageDomain::FindPackage(const char* fileName) const { - return fPackages.Lookup(name); + return fPackages.Lookup(fileName); } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h index e203f39f36..ac39020693 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef PACKAGE_DOMAIN_H @@ -34,9 +34,9 @@ public: void AddPackage(Package* package); void RemovePackage(Package* package); - Package* FindPackage(const char* name) const; + Package* FindPackage(const char* fileName) const; - const PackageHashTable& Packages() const + const PackageFileNameHashTable& Packages() const { return fPackages; } private: @@ -45,7 +45,7 @@ private: dev_t fDeviceID; ino_t fNodeID; NotificationListener* fListener; - PackageHashTable fPackages; + PackageFileNameHashTable fPackages; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 447c21e69d..7c1676f805 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -603,8 +603,8 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify) // add the packages to the node tree VolumeWriteLocker volumeLocker(this); - for (PackageHashTable::Iterator it = domain->Packages().GetIterator(); - Package* package = it.Next();) { + for (PackageFileNameHashTable::Iterator it + = domain->Packages().GetIterator(); Package* package = it.Next();) { error = _AddPackageContent(package, notify); if (error != B_OK) { for (it.Rewind(); Package* activePackage = it.Next();) { From 01102ee50e3e6ade8bdfe88b9a991ff42d01c364 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 16:27:24 +0200 Subject: [PATCH 0072/1170] WIP towards packagefs package links support * Introduce Version class representing a version. * Introduce Dependency and Resolvable class and add lists of either to Package. * Parse package attributes and add dependencies and resolvables to Package. * Add a mount type to Volume and add a respective mount parameter "mount-type" (values "system", "common", "home", "custom"). Also implies the shine-through type, if that's not given. * Introduce class PackageFamily which groups equally named and versioned packages. * Add class PackageFSRoot. Each instance represents a possible file system root (separate roots for different chroot environments). Tracks Volumes belonging to the same root and their packages. --- .../file_systems/packagefs/Dependency.cpp | 50 +++ .../file_systems/packagefs/Dependency.h | 54 +++ .../kernel/file_systems/packagefs/Jamfile | 18 +- .../kernel/file_systems/packagefs/Package.cpp | 50 +++ .../kernel/file_systems/packagefs/Package.h | 29 +- .../file_systems/packagefs/PackageDomain.cpp | 3 +- .../file_systems/packagefs/PackageDomain.h | 5 +- .../file_systems/packagefs/PackageFSRoot.cpp | 308 ++++++++++++++++++ .../file_systems/packagefs/PackageFSRoot.h | 109 +++++++ .../file_systems/packagefs/PackageFamily.cpp | 78 +++++ .../file_systems/packagefs/PackageFamily.h | 71 ++++ .../file_systems/packagefs/Resolvable.cpp | 40 +++ .../file_systems/packagefs/Resolvable.h | 38 +++ .../kernel/file_systems/packagefs/Version.cpp | 173 ++++++++++ .../kernel/file_systems/packagefs/Version.h | 44 +++ .../kernel/file_systems/packagefs/Volume.cpp | 211 ++++++++++-- .../kernel/file_systems/packagefs/Volume.h | 32 +- .../packagefs/kernel_interface.cpp | 10 + 18 files changed, 1293 insertions(+), 30 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/Dependency.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/Dependency.h create mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h create mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageFamily.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageFamily.h create mode 100644 src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/Resolvable.h create mode 100644 src/add-ons/kernel/file_systems/packagefs/Version.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/Version.h diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp new file mode 100644 index 0000000000..4b8762caa2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp @@ -0,0 +1,50 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "Dependency.h" + +#include +#include + +#include "Version.h" + + +Dependency::Dependency(Package* package) + : + fPackage(package), + fResolvable(NULL), + fName(NULL), + fVersion(NULL), + fVersionOperator(B_PACKAGE_RESOLVABLE_OP_EQUAL) +{ +} + + +Dependency::~Dependency() +{ + free(fName); + delete fVersion; +} + + +status_t +Dependency::Init(const char* name) +{ + fName = strdup(name); + if (fName == NULL) + return B_NO_MEMORY; + + return B_OK; +} + + +void +Dependency::SetVersionRequirement(BPackageResolvableOperator op, + Version* version) +{ + fVersionOperator = op; + fVersion = version; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.h b/src/add-ons/kernel/file_systems/packagefs/Dependency.h new file mode 100644 index 0000000000..e2027f8d1b --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.h @@ -0,0 +1,54 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef DEPENDENCY_H +#define DEPENDENCY_H + + +#include + +#include + +#include + + +class Package; +class Resolvable; +class Version; + + +using BPackageKit::BPackageResolvableOperator; + + +class Dependency : public BReferenceable, + public DoublyLinkedListLinkImpl { +public: + Dependency(Package* package); + virtual ~Dependency(); + + status_t Init(const char* name); + void SetVersionRequirement( + BPackageResolvableOperator op, + Version* version); + // version is optional; object takes over + // ownership + + void SetResolvable(::Resolvable* resolvable) + { fResolvable = resolvable; } + ::Resolvable* Resolvable() const + { return fResolvable; } + +private: + Package* fPackage; + ::Resolvable* fResolvable; + char* fName; + Version* fVersion; + BPackageResolvableOperator fVersionOperator; +}; + + +typedef DoublyLinkedList DependencyList; + + +#endif // DEPENDENCY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index c38e91f350..e07bf10a49 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -5,13 +5,11 @@ UseLibraryHeaders zlib ; UsePrivateKernelHeaders ; UsePrivateHeaders shared ; -DEFINES += B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT ; - # TODO: Remove when it is complete! - HAIKU_PACKAGE_FS_SOURCES = BlockBufferCacheKernel.cpp DebugSupport.cpp + Dependency.cpp Directory.cpp GlobalFactory.cpp kernel_interface.cpp @@ -20,11 +18,15 @@ HAIKU_PACKAGE_FS_SOURCES = Package.cpp PackageDirectory.cpp PackageDomain.cpp + PackageFamily.cpp PackageFile.cpp + PackageFSRoot.cpp PackageLeafNode.cpp PackageNode.cpp PackageNodeAttribute.cpp PackageSymlink.cpp + Resolvable.cpp + Version.cpp Volume.cpp ; @@ -50,6 +52,11 @@ HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES = ; +local libSharedSources = + NaturalCompare.cpp +; + + SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ; @@ -57,9 +64,14 @@ KernelAddon packagefs : $(HAIKU_PACKAGE_FS_SOURCES) $(HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES) + $(libSharedSources) : $(HAIKU_STATIC_LIBSUPC++) libz.a ; +SEARCH on [ FGristFiles $(libSharedSources) ] + += [ FDirName $(HAIKU_TOP) src kits shared ] ; + + HaikuSubInclude userland ; diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.cpp b/src/add-ons/kernel/file_systems/packagefs/Package.cpp index dd170dbe21..0221ce1ed4 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Package.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Package.cpp @@ -16,12 +16,16 @@ #include "DebugSupport.h" #include "PackageDomain.h" +#include "Version.h" Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID) : fDomain(domain), fFileName(NULL), + fName(NULL), + fVersion(NULL), + fFamily(NULL), fFD(-1), fOpenCount(0), fNodeID(nodeID), @@ -36,7 +40,15 @@ Package::~Package() while (PackageNode* node = fNodes.RemoveHead()) node->ReleaseReference(); + while (Resolvable* resolvable = fResolvables.RemoveHead()) + delete resolvable; + + while (Dependency* dependency = fDependencies.RemoveHead()) + delete dependency; + free(fFileName); + free(fName); + delete fVersion; mutex_destroy(&fLock); } @@ -53,6 +65,30 @@ Package::Init(const char* fileName) } +status_t +Package::SetName(const char* name) +{ + if (fName != NULL) + free(fName); + + fName = strdup(name); + if (fName == NULL) + RETURN_ERROR(B_NO_MEMORY); + + return B_OK; +} + + +void +Package::SetVersion(::Version* version) +{ + if (fVersion != NULL) + delete fVersion; + + fVersion = version; +} + + void Package::AddNode(PackageNode* node) { @@ -61,6 +97,20 @@ Package::AddNode(PackageNode* node) } +void +Package::AddResolvable(Resolvable* resolvable) +{ + fResolvables.Add(resolvable); +} + + +void +Package::AddDependency(Dependency* dependency) +{ + fDependencies.Add(dependency); +} + + int Package::Open() { diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.h b/src/add-ons/kernel/file_systems/packagefs/Package.h index a784accd2b..7d63ac27d1 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Package.h +++ b/src/add-ons/kernel/file_systems/packagefs/Package.h @@ -8,18 +8,24 @@ #include +#include #include #include #include +#include "Dependency.h" #include "PackageNode.h" +#include "Resolvable.h" class PackageDomain; +class PackageFamily; +class Version; -class Package : public BReferenceable { +class Package : public BReferenceable, + public DoublyLinkedListLinkImpl { public: Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID); @@ -30,10 +36,25 @@ public: PackageDomain* Domain() const { return fDomain; } const char* FileName() const { return fFileName; } + status_t SetName(const char* name); + const char* Name() const { return fName; } + + void SetVersion(::Version* version); + // takes over object ownership + ::Version* Version() const + { return fVersion; } + + void SetFamily(PackageFamily* family) + { fFamily = family; } + PackageFamily* Family() const + { return fFamily; } + Package*& FileNameHashTableNext() { return fFileNameHashTableNext; } void AddNode(PackageNode* node); + void AddResolvable(Resolvable* resolvable); + void AddDependency(Dependency* dependency); int Open(); void Close(); @@ -44,12 +65,17 @@ private: mutex fLock; PackageDomain* fDomain; char* fFileName; + char* fName; + ::Version* fVersion; + PackageFamily* fFamily; int fFD; uint32 fOpenCount; Package* fFileNameHashTableNext; ino_t fNodeID; dev_t fDeviceID; PackageNodeList fNodes; + ResolvableList fResolvables; + DependencyList fDependencies; }; @@ -103,6 +129,7 @@ struct PackageFileNameHashDefinition { typedef BOpenHashTable PackageFileNameHashTable; +typedef DoublyLinkedList PackageList; #endif // PACKAGE_H diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp index a44786f2ff..d2f4ceaa57 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp @@ -21,8 +21,9 @@ #include "DebugSupport.h" -PackageDomain::PackageDomain() +PackageDomain::PackageDomain(::Volume* volume) : + fVolume(volume), fPath(NULL), fDirFD(-1), fListener(NULL) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h index ac39020693..67c0354fd0 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h @@ -14,14 +14,16 @@ class NotificationListener; +class Volume; class PackageDomain : public BReferenceable, public DoublyLinkedListLinkImpl { public: - PackageDomain(); + PackageDomain(::Volume* volume); ~PackageDomain(); + ::Volume* Volume() const { return fVolume; } const char* Path() const { return fPath; } int DirectoryFD() { return fDirFD; } dev_t DeviceID() { return fDeviceID; } @@ -40,6 +42,7 @@ public: { return fPackages; } private: + ::Volume* fVolume; char* fPath; int fDirFD; dev_t fDeviceID; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp new file mode 100644 index 0000000000..e91adafa05 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp @@ -0,0 +1,308 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "PackageFSRoot.h" + +#include + +#include + +#include "DebugSupport.h" + + +mutex PackageFSRoot::sRootListLock = MUTEX_INITIALIZER("packagefs root list"); +PackageFSRoot::RootList PackageFSRoot::sRootList; + + +PackageFSRoot::PackageFSRoot(dev_t deviceID, ino_t nodeID) + : + fDeviceID(deviceID), + fNodeID(nodeID), + fSystemVolume(NULL) +{ + rw_lock_init(&fLock, "packagefs root"); +} + + +PackageFSRoot::~PackageFSRoot() +{ + rw_lock_destroy(&fLock); +} + + +/*static*/ status_t +PackageFSRoot::GlobalInit() +{ + return B_OK; +} + + +/*static*/ void +PackageFSRoot::GlobalUninit() +{ +} + + +status_t +PackageFSRoot::Init() +{ + status_t error = fPackageFamilies.Init(); + if (error != B_OK) + RETURN_ERROR(error); + + return B_OK; +} + + +/*static*/ status_t +PackageFSRoot::RegisterVolume(Volume* volume) +{ + // Unless the volume is custom mounted, we stat the supposed root directory. + // Get the volume mount point relative path to the root directory depending + // on the mount type. + const char* relativeRootPath = NULL; + + switch (volume->MountType()) { + case MOUNT_TYPE_SYSTEM: + case MOUNT_TYPE_COMMON: + relativeRootPath = ".."; + break; + case MOUNT_TYPE_HOME: + relativeRootPath = "../.."; + break; + case MOUNT_TYPE_CUSTOM: + default: + break; + } + + if (relativeRootPath != NULL) { + struct vnode* vnode; + status_t error = vfs_entry_ref_to_vnode(volume->MountPointDeviceID(), + volume->MountPointNodeID(), relativeRootPath, &vnode); + if (error != B_OK) { + dprintf("packagefs: Failed to get root directory \"%s\": %s\n", + relativeRootPath, strerror(error)); + RETURN_ERROR(error); + } + CObjectDeleter vnodePutter(vnode, &vfs_put_vnode); + + // stat it + struct stat st; + error = vfs_stat_vnode(vnode, &st); + if (error != B_OK) { + dprintf("packagefs: Failed to stat root directory \"%s\": %s\n", + relativeRootPath, strerror(error)); + RETURN_ERROR(error); + } + + // get/create the root + PackageFSRoot* root; + error = PackageFSRoot::_GetOrCreateRoot(st.st_dev, st.st_ino, root); + if (error != B_OK) + RETURN_ERROR(error); + + // add the volume + error = root->_AddVolume(volume); + if (error != B_OK) { + _PutRoot(root); + RETURN_ERROR(error); + } + + return B_OK; + } + + // custom mount -- always create a new root + PackageFSRoot* root = new(std::nothrow) PackageFSRoot(-1, 0); + if (root == NULL) + return B_NO_MEMORY; + ObjectDeleter rootDeleter(root); + + status_t error = root->Init(); + if (error != B_OK) + RETURN_ERROR(error); + + // add the volume + error = root->_AddVolume(volume); + if (error != B_OK) { + _PutRoot(root); + RETURN_ERROR(error); + } + + // We don't add the root to the list. + rootDeleter.Detach(); + return B_OK; +} + + +void +PackageFSRoot::UnregisterVolume(Volume* volume) +{ + _RemoveVolume(volume); + _PutRoot(this); +} + + +status_t +PackageFSRoot::AddPackage(Package* package) +{ + // Create a package family -- there might already be one, but since that's + // unlikely, we don't bother to check and recheck later. + PackageFamily* packageFamily = new(std::nothrow) PackageFamily; + if (packageFamily == NULL) + return B_NO_MEMORY; + ObjectDeleter packageFamilyDeleter(packageFamily); + + status_t error = packageFamily->Init(package); + if (error != B_OK) + RETURN_ERROR(error); + + // add the family + PackageFSRootWriteLocker writeLocker(this); + if (PackageFamily* otherPackageFamily + = fPackageFamilies.Lookup(packageFamily->Name())) { + packageFamily->RemovePackage(package); + packageFamily = otherPackageFamily; + packageFamily->AddPackage(package); + } else + fPackageFamilies.Insert(packageFamilyDeleter.Detach()); + +// TODO:... + + return B_OK; +} + + +void +PackageFSRoot::RemovePackage(Package* package) +{ + PackageFSRootWriteLocker writeLocker(this); + + PackageFamily* packageFamily = package->Family(); + if (packageFamily == NULL) + return; + + packageFamily->RemovePackage(package); + + if (packageFamily->IsEmpty()) { + fPackageFamilies.Remove(packageFamily); + delete packageFamily; + } + +// TODO:... +} + + +Volume* +PackageFSRoot::SystemVolume() const +{ + PackageFSRootReadLocker readLocker(this); + return fSystemVolume; +} + + +status_t +PackageFSRoot::_AddVolume(Volume* volume) +{ + PackageFSRootWriteLocker writeLocker(this); + + volume->SetPackageFSRoot(this); + + fVolumes.Add(volume); + // TODO: Correct order? + + if (fSystemVolume == NULL && volume->MountType() == MOUNT_TYPE_SYSTEM) + fSystemVolume = volume; + + return B_OK; +} + + +void +PackageFSRoot::_RemoveVolume(Volume* volume) +{ + PackageFSRootWriteLocker writeLocker(this); + + if (volume == fSystemVolume) + fSystemVolume = NULL; + + fVolumes.Remove(volume); + + volume->SetPackageFSRoot(NULL); +} + + +/*static*/ status_t +PackageFSRoot::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, + PackageFSRoot*& _root) +{ + // first check the list, if the root already exists + MutexLocker rootListLocker(sRootListLock); + + if (PackageFSRoot* root = _FindRootLocked(deviceID, nodeID)) { + root->AcquireReference(); + _root = root; + return B_OK; + } + + rootListLocker.Unlock(); + + // create a new root + PackageFSRoot* root = new(std::nothrow) PackageFSRoot(deviceID, nodeID); + if (root == NULL) + return B_NO_MEMORY; + ObjectDeleter rootDeleter(root); + + status_t error = root->Init(); + if (error != B_OK) + RETURN_ERROR(error); + + // add the root -- first recheck whether someone else added the root in the + // meantime + rootListLocker.Lock(); + + if (PackageFSRoot* otherRoot = _FindRootLocked(deviceID, nodeID)) { + // indeed, someone was faster + otherRoot->AcquireReference(); + _root = otherRoot; + return B_OK; + } + + sRootList.Add(root); + + _root = rootDeleter.Detach(); + return B_OK; +} + + +/*static*/ PackageFSRoot* +PackageFSRoot::_FindRootLocked(dev_t deviceID, ino_t nodeID) +{ + for (RootList::Iterator it = sRootList.GetIterator(); + PackageFSRoot* root = it.Next();) { + if (root->DeviceID() == deviceID && root->NodeID() == nodeID) + return root; + } + + return NULL; +} + + +/*static*/ void +PackageFSRoot::_PutRoot(PackageFSRoot* root) +{ + // Only non-custom roots are in the global list. + if (!root->IsCustom()) { + MutexLocker rootListLocker(sRootListLock); + + // When releasing the last reference, remove the root from the list. + if (root->CountReferences() == 1) + sRootList.Remove(root); + + rootListLocker.Unlock(); + } + + root->ReleaseReference(); +} diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h new file mode 100644 index 0000000000..9f08229971 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h @@ -0,0 +1,109 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef PACKAGE_FS_ROOT_H +#define PACKAGE_FS_ROOT_H + + +#include + +#include +#include + +#include + +#include "PackageFamily.h" +#include "Volume.h" + + +class PackageFSRoot : private BReferenceable, + public DoublyLinkedListLinkImpl { +public: + // constructor and destructor are conceptually private + PackageFSRoot(dev_t deviceID, ino_t nodeID); + virtual ~PackageFSRoot(); + + static status_t GlobalInit(); + static void GlobalUninit(); + + inline bool ReadLock() const; + inline void ReadUnlock() const; + inline bool WriteLock(); + inline void WriteUnlock(); + + status_t Init(); + + static status_t RegisterVolume(Volume* volume); + void UnregisterVolume(Volume* volume); + + status_t AddPackage(Package* package); + void RemovePackage(Package* package); + + dev_t DeviceID() const { return fDeviceID; } + ino_t NodeID() const { return fNodeID; } + bool IsCustom() const { return fDeviceID < 0; } + + Volume* SystemVolume() const; + +private: + typedef DoublyLinkedList RootList; + typedef DoublyLinkedList VolumeList; + +private: + status_t _AddVolume(Volume* volume); + void _RemoveVolume(Volume* volume); + + static status_t _GetOrCreateRoot(dev_t deviceID, ino_t nodeID, + PackageFSRoot*& _root); + static PackageFSRoot* _FindRootLocked(dev_t deviceID, ino_t nodeID); + static void _PutRoot(PackageFSRoot* root); + +private: + static mutex sRootListLock; + static RootList sRootList; + + mutable rw_lock fLock; + dev_t fDeviceID; + ino_t fNodeID; + VolumeList fVolumes; + Volume* fSystemVolume; + PackageFamilyHashTable fPackageFamilies; +}; + + +bool +PackageFSRoot::ReadLock() const +{ + return rw_lock_read_lock(&fLock) == B_OK; +} + + +void +PackageFSRoot::ReadUnlock() const +{ + rw_lock_read_unlock(&fLock); +} + + +bool +PackageFSRoot::WriteLock() +{ + return rw_lock_write_lock(&fLock) == B_OK; +} + + +void +PackageFSRoot::WriteUnlock() +{ + rw_lock_write_unlock(&fLock); +} + + +typedef AutoLocker > PackageFSRootReadLocker; +typedef AutoLocker > + PackageFSRootWriteLocker; + + +#endif // PACKAGE_FS_ROOT_H diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFamily.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFamily.cpp new file mode 100644 index 0000000000..18ca55b67b --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFamily.cpp @@ -0,0 +1,78 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "PackageFamily.h" + +#include +#include + +#include "DebugSupport.h" +#include "Version.h" + + +PackageFamily::PackageFamily() + : + fName(NULL) +{ +} + + +PackageFamily::~PackageFamily() +{ + while (Package* package = fPackages.RemoveHead()) + package->SetFamily(NULL); + + free(fName); +} + + +status_t +PackageFamily::Init(Package* package) +{ + // compute the allocation size needed for the versioned name + size_t nameLength = strlen(package->Name()); + size_t size = nameLength + 1; + + Version* version = package->Version(); + if (version != NULL) { + size += 1 + version->ToString(NULL, 0); + // + 1 for the '-' + } + + // allocate the name and compose it + fName = (char*)malloc(size); + if (fName == NULL) + return B_NO_MEMORY; + + memcpy(fName, package->Name(), nameLength + 1); + if (version != NULL) { + fName[nameLength] = '-'; + version->ToString(fName + nameLength + 1, size - nameLength - 1); + } + + // add the package + AddPackage(package); + + return B_OK; +} + + +void +PackageFamily::AddPackage(Package* package) +{ + fPackages.Add(package); + package->SetFamily(this); +} + + +void +PackageFamily::RemovePackage(Package* package) +{ + ASSERT(package->Family() == this); + + package->SetFamily(NULL); + fPackages.Remove(package); +} diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFamily.h b/src/add-ons/kernel/file_systems/packagefs/PackageFamily.h new file mode 100644 index 0000000000..33939a0b54 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFamily.h @@ -0,0 +1,71 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef PACKAGE_FAMILY_H +#define PACKAGE_FAMILY_H + + +#include + +#include "Package.h" + + +/*! A set of equally named and versioned packages. + This should only happen when the same package is installed in multiple + domains (e.g. common and home). +*/ +class PackageFamily { +public: + PackageFamily(); + ~PackageFamily(); + + status_t Init(Package* package); + + const char* Name() const { return fName; } + + void AddPackage(Package* package); + void RemovePackage(Package* package); + + bool IsEmpty() const + { return fPackages.IsEmpty(); } + + PackageFamily*& HashNext() { return fHashNext; } + +private: + PackageFamily* fHashNext; + char* fName; + PackageList fPackages; +}; + + +struct PackageFamilyHashDefinition { + typedef const char* KeyType; + typedef PackageFamily ValueType; + + size_t HashKey(const char* key) const + { + return hash_hash_string(key); + } + + size_t Hash(const PackageFamily* value) const + { + return HashKey(value->Name()); + } + + bool Compare(const char* key, const PackageFamily* value) const + { + return strcmp(value->Name(), key) == 0; + } + + PackageFamily*& GetLink(PackageFamily* value) const + { + return value->HashNext(); + } +}; + + +typedef BOpenHashTable PackageFamilyHashTable; + + +#endif // PACKAGE_FAMILY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp b/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp new file mode 100644 index 0000000000..7e00edb05f --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp @@ -0,0 +1,40 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "Resolvable.h" + +#include + +#include "Version.h" + + +Resolvable::Resolvable(Package* package) + : + fPackage(package), + fName(NULL), + fVersion(NULL) +{ +} + + +Resolvable::~Resolvable() +{ + free(fName); + delete fVersion; +} + + +status_t +Resolvable::Init(const char* name, Version* version) +{ + fVersion = version; + + fName = strdup(name); + if (fName == NULL) + return B_NO_MEMORY; + + return B_OK; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Resolvable.h b/src/add-ons/kernel/file_systems/packagefs/Resolvable.h new file mode 100644 index 0000000000..e73f6affc8 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/Resolvable.h @@ -0,0 +1,38 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef RESOLVABLE_H +#define RESOLVABLE_H + + +#include + +#include + + +class Package; +class Version; + + +class Resolvable : public BReferenceable, + public DoublyLinkedListLinkImpl { +public: + Resolvable(Package* package); + virtual ~Resolvable(); + + status_t Init(const char* name, Version* version); + // version is optional; object takes over + // ownership (even in case of error) + +private: + Package* fPackage; + char* fName; + Version* fVersion; +}; + + +typedef DoublyLinkedList ResolvableList; + + +#endif // RESOLVABLE_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Version.cpp b/src/add-ons/kernel/file_systems/packagefs/Version.cpp new file mode 100644 index 0000000000..8ab800c23b --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/Version.cpp @@ -0,0 +1,173 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "Version.h" + +#include +#include +#include + +#include + +#include + +#include "DebugSupport.h" + + +static const char* const kVersionPartPlaceholder = "_"; + + +static int +compare_version_part(const char* a, const char* b) +{ + if (a == NULL) + return b != NULL ? -1 : 0; + if (b == NULL) + return 1; + + return BPrivate::NaturalCompare(a, b); +} + + +Version::Version() + : + fMajor(NULL), + fMinor(NULL), + fMicro(NULL), + fRelease(0) +{ +} + + +Version::~Version() +{ + free(fMajor); + free(fMinor); + free(fMicro); +} + + +status_t +Version::Init(const char* major, const char* minor, const char* micro, + uint8 release) +{ + if (major != NULL) { + fMajor = strdup(major); + if (fMajor == NULL) + return B_NO_MEMORY; + } + + if (minor != NULL) { + fMinor = strdup(major); + if (fMinor == NULL) + return B_NO_MEMORY; + } + + if (micro != NULL) { + fMicro = strdup(micro); + if (fMicro == NULL) + return B_NO_MEMORY; + } + + fRelease = release; + + return B_OK; +} + + +/*static*/ status_t +Version::Create(const char* major, const char* minor, const char* micro, + uint8 release, Version*& _version) +{ + Version* version = new(std::nothrow) Version; + if (version == NULL) + return B_NO_MEMORY; + + status_t error = version->Init(major, minor, micro, release); + if (error != B_OK) { + delete version; + return error; + } + + _version = version; + return B_OK; +} + + +int +Version::Compare(const Version& other) const +{ + int cmp = compare_version_part(fMajor, other.fMajor); + if (cmp != 0) + return cmp; + + cmp = compare_version_part(fMinor, other.fMinor); + if (cmp != 0) + return cmp; + + cmp = compare_version_part(fMicro, other.fMicro); + if (cmp != 0) + return cmp; + + return (int)fRelease - other.fRelease; +} + + +bool +Version::Compare(BPackageResolvableOperator op, + const Version& other) const +{ + int cmp = Compare(other); + + switch (op) { + case B_PACKAGE_RESOLVABLE_OP_LESS: + return cmp < 0; + case B_PACKAGE_RESOLVABLE_OP_LESS_EQUAL: + return cmp <= 0; + case B_PACKAGE_RESOLVABLE_OP_EQUAL: + return cmp == 0; + case B_PACKAGE_RESOLVABLE_OP_NOT_EQUAL: + return cmp != 0; + case B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL: + return cmp >= 0; + case B_PACKAGE_RESOLVABLE_OP_GREATER: + return cmp > 0; + default: + ERROR("packagefs: Version::Compare(): Invalid operator %d\n", op); + return false; + } +} + + +size_t +Version::ToString(char* buffer, size_t bufferSize) const +{ + // We need to normalize the version string somewhat. If a subpart is given, + // make sure that also the superparts are defined, using a placeholder. This + // avoids clashes, e.g. if one version defines only major and one only + // micro. + const char* major = fMajor; + const char* minor = fMinor; + const char* micro = fMicro; + + if (micro != NULL && minor == NULL) + minor = kVersionPartPlaceholder; + if (minor != NULL && major == NULL) + major = kVersionPartPlaceholder; + + if (micro != NULL) { + return snprintf(buffer, bufferSize, "%s.%s.%s-%u", major, minor, micro, + fRelease); + } + + if (minor != NULL) + return snprintf(buffer, bufferSize, "%s.%s-%u", major, minor, fRelease); + + if (major != NULL) + return snprintf(buffer, bufferSize, "%s-%u", major, fRelease); + + return snprintf(buffer, bufferSize, "%u", fRelease); +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Version.h b/src/add-ons/kernel/file_systems/packagefs/Version.h new file mode 100644 index 0000000000..1c72731215 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/Version.h @@ -0,0 +1,44 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef VERSION_H +#define VERSION_H + + +#include +#include + + +using namespace BPackageKit; + + +class Version { +public: + Version(); + ~Version(); + + status_t Init(const char* major, const char* minor, + const char* micro, uint8 release); + + static status_t Create(const char* major, const char* minor, + const char* micro, uint8 release, + Version*& _version); + + int Compare(const Version& other) const; + bool Compare(BPackageResolvableOperator op, + const Version& other) const; + + size_t ToString(char* buffer, size_t bufferSize) const; + // returns how big the buffer should have + // been (excluding the terminating null) + +private: + char* fMajor; + char* fMinor; + char* fMicro; + uint8 fRelease; +}; + + +#endif // VERSION_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 7c1676f805..9f06212992 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -18,6 +18,7 @@ #include #include #include +#include #include @@ -35,9 +36,13 @@ #include "kernel_interface.h" #include "PackageDirectory.h" #include "PackageFile.h" +#include "PackageFSRoot.h" #include "PackageSymlink.h" +#include "Resolvable.h" +#include "Version.h" +using namespace BPackageKit; using namespace BPackageKit::BHPKG; using BPackageKit::BHPKG::BPrivate::PackageReaderImpl; @@ -271,6 +276,99 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler { virtual status_t HandlePackageAttribute( const BPackageInfoAttributeValue& value) { + switch (value.attributeID) { +// union { +// uint64 unsignedInt; +// const char* string; +// BPackageVersionData version; +// BPackageResolvableData resolvable; +// BPackageResolvableExpressionData resolvableExpression; +// }; + case B_PACKAGE_INFO_NAME: + return fPackage->SetName(value.string); + + case B_PACKAGE_INFO_VERSION: + { + Version* version; + status_t error = Version::Create(value.version.major, + value.version.minor, value.version.micro, + value.version.release, version); + if (error != B_OK) + RETURN_ERROR(error); + + fPackage->SetVersion(version); + + break; + } + + case B_PACKAGE_INFO_PROVIDES: + { + // create a version object, if a version is specified + Version* version = NULL; + if (value.resolvable.haveVersion) { + const BPackageVersionData& versionInfo + = value.resolvable.version; + status_t error = Version::Create(versionInfo.major, + versionInfo.minor, versionInfo.micro, + versionInfo.release, version); + if (error != B_OK) + RETURN_ERROR(error); + } + ObjectDeleter versionDeleter(version); + + // create the resolvable + Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage); + if (resolvable == NULL) + RETURN_ERROR(B_NO_MEMORY); + ObjectDeleter resolvableDeleter(resolvable); + + status_t error = resolvable->Init(value.resolvable.name, + versionDeleter.Detach()); + if (error != B_OK) + RETURN_ERROR(error); + + fPackage->AddResolvable(resolvableDeleter.Detach()); + + break; + } + + case B_PACKAGE_INFO_REQUIRES: + { + // create the dependency + Dependency* dependency = new(std::nothrow) Dependency(fPackage); + if (dependency == NULL) + RETURN_ERROR(B_NO_MEMORY); + ObjectDeleter dependencyDeleter(dependency); + + status_t error = dependency->Init( + value.resolvableExpression.name); + if (error != B_OK) + RETURN_ERROR(error); + + // create a version object, if a version is specified + Version* version = NULL; + if (value.resolvableExpression.haveOpAndVersion) { + const BPackageVersionData& versionInfo + = value.resolvableExpression.version; + status_t error = Version::Create(versionInfo.major, + versionInfo.minor, versionInfo.micro, + versionInfo.release, version); + if (error != B_OK) + RETURN_ERROR(error); + + dependency->SetVersionRequirement( + value.resolvableExpression.op, version); + } + + fPackage->AddDependency(dependencyDeleter.Detach()); + + break; + } + + default: + break; + } + // TODO! return B_OK; } @@ -323,6 +421,7 @@ Volume::Volume(fs_volume* fsVolume) : fFSVolume(fsVolume), fRootDirectory(NULL), + fPackageFSRoot(NULL), fPackageLoader(-1), fNextNodeID(kRootDirectoryID + 1), fTerminating(false) @@ -348,6 +447,9 @@ Volume::~Volume() node = next; } + if (fPackageFSRoot != NULL) + fPackageFSRoot->UnregisterVolume(this); + if (fRootDirectory != NULL) fRootDirectory->ReleaseReference(); @@ -366,6 +468,7 @@ Volume::Mount(const char* parameterString) const char* packages = NULL; const char* volumeName = NULL; + const char* mountType = NULL; const char* shineThrough = NULL; void* parameterHandle = parse_driver_settings_string(parameterString); @@ -374,6 +477,7 @@ Volume::Mount(const char* parameterString) NULL); volumeName = get_driver_parameter(parameterHandle, "volume-name", NULL, NULL); + mountType = get_driver_parameter(parameterHandle, "type", NULL, NULL); shineThrough = get_driver_parameter(parameterHandle, "shine-through", NULL, NULL); } @@ -386,6 +490,12 @@ Volume::Mount(const char* parameterString) RETURN_ERROR(B_BAD_VALUE); } + error = _InitMountType(mountType); + if (error != B_OK) { + ERROR("invalid mount type: \"%s\"\n", mountType); + RETURN_ERROR(B_ERROR); + } + struct stat st; if (stat(packages, &st) < 0) RETURN_ERROR(B_ERROR); @@ -398,6 +508,23 @@ Volume::Mount(const char* parameterString) fRootDirectory->Init(NULL, volumeName != NULL ? volumeName : "Package FS"); fNodes.Insert(fRootDirectory); + // get our mount point + error = vfs_get_mount_point(fFSVolume->id, &fMountPoint.deviceID, + &fMountPoint.nodeID); + if (error != B_OK) + RETURN_ERROR(error); + + // register with packagefs root + error = ::PackageFSRoot::RegisterVolume(this); + if (error != B_OK) + RETURN_ERROR(error); + + if (this == fPackageFSRoot->SystemVolume()) { + error = _AddPackageLinksDirectory(); + if (error != B_OK) + RETURN_ERROR(error); + } + // create default package domain error = _AddInitialPackageDomain(packages); if (error != B_OK) @@ -409,6 +536,11 @@ Volume::Mount(const char* parameterString) if (fPackageLoader < 0) RETURN_ERROR(fPackageLoader); + // establish shine-through directories + error = _CreateShineThroughDirectories(shineThrough); + if (error != B_OK) + RETURN_ERROR(error); + // publish the root node fRootDirectory->AcquireReference(); error = PublishVNode(fRootDirectory); @@ -417,11 +549,6 @@ Volume::Mount(const char* parameterString) RETURN_ERROR(error); } - // establish shine-through directories - error = _CreateShineThroughDirectories(shineThrough); - if (error != B_OK) - RETURN_ERROR(error); - // run the package loader resume_thread(fPackageLoader); @@ -468,7 +595,7 @@ Volume::PublishVNode(Node* node) status_t Volume::AddPackageDomain(const char* path) { - PackageDomain* packageDomain = new(std::nothrow) PackageDomain; + PackageDomain* packageDomain = new(std::nothrow) PackageDomain(this); if (packageDomain == NULL) RETURN_ERROR(B_NO_MEMORY); BReference packageDomainReference(packageDomain, true); @@ -552,7 +679,7 @@ Volume::_PushJob(Job* job) status_t Volume::_AddInitialPackageDomain(const char* path) { - PackageDomain* domain = new(std::nothrow) PackageDomain; + PackageDomain* domain = new(std::nothrow) PackageDomain(this); if (domain == NULL) RETURN_ERROR(B_NO_MEMORY); BReference domainReference(domain, true); @@ -656,12 +783,16 @@ Volume::_LoadPackage(Package* package) status_t Volume::_AddPackageContent(Package* package, bool notify) { + status_t error = fPackageFSRoot->AddPackage(package); + if (error != B_OK) + RETURN_ERROR(error); + for (PackageNodeList::Iterator it = package->Nodes().GetIterator(); PackageNode* node = it.Next();) { // skip over ".PackageInfo" file, it isn't part of the package content if (strcmp(node->Name(), B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) continue; - status_t error = _AddPackageContentRootNode(package, node, notify); + error = _AddPackageContentRootNode(package, node, notify); if (error != B_OK) { _RemovePackageContent(package, node, notify); RETURN_ERROR(error); @@ -689,6 +820,8 @@ Volume::_RemovePackageContent(Package* package, PackageNode* endNode, node = nextNode; } + + fPackageFSRoot->RemovePackage(package);; } @@ -1109,16 +1242,48 @@ Volume::_DomainEntryMoved(PackageDomain* domain, dev_t deviceID, } +status_t +Volume::_InitMountType(const char* mountType) +{ + if (mountType == NULL) + fMountType = MOUNT_TYPE_CUSTOM; + else if (strcmp(mountType, "system") == 0) + fMountType = MOUNT_TYPE_SYSTEM; + else if (strcmp(mountType, "common") == 0) + fMountType = MOUNT_TYPE_COMMON; + else if (strcmp(mountType, "home") == 0) + fMountType = MOUNT_TYPE_HOME; + else if (strcmp(mountType, "custom") == 0) + fMountType = MOUNT_TYPE_CUSTOM; + else + RETURN_ERROR(B_BAD_VALUE); + + return B_OK; +} + + status_t Volume::_CreateShineThroughDirectories(const char* shineThroughSetting) { - if (shineThroughSetting == NULL) - return B_OK; - // get the directories to map const char* const* directories = NULL; - if (strcmp(shineThroughSetting, "system") == 0) + if (shineThroughSetting == NULL) { + // nothing specified -- derive from mount type + switch (fMountType) { + case MOUNT_TYPE_SYSTEM: + directories = kSystemShineThroughDirectories; + break; + case MOUNT_TYPE_COMMON: + directories = kCommonShineThroughDirectories; + break; + case MOUNT_TYPE_HOME: + directories = kHomeShineThroughDirectories; + break; + case MOUNT_TYPE_CUSTOM: + return B_OK; + } + } else if (strcmp(shineThroughSetting, "system") == 0) directories = kSystemShineThroughDirectories; else if (strcmp(shineThroughSetting, "common") == 0) directories = kCommonShineThroughDirectories; @@ -1132,21 +1297,13 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting) if (directories == NULL) return B_OK; - // get our mount point - dev_t mountPointDevice; - ino_t mountPointNode; - status_t error = vfs_get_mount_point(fFSVolume->id, &mountPointDevice, - &mountPointNode); - if (error != B_OK) - RETURN_ERROR(error); - // iterate through the directory list, create the directories, and bind them // to the mount point subdirectories while (const char* directoryName = *(directories++)) { // look up the mount point subdirectory struct vnode* vnode; - error = vfs_entry_ref_to_vnode(mountPointDevice, mountPointNode, - directoryName, &vnode); + status_t error = vfs_entry_ref_to_vnode(fMountPoint.deviceID, + fMountPoint.nodeID, directoryName, &vnode); if (error != B_OK) { dprintf("packagefs: Failed to get shine-through directory \"%s\": " "%s\n", directoryName, strerror(error)); @@ -1196,3 +1353,11 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting) return B_OK; } + + +status_t +Volume::_AddPackageLinksDirectory() +{ +// TODO:... + return B_OK; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h index a5acba3016..5b46ad2a32 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h @@ -20,9 +20,18 @@ class Directory; class Node; +class PackageFSRoot; -class Volume { +enum MountType { + MOUNT_TYPE_SYSTEM, + MOUNT_TYPE_COMMON, + MOUNT_TYPE_HOME, + MOUNT_TYPE_CUSTOM +}; + + +class Volume : public DoublyLinkedListLinkImpl { public: Volume(fs_volume* fsVolume); ~Volume(); @@ -36,6 +45,18 @@ public: dev_t ID() const { return fFSVolume->id; } Directory* RootDirectory() const { return fRootDirectory; } + ::MountType MountType() const { return fMountType; } + + void SetPackageFSRoot(::PackageFSRoot* root) + { fPackageFSRoot = root; } + ::PackageFSRoot* PackageFSRoot() const + { return fPackageFSRoot; } + + dev_t MountPointDeviceID() const + { return fMountPoint.deviceID; } + ino_t MountPointNodeID() const + { return fMountPoint.nodeID; } + status_t Mount(const char* parameterString); void Unmount(); @@ -118,15 +139,24 @@ private: ino_t nodeID, const char* fromName, const char* name, bool notify); + status_t _InitMountType(const char* mountType); status_t _CreateShineThroughDirectories( const char* shineThroughSetting); + status_t _AddPackageLinksDirectory(); private: rw_lock fLock; fs_volume* fFSVolume; Directory* fRootDirectory; + ::PackageFSRoot* fPackageFSRoot; + ::MountType fMountType; thread_id fPackageLoader; PackageDomainList fPackageDomains; + struct { + dev_t deviceID; + ino_t nodeID; + } fMountPoint; + NodeIDHashTable fNodes; JobList fJobQueue; diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp index fbf46b1dce..c2c6c93636 100644 --- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp @@ -22,6 +22,7 @@ #include "Directory.h" #include "GlobalFactory.h" #include "LeafNode.h" +#include "PackageFSRoot.h" #include "Volume.h" @@ -1063,12 +1064,21 @@ packagefs_std_ops(int32 op, ...) return error; } + error = PackageFSRoot::GlobalInit(); + if (error != B_OK) { + ERROR("Failed to init PackageFSRoot\n"); + GlobalFactory::DeleteDefault(); + exit_debugging(); + return error; + } + return B_OK; } case B_MODULE_UNINIT: { PRINT("package_std_ops(): B_MODULE_UNINIT\n"); + PackageFSRoot::GlobalUninit(); GlobalFactory::DeleteDefault(); exit_debugging(); return B_OK; From 31cd721ebd3122eb93bd743213b0bc16b7997438 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 16:33:17 +0200 Subject: [PATCH 0073/1170] Change package and resolvable version --- src/data/package_infos/haiku | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku index d1ed521a69..4fc4b09375 100644 --- a/src/data/package_infos/haiku +++ b/src/data/package_infos/haiku @@ -1,5 +1,5 @@ name = Haiku -version = 1-1 +version = R1.pm1-1 architecture = x86_gcc2 summary = "The Haiku base system" description = "The Haiku base system includes all system core software, like @@ -12,7 +12,7 @@ copyright = "2001-2011 Haiku, Inc. et al" licenses = [ "MIT" ] provides = [ - haiku + haiku=R1.pm1-1 ] requires = [ From 4b5dbacdbfada68d3b4352cd666a04b504a4b77c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 16:35:05 +0200 Subject: [PATCH 0074/1170] Make Volume::Read{Lock,Unlock} const --- src/add-ons/kernel/file_systems/packagefs/Volume.h | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h index 5b46ad2a32..813b0f505c 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h @@ -36,8 +36,8 @@ public: Volume(fs_volume* fsVolume); ~Volume(); - inline bool ReadLock(); - inline void ReadUnlock(); + inline bool ReadLock() const; + inline void ReadUnlock() const; inline bool WriteLock(); inline void WriteUnlock(); @@ -144,7 +144,7 @@ private: const char* shineThroughSetting); status_t _AddPackageLinksDirectory(); private: - rw_lock fLock; + mutable rw_lock fLock; fs_volume* fFSVolume; Directory* fRootDirectory; ::PackageFSRoot* fPackageFSRoot; @@ -170,14 +170,14 @@ private: bool -Volume::ReadLock() +Volume::ReadLock() const { return rw_lock_read_lock(&fLock) == B_OK; } void -Volume::ReadUnlock() +Volume::ReadUnlock() const { rw_lock_read_unlock(&fLock); } @@ -197,7 +197,8 @@ Volume::WriteUnlock() } -typedef AutoLocker > VolumeReadLocker; +typedef AutoLocker > + VolumeReadLocker; typedef AutoLocker > VolumeWriteLocker; From 22a808885bf961eeedecae46e972a592c07caea2 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 17:37:44 +0200 Subject: [PATCH 0075/1170] Remove kernel_interface.cpp LeafNode dependency Introduce abstract virtual Node::ReadSymlink() method that is now used in packagefs_read_symlink() instead of casting to LeafNode. --- .../file_systems/packagefs/Directory.cpp | 9 ++++++- .../kernel/file_systems/packagefs/Directory.h | 5 +++- .../file_systems/packagefs/LeafNode.cpp | 27 ++++++++++++++++++- .../kernel/file_systems/packagefs/LeafNode.h | 5 +++- .../kernel/file_systems/packagefs/Node.h | 5 +++- .../packagefs/kernel_interface.cpp | 13 +-------- 6 files changed, 47 insertions(+), 17 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp index e047223bde..663afeb52a 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ @@ -164,6 +164,13 @@ Directory::Read(io_request* request) } +status_t +Directory::ReadSymlink(void* buffer, size_t* bufferSize) +{ + return B_IS_A_DIRECTORY; +} + + void Directory::AddChild(Node* node) { diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.h b/src/add-ons/kernel/file_systems/packagefs/Directory.h index 099fd74325..95c56dd9c9 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.h +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.h @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef DIRECTORY_H @@ -48,6 +48,9 @@ public: size_t* bufferSize); virtual status_t Read(io_request* request); + virtual status_t ReadSymlink(void* buffer, + size_t* bufferSize); + void AddChild(Node* node); void RemoveChild(Node* node); Node* FindChild(const char* name); diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp index 43804d67d2..382441d420 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp @@ -1,11 +1,15 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #include "LeafNode.h" +#include + +#include + #include "Utils.h" @@ -168,6 +172,27 @@ LeafNode::Read(io_request* request) } +status_t +LeafNode::ReadSymlink(void* buffer, size_t* bufferSize) +{ + PackageLeafNode* packageNode = fPackageNodes.Head(); + if (packageNode == NULL) + return B_BAD_VALUE; + + const char* linkPath = packageNode->SymlinkPath(); + if (linkPath == NULL) { + *bufferSize = 0; + return B_OK; + } + + size_t toCopy = std::min(strlen(linkPath), *bufferSize); + memcpy(buffer, linkPath, toCopy); + *bufferSize = toCopy; + + return B_OK; +} + + const char* LeafNode::SymlinkPath() const { diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h index d680e19273..2d3b403ec2 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef LEAF_NODE_H @@ -35,6 +35,9 @@ public: size_t* bufferSize); virtual status_t Read(io_request* request); + virtual status_t ReadSymlink(void* buffer, + size_t* bufferSize); + const char* SymlinkPath() const; private: diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h index f02d9f05b1..f2ec3576f2 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.h +++ b/src/add-ons/kernel/file_systems/packagefs/Node.h @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ #ifndef NODE_H @@ -60,6 +60,9 @@ public: size_t* bufferSize) = 0; virtual status_t Read(io_request* request) = 0; + virtual status_t ReadSymlink(void* buffer, + size_t* bufferSize) = 0; + protected: rw_lock fLock; ino_t fID; diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp index c2c6c93636..7868d0ea57 100644 --- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp @@ -21,7 +21,6 @@ #include "DebugSupport.h" #include "Directory.h" #include "GlobalFactory.h" -#include "LeafNode.h" #include "PackageFSRoot.h" #include "Volume.h" @@ -315,17 +314,7 @@ packagefs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer, if (!S_ISLNK(node->Mode())) return B_BAD_VALUE; - const char* linkPath = dynamic_cast(node)->SymlinkPath(); - if (linkPath == NULL) { - *_bufferSize = 0; - return B_OK; - } - - size_t toCopy = std::min(strlen(linkPath), *_bufferSize); - memcpy(buffer, linkPath, toCopy); - *_bufferSize = toCopy; - - return B_OK; + return node->ReadSymlink(buffer, _bufferSize); } From 8ae81ef94eb2a0941bdde3cfa8b0ef01cfe38d73 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 19:41:56 +0200 Subject: [PATCH 0076/1170] Kernel interface abstraction for attribute access * Introduce interface AttributeCookie and currently only implementation UnpackingAttributeCookie. This is an interface for reading/stat()ing an attribute. * Add abstract virtual Node::OpenAttribute() method that returns an AttributeCookie and implemented it for derived classes. * In the kernel interface attribute hooks use AttributeCookie now. The attribute directory hooks are unchanged. --- .../packagefs/AttributeCookie.cpp | 12 ++ .../file_systems/packagefs/AttributeCookie.h | 25 +++ .../file_systems/packagefs/Directory.cpp | 10 ++ .../kernel/file_systems/packagefs/Directory.h | 3 + .../kernel/file_systems/packagefs/Jamfile | 2 + .../file_systems/packagefs/LeafNode.cpp | 10 ++ .../kernel/file_systems/packagefs/LeafNode.h | 3 + .../kernel/file_systems/packagefs/Node.h | 4 + .../packagefs/UnpackingAttributeCookie.cpp | 142 ++++++++++++++++++ .../packagefs/UnpackingAttributeCookie.h | 41 +++++ .../packagefs/kernel_interface.cpp | 105 ++----------- 11 files changed, 261 insertions(+), 96 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/AttributeCookie.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/AttributeCookie.h create mode 100644 src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.h diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.cpp new file mode 100644 index 0000000000..2df7b99c4b --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.cpp @@ -0,0 +1,12 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "AttributeCookie.h" + + +AttributeCookie::~AttributeCookie() +{ +} diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.h b/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.h new file mode 100644 index 0000000000..40ee92c18f --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.h @@ -0,0 +1,25 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ATTRIBUTE_COOKIE_H +#define ATTRIBUTE_COOKIE_H + + +#include + +#include + + +class AttributeCookie { +public: + virtual ~AttributeCookie(); + + virtual status_t Close() = 0; + virtual status_t ReadAttribute(off_t offset, void* buffer, + size_t* bufferSize) = 0; + virtual status_t ReadAttributeStat(struct stat* st) = 0; +}; + + +#endif // ATTRIBUTE_COOKIE_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp index 663afeb52a..f2b8f7c32c 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp @@ -7,6 +7,7 @@ #include "Directory.h" #include "DebugSupport.h" +#include "UnpackingAttributeCookie.h" #include "Utils.h" @@ -171,6 +172,15 @@ Directory::ReadSymlink(void* buffer, size_t* bufferSize) } +status_t +Directory::OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie) +{ + return UnpackingAttributeCookie::Open(fPackageDirectories.Head(), name, + openMode, _cookie); +} + + void Directory::AddChild(Node* node) { diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.h b/src/add-ons/kernel/file_systems/packagefs/Directory.h index 95c56dd9c9..1bb4b5f7d8 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.h +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.h @@ -51,6 +51,9 @@ public: virtual status_t ReadSymlink(void* buffer, size_t* bufferSize); + virtual status_t OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie); + void AddChild(Node* node); void RemoveChild(Node* node); Node* FindChild(const char* name); diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index e07bf10a49..ee76172acb 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -7,6 +7,7 @@ UsePrivateHeaders shared ; HAIKU_PACKAGE_FS_SOURCES = + AttributeCookie.cpp BlockBufferCacheKernel.cpp DebugSupport.cpp Dependency.cpp @@ -26,6 +27,7 @@ HAIKU_PACKAGE_FS_SOURCES = PackageNodeAttribute.cpp PackageSymlink.cpp Resolvable.cpp + UnpackingAttributeCookie.cpp Version.cpp Volume.cpp ; diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp index 382441d420..0bd8116f61 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp @@ -10,6 +10,7 @@ #include +#include "UnpackingAttributeCookie.h" #include "Utils.h" @@ -193,6 +194,15 @@ LeafNode::ReadSymlink(void* buffer, size_t* bufferSize) } +status_t +LeafNode::OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie) +{ + return UnpackingAttributeCookie::Open(fPackageNodes.Head(), name, openMode, + _cookie); +} + + const char* LeafNode::SymlinkPath() const { diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h index 2d3b403ec2..016dab919e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h @@ -38,6 +38,9 @@ public: virtual status_t ReadSymlink(void* buffer, size_t* bufferSize); + virtual status_t OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie); + const char* SymlinkPath() const; private: diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h index f2ec3576f2..3946fcd269 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.h +++ b/src/add-ons/kernel/file_systems/packagefs/Node.h @@ -17,6 +17,7 @@ #include +class AttributeCookie; class Directory; class PackageNode; @@ -63,6 +64,9 @@ public: virtual status_t ReadSymlink(void* buffer, size_t* bufferSize) = 0; + virtual status_t OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie) = 0; + protected: rw_lock fLock; ino_t fID; diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp new file mode 100644 index 0000000000..2c1fe25a51 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp @@ -0,0 +1,142 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "UnpackingAttributeCookie.h" + +#include +#include + +#include +#include +#include + +#include + +#include "DebugSupport.h" +#include "GlobalFactory.h" +#include "Package.h" +#include "PackageNode.h" + + +using BPackageKit::BHPKG::BBufferDataReader; +//using BPackageKit::BHPKG::BDataReader; +using BPackageKit::BHPKG::BFDDataReader; +//using BPackageKit::BHPKG::BPackageData; +//using BPackageKit::BHPKG::BPackageDataReader; + + +static status_t +read_package_data(const BPackageData& data, BDataReader* dataReader, + off_t offset, void* buffer, size_t* bufferSize) +{ + // create a BPackageDataReader + BPackageDataReader* reader; + status_t error = GlobalFactory::Default()->CreatePackageDataReader( + dataReader, data, reader); + if (error != B_OK) + RETURN_ERROR(error); + ObjectDeleter readerDeleter(reader); + + // check the offset + if (offset < 0 || (uint64)offset > data.UncompressedSize()) + return B_BAD_VALUE; + + // clamp the size + size_t toRead = std::min((uint64)*bufferSize, + data.UncompressedSize() - offset); + + // read + if (toRead > 0) { + status_t error = reader->ReadData(offset, buffer, toRead); + if (error != B_OK) + RETURN_ERROR(error); + } + + *bufferSize = toRead; + return B_OK; +} + + +UnpackingAttributeCookie::UnpackingAttributeCookie(PackageNode* packageNode, + PackageNodeAttribute* attribute, int openMode) + : + fPackageNode(packageNode), + fPackage(packageNode->GetPackage()), + fAttribute(attribute), + fOpenMode(openMode) +{ + fPackageNode->AcquireReference(); + fPackage->AcquireReference(); +} + + +UnpackingAttributeCookie::~UnpackingAttributeCookie() +{ + fPackageNode->ReleaseReference(); + fPackage->ReleaseReference(); +} + + +/*static*/ status_t +UnpackingAttributeCookie::Open(PackageNode* packageNode, const char* name, + int openMode, AttributeCookie*& _cookie) +{ + if (packageNode == NULL) + return B_ENTRY_NOT_FOUND; + + // get the attribute + PackageNodeAttribute* attribute = packageNode->FindAttribute(name); + if (attribute == NULL) + return B_ENTRY_NOT_FOUND; + + // allocate the cookie + UnpackingAttributeCookie* cookie = new(std::nothrow) + UnpackingAttributeCookie(packageNode, attribute, openMode); + if (cookie == NULL) + RETURN_ERROR(B_NO_MEMORY); + + _cookie = cookie; + return B_OK; +} + + +status_t +UnpackingAttributeCookie::Close() +{ + return B_OK; +} + + +status_t +UnpackingAttributeCookie::ReadAttribute(off_t offset, void* buffer, + size_t* bufferSize) +{ + const BPackageData& data = fAttribute->Data(); + if (data.IsEncodedInline()) { + // inline data + BBufferDataReader dataReader(data.InlineData(), data.CompressedSize()); + return read_package_data(data, &dataReader, offset, buffer, bufferSize); + } + + // data not inline -- open the package + int fd = fPackage->Open(); + if (fd < 0) + RETURN_ERROR(fd); + PackageCloser packageCloser(fPackage); + + BFDDataReader dataReader(fd); + return read_package_data(data, &dataReader, offset, buffer, bufferSize); +} + + +status_t +UnpackingAttributeCookie::ReadAttributeStat(struct stat* st) +{ + st->st_size = fAttribute->Data().UncompressedSize(); + st->st_type = fAttribute->Type(); + + return B_OK; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.h new file mode 100644 index 0000000000..27fec3dbe2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.h @@ -0,0 +1,41 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef UNPACKING_ATTRIBUTE_COOKIE_H +#define UNPACKING_ATTRIBUTE_COOKIE_H + + +#include "AttributeCookie.h" + + +class Package; +class PackageNode; +class PackageNodeAttribute; + + +class UnpackingAttributeCookie : public AttributeCookie { +public: + UnpackingAttributeCookie( + PackageNode* packageNode, + PackageNodeAttribute* attribute, + int openMode); + virtual ~UnpackingAttributeCookie(); + + static status_t Open(PackageNode* packageNode, const char* name, + int openMode, AttributeCookie*& _cookie); + + virtual status_t Close(); + virtual status_t ReadAttribute(off_t offset, void* buffer, + size_t* bufferSize); + virtual status_t ReadAttributeStat(struct stat* st); + +private: + PackageNode* fPackageNode; + Package* fPackage; + PackageNodeAttribute* fAttribute; + int fOpenMode; +}; + + +#endif // UNPACKING_ATTRIBUTE_COOKIE_H diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp index 7868d0ea57..7a5ad75cbe 100644 --- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp @@ -8,7 +8,6 @@ #include -#include #include #include @@ -18,6 +17,7 @@ #include +#include "AttributeCookie.h" #include "DebugSupport.h" #include "Directory.h" #include "GlobalFactory.h" @@ -25,10 +25,6 @@ #include "Volume.h" -using BPackageKit::BHPKG::BBufferDataReader; -using BPackageKit::BHPKG::BFDDataReader; - - static const uint32 kOptimalIOSize = 64 * 1024; @@ -860,32 +856,6 @@ packagefs_rewind_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) // #pragma mark - Attribute Operations -struct AttributeCookie { - PackageNode* packageNode; - Package* package; - PackageNodeAttribute* attribute; - int openMode; - - AttributeCookie(PackageNode* packageNode, PackageNodeAttribute* attribute, - int openMode) - : - packageNode(packageNode), - package(packageNode->GetPackage()), - attribute(attribute), - openMode(openMode) - { - packageNode->AcquireReference(); - package->AcquireReference(); - } - - ~AttributeCookie() - { - packageNode->ReleaseReference(); - package->ReleaseReference(); - } -}; - - status_t packagefs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, int openMode, void** _cookie) @@ -907,21 +877,12 @@ packagefs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, if (error != B_OK) return error; - // get the package node and the respectively named attribute - PackageNode* packageNode = node->GetPackageNode(); - PackageNodeAttribute* attribute = packageNode != NULL - ? packageNode->FindAttribute(name) : NULL; - if (attribute == NULL) - return B_ENTRY_NOT_FOUND; - - // allocate the cookie - AttributeCookie* cookie = new(std::nothrow) AttributeCookie(packageNode, - attribute, openMode); - if (cookie == NULL) - RETURN_ERROR(B_NO_MEMORY); + AttributeCookie* cookie; + error = node->OpenAttribute(name, openMode, cookie); + if (error != B_OK) + return error; *_cookie = cookie; - return B_OK; } @@ -929,7 +890,8 @@ packagefs_open_attr(fs_volume* fsVolume, fs_vnode* fsNode, const char* name, status_t packagefs_close_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) { - return B_OK; + AttributeCookie* cookie = (AttributeCookie*)_cookie; + RETURN_ERROR(cookie->Close()); } @@ -951,38 +913,6 @@ packagefs_free_attr_cookie(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) } -static status_t -read_package_data(const BPackageData& data, BDataReader* dataReader, off_t offset, - void* buffer, size_t* bufferSize) -{ - // create a BPackageDataReader - BPackageDataReader* reader; - status_t error = GlobalFactory::Default()->CreatePackageDataReader( - dataReader, data, reader); - if (error != B_OK) - RETURN_ERROR(error); - ObjectDeleter readerDeleter(reader); - - // check the offset - if (offset < 0 || (uint64)offset > data.UncompressedSize()) - return B_BAD_VALUE; - - // clamp the size - size_t toRead = std::min((uint64)*bufferSize, - data.UncompressedSize() - offset); - - // read - if (toRead > 0) { - status_t error = reader->ReadData(offset, buffer, toRead); - if (error != B_OK) - RETURN_ERROR(error); - } - - *bufferSize = toRead; - return B_OK; -} - - status_t packagefs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie, off_t offset, void* buffer, size_t* bufferSize) @@ -996,21 +926,7 @@ packagefs_read_attr(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie, TOUCH(volume); TOUCH(node); - const BPackageData& data = cookie->attribute->Data(); - if (data.IsEncodedInline()) { - // inline data - BBufferDataReader dataReader(data.InlineData(), data.CompressedSize()); - return read_package_data(data, &dataReader, offset, buffer, bufferSize); - } - - // data not inline -- open the package - int fd = cookie->package->Open(); - if (fd < 0) - RETURN_ERROR(fd); - PackageCloser packageCloser(cookie->package); - - BFDDataReader dataReader(fd); - return read_package_data(data, &dataReader, offset, buffer, bufferSize); + return cookie->ReadAttribute(offset, buffer, bufferSize); } @@ -1027,10 +943,7 @@ packagefs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode, TOUCH(volume); TOUCH(node); - st->st_size = cookie->attribute->Data().UncompressedSize(); - st->st_type = cookie->attribute->Type(); - - return B_OK; + return cookie->ReadAttributeStat(st); } From fa9fde956eba228e0c7963621627190a0b087757 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 21:22:47 +0200 Subject: [PATCH 0077/1170] Remove unused Node fields --- src/add-ons/kernel/file_systems/packagefs/Node.cpp | 4 +--- src/add-ons/kernel/file_systems/packagefs/Node.h | 3 --- 2 files changed, 1 insertion(+), 6 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.cpp b/src/add-ons/kernel/file_systems/packagefs/Node.cpp index da617b6902..2238cac148 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Node.cpp @@ -16,9 +16,7 @@ Node::Node(ino_t id) : fID(id), fParent(NULL), - fName(NULL), - fUserID(0), - fGroupID(0) + fName(NULL) { rw_lock_init(&fLock, "packagefs node"); } diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h index 3946fcd269..af47f5e150 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.h +++ b/src/add-ons/kernel/file_systems/packagefs/Node.h @@ -74,9 +74,6 @@ protected: char* fName; Node* fNameHashTableNext; Node* fIDHashTableNext; - mode_t fMode; - uid_t fUserID; - gid_t fGroupID; }; From b5ff7abceabdb1c2fa700c83dbfba0fce16ddb25 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 21:23:55 +0200 Subject: [PATCH 0078/1170] Remove unused LeafNode::SymlinkPath() --- src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp | 9 --------- src/add-ons/kernel/file_systems/packagefs/LeafNode.h | 2 -- 2 files changed, 11 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp index 0bd8116f61..dcb1eb3c5d 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp @@ -201,12 +201,3 @@ LeafNode::OpenAttribute(const char* name, int openMode, return UnpackingAttributeCookie::Open(fPackageNodes.Head(), name, openMode, _cookie); } - - -const char* -LeafNode::SymlinkPath() const -{ - if (PackageLeafNode* packageNode = fPackageNodes.Head()) - return packageNode->SymlinkPath(); - return NULL; -} diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h index 016dab919e..9515c1e4f6 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h @@ -41,8 +41,6 @@ public: virtual status_t OpenAttribute(const char* name, int openMode, AttributeCookie*& _cookie); - const char* SymlinkPath() const; - private: PackageLeafNodeList fPackageNodes; }; From 3ad1037bcce52347c19b49ede50eeed8545e3cff Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 21:28:35 +0200 Subject: [PATCH 0079/1170] Move set_dirent_name() to Utils.h --- .../kernel/file_systems/packagefs/Utils.h | 19 +++++++++++++++++++ .../packagefs/kernel_interface.cpp | 16 +--------------- 2 files changed, 20 insertions(+), 15 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Utils.h b/src/add-ons/kernel/file_systems/packagefs/Utils.h index 853792b017..e81b475cba 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Utils.h +++ b/src/add-ons/kernel/file_systems/packagefs/Utils.h @@ -6,6 +6,10 @@ #define UTILS_H +#include +#include + + inline bool operator<(const timespec& a, const timespec& b) { return a.tv_sec < b.tv_sec @@ -19,4 +23,19 @@ inline bool operator>(const timespec& a, const timespec& b) } +static inline bool +set_dirent_name(struct dirent* buffer, size_t bufferSize, const char* name, + size_t nameLen) +{ + size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer; + if (length > bufferSize) + return false; + + memcpy(buffer->d_name, name, nameLen); + buffer->d_name[nameLen] = '\0'; + buffer->d_reclen = length; + return true; +} + + #endif // UTILS_H diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp index 7a5ad75cbe..7e140f6e5d 100644 --- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp @@ -22,6 +22,7 @@ #include "Directory.h" #include "GlobalFactory.h" #include "PackageFSRoot.h" +#include "Utils.h" #include "Volume.h" @@ -45,21 +46,6 @@ is_user_in_group(gid_t gid) } -static bool -set_dirent_name(struct dirent* buffer, size_t bufferSize, const char* name, - size_t nameLen) -{ - size_t length = (buffer->d_name + nameLen + 1) - (char*)buffer; - if (length > bufferSize) - return false; - - memcpy(buffer->d_name, name, nameLen); - buffer->d_name[nameLen] = '\0'; - buffer->d_reclen = length; - return true; -} - - static status_t check_access(Node* node, int mode) { From e807d80833d95840f9b2b529debd6f9de2558e2d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 22:01:59 +0200 Subject: [PATCH 0080/1170] Attribute dir access kernel interface abstraction * Introduce interface AttributeDirectoryCookie and currently only implementation UnpackingAttributeDirectoryCookie. This is an interface for reading/rewinding an attribute directory. * Add abstract virtual Node::OpenAttributeDirectory() method that returns an AttributeDirectoryCookie and implement it for derived classes. * In the kernel interface attribute directory hooks use AttributeDirectoryCookie now. --- .../packagefs/AttributeDirectoryCookie.cpp | 12 ++ .../packagefs/AttributeDirectoryCookie.h | 26 ++++ .../file_systems/packagefs/Directory.cpp | 9 ++ .../kernel/file_systems/packagefs/Directory.h | 2 + .../kernel/file_systems/packagefs/Jamfile | 2 + .../file_systems/packagefs/LeafNode.cpp | 9 ++ .../kernel/file_systems/packagefs/LeafNode.h | 2 + .../kernel/file_systems/packagefs/Node.h | 3 + .../UnpackingAttributeDirectoryCookie.cpp | 116 ++++++++++++++++++ .../UnpackingAttributeDirectoryCookie.h | 39 ++++++ .../packagefs/kernel_interface.cpp | 108 ++-------------- 11 files changed, 229 insertions(+), 99 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.h create mode 100644 src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.h diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.cpp new file mode 100644 index 0000000000..adbdc629f0 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.cpp @@ -0,0 +1,12 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "AttributeDirectoryCookie.h" + + +AttributeDirectoryCookie::~AttributeDirectoryCookie() +{ +} diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.h b/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.h new file mode 100644 index 0000000000..eb5d271e16 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.h @@ -0,0 +1,26 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef ATTRIBUTE_DIRECTORY_COOKIE_H +#define ATTRIBUTE_DIRECTORY_COOKIE_H + + +#include + +#include + + +class AttributeDirectoryCookie { +public: + virtual ~AttributeDirectoryCookie(); + + virtual status_t Close() = 0; + virtual status_t Read(dev_t volumeID, ino_t nodeID, + struct dirent* buffer, size_t bufferSize, + uint32* _count) = 0; + virtual status_t Rewind() = 0; +}; + + +#endif // ATTRIBUTE_DIRECTORY_COOKIE_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp index f2b8f7c32c..0962974498 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp @@ -8,6 +8,7 @@ #include "DebugSupport.h" #include "UnpackingAttributeCookie.h" +#include "UnpackingAttributeDirectoryCookie.h" #include "Utils.h" @@ -172,6 +173,14 @@ Directory::ReadSymlink(void* buffer, size_t* bufferSize) } +status_t +Directory::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) +{ + return UnpackingAttributeDirectoryCookie::Open(fPackageDirectories.Head(), + _cookie); +} + + status_t Directory::OpenAttribute(const char* name, int openMode, AttributeCookie*& _cookie) diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.h b/src/add-ons/kernel/file_systems/packagefs/Directory.h index 1bb4b5f7d8..6a73d24fef 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.h +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.h @@ -51,6 +51,8 @@ public: virtual status_t ReadSymlink(void* buffer, size_t* bufferSize); + virtual status_t OpenAttributeDirectory( + AttributeDirectoryCookie*& _cookie); virtual status_t OpenAttribute(const char* name, int openMode, AttributeCookie*& _cookie); diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index ee76172acb..12d9dae345 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -8,6 +8,7 @@ UsePrivateHeaders shared ; HAIKU_PACKAGE_FS_SOURCES = AttributeCookie.cpp + AttributeDirectoryCookie.cpp BlockBufferCacheKernel.cpp DebugSupport.cpp Dependency.cpp @@ -28,6 +29,7 @@ HAIKU_PACKAGE_FS_SOURCES = PackageSymlink.cpp Resolvable.cpp UnpackingAttributeCookie.cpp + UnpackingAttributeDirectoryCookie.cpp Version.cpp Volume.cpp ; diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp index dcb1eb3c5d..b02a48b930 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp @@ -11,6 +11,7 @@ #include #include "UnpackingAttributeCookie.h" +#include "UnpackingAttributeDirectoryCookie.h" #include "Utils.h" @@ -194,6 +195,14 @@ LeafNode::ReadSymlink(void* buffer, size_t* bufferSize) } +status_t +LeafNode::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) +{ + return UnpackingAttributeDirectoryCookie::Open(fPackageNodes.Head(), + _cookie); +} + + status_t LeafNode::OpenAttribute(const char* name, int openMode, AttributeCookie*& _cookie) diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h index 9515c1e4f6..877a9bd3be 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h @@ -38,6 +38,8 @@ public: virtual status_t ReadSymlink(void* buffer, size_t* bufferSize); + virtual status_t OpenAttributeDirectory( + AttributeDirectoryCookie*& _cookie); virtual status_t OpenAttribute(const char* name, int openMode, AttributeCookie*& _cookie); diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h index af47f5e150..62b1695231 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.h +++ b/src/add-ons/kernel/file_systems/packagefs/Node.h @@ -18,6 +18,7 @@ class AttributeCookie; +class AttributeDirectoryCookie; class Directory; class PackageNode; @@ -64,6 +65,8 @@ public: virtual status_t ReadSymlink(void* buffer, size_t* bufferSize) = 0; + virtual status_t OpenAttributeDirectory( + AttributeDirectoryCookie*& _cookie) = 0; virtual status_t OpenAttribute(const char* name, int openMode, AttributeCookie*& _cookie) = 0; diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.cpp new file mode 100644 index 0000000000..3a95440637 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.cpp @@ -0,0 +1,116 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "UnpackingAttributeDirectoryCookie.h" + +#include "DebugSupport.h" +#include "PackageNode.h" +#include "Utils.h" + + +UnpackingAttributeDirectoryCookie::UnpackingAttributeDirectoryCookie( + PackageNode* packageNode) + : + fPackageNode(packageNode), + fAttribute(NULL) +{ + if (fPackageNode != NULL) { + fPackageNode->AcquireReference(); + fAttribute = fPackageNode->Attributes().Head(); + } +} + + +UnpackingAttributeDirectoryCookie::~UnpackingAttributeDirectoryCookie() +{ + if (fPackageNode != NULL) + fPackageNode->ReleaseReference(); +} + + +/*static*/ status_t +UnpackingAttributeDirectoryCookie::Open(PackageNode* packageNode, + AttributeDirectoryCookie*& _cookie) +{ + UnpackingAttributeDirectoryCookie* cookie = new(std::nothrow) + UnpackingAttributeDirectoryCookie(packageNode); + if (cookie == NULL) + return B_NO_MEMORY; + + _cookie = cookie; + return B_OK; +} + + +status_t +UnpackingAttributeDirectoryCookie::Close() +{ + return B_OK; +} + + +status_t +UnpackingAttributeDirectoryCookie::Read(dev_t volumeID, ino_t nodeID, + struct dirent* buffer, size_t bufferSize, uint32* _count) +{ + uint32 maxCount = *_count; + uint32 count = 0; + + dirent* previousEntry = NULL; + + while (fAttribute != NULL) { + // don't read more entries than requested + if (count >= maxCount) + break; + + // align the buffer for subsequent entries + if (count > 0) { + addr_t offset = (addr_t)buffer % 8; + if (offset > 0) { + offset = 8 - offset; + if (bufferSize <= offset) + break; + + previousEntry->d_reclen += offset; + buffer = (dirent*)((addr_t)buffer + offset); + bufferSize -= offset; + } + } + + // fill in the entry name -- checks whether the entry fits into the + // buffer + const char* name = fAttribute->Name(); + if (!set_dirent_name(buffer, bufferSize, name, strlen(name))) { + if (count == 0) + RETURN_ERROR(B_BUFFER_OVERFLOW); + break; + } + + // fill in the other data + buffer->d_dev = volumeID; + buffer->d_ino = nodeID; + + count++; + previousEntry = buffer; + bufferSize -= buffer->d_reclen; + buffer = (dirent*)((addr_t)buffer + buffer->d_reclen); + + fAttribute = fPackageNode->Attributes().GetNext(fAttribute); + } + + *_count = count; + return B_OK; +} + + +status_t +UnpackingAttributeDirectoryCookie::Rewind() +{ + if (fPackageNode != NULL) + fAttribute = fPackageNode->Attributes().Head(); + + return B_OK; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.h new file mode 100644 index 0000000000..0f6bc1baf0 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.h @@ -0,0 +1,39 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef UNPACKING_ATTRIBUTE_DIRECTORY_COOKIE_H +#define UNPACKING_ATTRIBUTE_DIRECTORY_COOKIE_H + + +#include "AttributeDirectoryCookie.h" + + +struct dirent; + +class PackageNode; +class PackageNodeAttribute; + + +class UnpackingAttributeDirectoryCookie : public AttributeDirectoryCookie { +public: + UnpackingAttributeDirectoryCookie( + PackageNode* packageNode); + virtual ~UnpackingAttributeDirectoryCookie(); + + static status_t Open(PackageNode* packageNode, + AttributeDirectoryCookie*& _cookie); + + virtual status_t Close(); + virtual status_t Read(dev_t volumeID, ino_t nodeID, + struct dirent* buffer, size_t bufferSize, + uint32* _count); + virtual status_t Rewind(); + +private: + PackageNode* fPackageNode; + PackageNodeAttribute* fAttribute; +}; + + +#endif // UNPACKING_ATTRIBUTE_DIRECTORY_COOKIE_H diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp index 7e140f6e5d..41e6ca6df6 100644 --- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp @@ -18,6 +18,7 @@ #include #include "AttributeCookie.h" +#include "AttributeDirectoryCookie.h" #include "DebugSupport.h" #include "Directory.h" #include "GlobalFactory.h" @@ -663,50 +664,6 @@ packagefs_rewind_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) // #pragma mark - Attribute Directories -struct AttributeDirectoryCookie { - Node* node; - PackageNode* packageNode; - PackageNodeAttribute* attribute; - - AttributeDirectoryCookie(Node* node) - : - node(node), - packageNode(node->GetPackageNode()), - attribute(NULL) - { - if (packageNode != NULL) { - packageNode->AcquireReference(); - attribute = packageNode->Attributes().Head(); - } - } - - ~AttributeDirectoryCookie() - { - if (packageNode != NULL) - packageNode->ReleaseReference(); - } - - PackageNodeAttribute* Current() const - { - return attribute; - } - - void Next() - { - if (attribute == NULL) - return; - - attribute = packageNode->Attributes().GetNext(attribute); - } - - void Rewind() - { - if (packageNode != NULL) - attribute = packageNode->Attributes().Head(); - } -}; - - status_t packagefs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie) { @@ -722,10 +679,10 @@ packagefs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie) // create a cookie NodeReadLocker nodeLocker(node); - AttributeDirectoryCookie* cookie - = new(std::nothrow) AttributeDirectoryCookie(node); - if (cookie == NULL) - RETURN_ERROR(B_NO_MEMORY); + AttributeDirectoryCookie* cookie; + error = node->OpenAttributeDirectory(cookie); + if (error != B_OK) + RETURN_ERROR(error); *_cookie = cookie; return B_OK; @@ -735,7 +692,8 @@ packagefs_open_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void** _cookie) status_t packagefs_close_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) { - return B_OK; + AttributeDirectoryCookie* cookie = (AttributeDirectoryCookie*)_cookie; + return cookie->Close(); } @@ -771,53 +729,7 @@ packagefs_read_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie, TOUCH(volume); TOUCH(node); - uint32 maxCount = *_count; - uint32 count = 0; - - dirent* previousEntry = NULL; - - while (PackageNodeAttribute* attribute = cookie->Current()) { - // don't read more entries than requested - if (count >= maxCount) - break; - - // align the buffer for subsequent entries - if (count > 0) { - addr_t offset = (addr_t)buffer % 8; - if (offset > 0) { - offset = 8 - offset; - if (bufferSize <= offset) - break; - - previousEntry->d_reclen += offset; - buffer = (dirent*)((addr_t)buffer + offset); - bufferSize -= offset; - } - } - - // fill in the entry name -- checks whether the entry fits into the - // buffer - const char* name = attribute->Name(); - if (!set_dirent_name(buffer, bufferSize, name, strlen(name))) { - if (count == 0) - RETURN_ERROR(B_BUFFER_OVERFLOW); - break; - } - - // fill in the other data - buffer->d_dev = volume->ID(); - buffer->d_ino = node->ID(); - - count++; - previousEntry = buffer; - bufferSize -= buffer->d_reclen; - buffer = (dirent*)((addr_t)buffer + buffer->d_reclen); - - cookie->Next(); - } - - *_count = count; - return B_OK; + return cookie->Read(volume->ID(), node->ID(), buffer, bufferSize, _count); } @@ -833,9 +745,7 @@ packagefs_rewind_attr_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie) TOUCH(volume); TOUCH(node); - cookie->Rewind(); - - return B_OK; + return cookie->Rewind(); } From e85e0ae85a25fe859f950b1218bf8cb8c7a56322 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 23:13:18 +0200 Subject: [PATCH 0081/1170] Remove package related dependencies from Node * Move package related methods from Node to new interface UnpackingNode. * LeafNode and Directory derive from UnpackingNode now. * Adjust Volume implementation accordingly. --- .../file_systems/packagefs/Directory.cpp | 7 +++ .../kernel/file_systems/packagefs/Directory.h | 5 +- .../kernel/file_systems/packagefs/Jamfile | 1 + .../file_systems/packagefs/LeafNode.cpp | 7 +++ .../kernel/file_systems/packagefs/LeafNode.h | 5 +- .../kernel/file_systems/packagefs/Node.h | 5 -- .../file_systems/packagefs/UnpackingNode.cpp | 12 ++++ .../file_systems/packagefs/UnpackingNode.h | 29 +++++++++ .../kernel/file_systems/packagefs/Volume.cpp | 59 ++++++++++++------- .../kernel/file_systems/packagefs/Volume.h | 6 +- 10 files changed, 106 insertions(+), 30 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/UnpackingNode.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp index 0962974498..141c6ce85e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp @@ -99,6 +99,13 @@ Directory::FileSize() const } +Node* +Directory::GetNode() +{ + return this; +} + + status_t Directory::AddPackageNode(PackageNode* packageNode) { diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.h b/src/add-ons/kernel/file_systems/packagefs/Directory.h index 6a73d24fef..f9c9ac173f 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.h +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.h @@ -8,6 +8,7 @@ #include "Node.h" #include "PackageDirectory.h" +#include "UnpackingNode.h" struct DirectoryIterator : DoublyLinkedListLinkImpl { @@ -23,7 +24,7 @@ struct DirectoryIterator : DoublyLinkedListLinkImpl { typedef DoublyLinkedList DirectoryIteratorList; -class Directory : public Node { +class Directory : public Node, public UnpackingNode { public: Directory(ino_t id); virtual ~Directory(); @@ -39,6 +40,8 @@ public: virtual timespec ModifiedTime() const; virtual off_t FileSize() const; + virtual Node* GetNode(); + virtual status_t AddPackageNode(PackageNode* packageNode); virtual void RemovePackageNode(PackageNode* packageNode); diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index 12d9dae345..043f157e09 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -30,6 +30,7 @@ HAIKU_PACKAGE_FS_SOURCES = Resolvable.cpp UnpackingAttributeCookie.cpp UnpackingAttributeDirectoryCookie.cpp + UnpackingNode.cpp Version.cpp Volume.cpp ; diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp index b02a48b930..874dbc264c 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp @@ -98,6 +98,13 @@ LeafNode::FileSize() const } +Node* +LeafNode::GetNode() +{ + return this; +} + + status_t LeafNode::AddPackageNode(PackageNode* packageNode) { diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h index 877a9bd3be..2e427b3b75 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/LeafNode.h @@ -8,9 +8,10 @@ #include "Node.h" #include "PackageLeafNode.h" +#include "UnpackingNode.h" -class LeafNode : public Node { +class LeafNode : public Node, public UnpackingNode { public: LeafNode(ino_t id); virtual ~LeafNode(); @@ -26,6 +27,8 @@ public: virtual timespec ModifiedTime() const; virtual off_t FileSize() const; + virtual Node* GetNode(); + virtual status_t AddPackageNode(PackageNode* packageNode); virtual void RemovePackageNode(PackageNode* packageNode); diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h index 62b1695231..9b0dc31efe 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.h +++ b/src/add-ons/kernel/file_systems/packagefs/Node.h @@ -53,11 +53,6 @@ public: virtual timespec ModifiedTime() const = 0; virtual off_t FileSize() const = 0; - virtual status_t AddPackageNode(PackageNode* packageNode) = 0; - virtual void RemovePackageNode(PackageNode* packageNode) = 0; - - virtual PackageNode* GetPackageNode() = 0; - virtual status_t Read(off_t offset, void* buffer, size_t* bufferSize) = 0; virtual status_t Read(io_request* request) = 0; diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.cpp new file mode 100644 index 0000000000..dd99ca9dd2 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.cpp @@ -0,0 +1,12 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "UnpackingNode.h" + + +UnpackingNode::~UnpackingNode() +{ +} diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h new file mode 100644 index 0000000000..f1edd5fe3d --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h @@ -0,0 +1,29 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef UNPACKING_NODE_H +#define UNPACKING_NODE_H + + +#include + + +class Node; +class PackageNode; + + +class UnpackingNode { +public: + virtual ~UnpackingNode(); + + virtual Node* GetNode() = 0; + + virtual status_t AddPackageNode(PackageNode* packageNode) = 0; + virtual void RemovePackageNode(PackageNode* packageNode) = 0; + + virtual PackageNode* GetPackageNode() = 0; +}; + + +#endif // UNPACKING_NODE_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 9f06212992..1ee70f9349 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -949,17 +949,26 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode, bool notify, Node*& _node) { bool newNode = false; + UnpackingNode* unpackingNode; Node* node = directory->FindChild(packageNode->Name()); - if (node == NULL) { - status_t error = _CreateNode(packageNode->Mode(), directory, - packageNode->Name(), node); + + if (node != NULL) { + unpackingNode = dynamic_cast(node); + if (unpackingNode == NULL) + RETURN_ERROR(B_BAD_VALUE); + } else { + status_t error = _CreateUnpackingNode(packageNode->Mode(), directory, + packageNode->Name(), unpackingNode); if (error != B_OK) RETURN_ERROR(error); + + node = unpackingNode->GetNode(); newNode = true; } + BReference nodeReference(node); - status_t error = node->AddPackageNode(packageNode); + status_t error = unpackingNode->AddPackageNode(packageNode); if (error != B_OK) { // remove the node, if created before if (newNode) @@ -971,7 +980,7 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode, if (newNode) { notify_entry_created(ID(), directory->ID(), node->Name(), node->ID()); - } else if (packageNode == node->GetPackageNode()) { + } else if (packageNode == unpackingNode->GetPackageNode()) { // The new package node has become the one representing the node. // Send stat changed notification for directories and entry // removed + created notifications for files and symlinks. @@ -999,15 +1008,19 @@ void Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode, Node* node, bool notify) { + UnpackingNode* unpackingNode = dynamic_cast(node); + if (unpackingNode == NULL) + return; + BReference nodeReference(node); - PackageNode* headPackageNode = node->GetPackageNode(); - node->RemovePackageNode(packageNode); + PackageNode* headPackageNode = unpackingNode->GetPackageNode(); + unpackingNode->RemovePackageNode(packageNode); // If the node doesn't have any more package nodes attached, remove it // completely. bool nodeRemoved = false; - if (node->GetPackageNode() == NULL) { + if (unpackingNode->GetPackageNode() == NULL) { // we get and put the vnode to notify the VFS // TODO: We should probably only do that, if the node is known to the // VFS in the first place. @@ -1050,19 +1063,21 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode, status_t -Volume::_CreateNode(mode_t mode, Directory* parent, const char* name, - Node*& _node) +Volume::_CreateUnpackingNode(mode_t mode, Directory* parent, const char* name, + UnpackingNode*& _node) { - Node* node; + UnpackingNode* unpackingNode; if (S_ISREG(mode) || S_ISLNK(mode)) - node = new(std::nothrow) LeafNode(fNextNodeID++); + unpackingNode = new(std::nothrow) LeafNode(fNextNodeID++); else if (S_ISDIR(mode)) - node = new(std::nothrow) Directory(fNextNodeID++); + unpackingNode = new(std::nothrow) Directory(fNextNodeID++); else RETURN_ERROR(B_UNSUPPORTED); - if (node == NULL) + if (unpackingNode == NULL) RETURN_ERROR(B_NO_MEMORY); + + Node* node = unpackingNode->GetNode(); BReference nodeReference(node, true); status_t error = node->Init(parent, name); @@ -1075,7 +1090,7 @@ Volume::_CreateNode(mode_t mode, Directory* parent, const char* name, nodeReference.Detach(); // we keep the initial node reference for this table - _node = node; + _node = unpackingNode; return B_OK; } @@ -1327,23 +1342,25 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting) } // create the directory - Node* directory; - error = _CreateNode(S_IFDIR, fRootDirectory, directoryName, directory); + UnpackingNode* directory; + error = _CreateUnpackingNode(S_IFDIR, fRootDirectory, directoryName, + directory); if (error != B_OK) RETURN_ERROR(error); // publish its vnode, so the VFS will find it without asking us - error = PublishVNode(directory); + Node* directoryNode = directory->GetNode(); + error = PublishVNode(directoryNode); if (error != B_OK) { - _RemoveNode(directory); + _RemoveNode(directoryNode); RETURN_ERROR(error); } // bind the directory error = vfs_bind_mount_directory(st.st_dev, st.st_ino, fFSVolume->id, - directory->ID()); + directoryNode->ID()); - PutVNode(directory->ID()); + PutVNode(directoryNode->ID()); // release our reference again -- on success // vfs_bind_mount_directory() got one diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h index 813b0f505c..e7e5a3a867 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h @@ -21,6 +21,7 @@ class Directory; class Node; class PackageFSRoot; +class UnpackingNode; enum MountType { @@ -117,8 +118,9 @@ private: PackageNode* packageNode, Node* node, bool notify); - status_t _CreateNode(mode_t mode, Directory* parent, - const char* name, Node*& _node); + status_t _CreateUnpackingNode(mode_t mode, + Directory* parent, const char* name, + UnpackingNode*& _node); // does *not* return a reference void _RemoveNode(Node* node); From 876a16a21e528ade35c5b4bfd3e10c0b835fe03a Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 23:18:13 +0200 Subject: [PATCH 0082/1170] Rename LeafNode to UnpackingLeafNode --- .../kernel/file_systems/packagefs/Jamfile | 2 +- .../{LeafNode.cpp => UnpackingLeafNode.cpp} | 40 +++++++++---------- .../{LeafNode.h => UnpackingLeafNode.h} | 6 +-- .../kernel/file_systems/packagefs/Volume.cpp | 4 +- 4 files changed, 26 insertions(+), 26 deletions(-) rename src/add-ons/kernel/file_systems/packagefs/{LeafNode.cpp => UnpackingLeafNode.cpp} (78%) rename src/add-ons/kernel/file_systems/packagefs/{LeafNode.h => UnpackingLeafNode.h} (90%) diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index 043f157e09..3c88293997 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -15,7 +15,6 @@ HAIKU_PACKAGE_FS_SOURCES = Directory.cpp GlobalFactory.cpp kernel_interface.cpp - LeafNode.cpp Node.cpp Package.cpp PackageDirectory.cpp @@ -30,6 +29,7 @@ HAIKU_PACKAGE_FS_SOURCES = Resolvable.cpp UnpackingAttributeCookie.cpp UnpackingAttributeDirectoryCookie.cpp + UnpackingLeafNode.cpp UnpackingNode.cpp Version.cpp Volume.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp similarity index 78% rename from src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp rename to src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp index 874dbc264c..a1af6c0c3a 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp @@ -4,7 +4,7 @@ */ -#include "LeafNode.h" +#include "UnpackingLeafNode.h" #include @@ -15,27 +15,27 @@ #include "Utils.h" -LeafNode::LeafNode(ino_t id) +UnpackingLeafNode::UnpackingLeafNode(ino_t id) : Node(id) { } -LeafNode::~LeafNode() +UnpackingLeafNode::~UnpackingLeafNode() { } status_t -LeafNode::Init(Directory* parent, const char* name) +UnpackingLeafNode::Init(Directory* parent, const char* name) { return Node::Init(parent, name); } status_t -LeafNode::VFSInit(dev_t deviceID) +UnpackingLeafNode::VFSInit(dev_t deviceID) { if (PackageLeafNode* packageNode = fPackageNodes.Head()) return packageNode->VFSInit(deviceID, fID); @@ -44,7 +44,7 @@ LeafNode::VFSInit(dev_t deviceID) void -LeafNode::VFSUninit() +UnpackingLeafNode::VFSUninit() { if (PackageLeafNode* packageNode = fPackageNodes.Head()) packageNode->VFSUninit(); @@ -52,7 +52,7 @@ LeafNode::VFSUninit() mode_t -LeafNode::Mode() const +UnpackingLeafNode::Mode() const { if (PackageLeafNode* packageNode = fPackageNodes.Head()) return packageNode->Mode(); @@ -61,7 +61,7 @@ LeafNode::Mode() const uid_t -LeafNode::UserID() const +UnpackingLeafNode::UserID() const { if (PackageLeafNode* packageNode = fPackageNodes.Head()) return packageNode->UserID(); @@ -70,7 +70,7 @@ LeafNode::UserID() const gid_t -LeafNode::GroupID() const +UnpackingLeafNode::GroupID() const { if (PackageLeafNode* packageNode = fPackageNodes.Head()) return packageNode->GroupID(); @@ -79,7 +79,7 @@ LeafNode::GroupID() const timespec -LeafNode::ModifiedTime() const +UnpackingLeafNode::ModifiedTime() const { if (PackageLeafNode* packageNode = fPackageNodes.Head()) return packageNode->ModifiedTime(); @@ -90,7 +90,7 @@ LeafNode::ModifiedTime() const off_t -LeafNode::FileSize() const +UnpackingLeafNode::FileSize() const { if (PackageLeafNode* packageNode = fPackageNodes.Head()) return packageNode->FileSize(); @@ -99,14 +99,14 @@ LeafNode::FileSize() const Node* -LeafNode::GetNode() +UnpackingLeafNode::GetNode() { return this; } status_t -LeafNode::AddPackageNode(PackageNode* packageNode) +UnpackingLeafNode::AddPackageNode(PackageNode* packageNode) { if (S_ISDIR(packageNode->Mode())) return B_BAD_VALUE; @@ -132,7 +132,7 @@ LeafNode::AddPackageNode(PackageNode* packageNode) void -LeafNode::RemovePackageNode(PackageNode* packageNode) +UnpackingLeafNode::RemovePackageNode(PackageNode* packageNode) { bool isNewest = packageNode == fPackageNodes.Head(); fPackageNodes.Remove(dynamic_cast(packageNode)); @@ -157,14 +157,14 @@ LeafNode::RemovePackageNode(PackageNode* packageNode) PackageNode* -LeafNode::GetPackageNode() +UnpackingLeafNode::GetPackageNode() { return fPackageNodes.Head(); } status_t -LeafNode::Read(off_t offset, void* buffer, size_t* bufferSize) +UnpackingLeafNode::Read(off_t offset, void* buffer, size_t* bufferSize) { if (PackageLeafNode* packageNode = fPackageNodes.Head()) return packageNode->Read(offset, buffer, bufferSize); @@ -173,7 +173,7 @@ LeafNode::Read(off_t offset, void* buffer, size_t* bufferSize) status_t -LeafNode::Read(io_request* request) +UnpackingLeafNode::Read(io_request* request) { if (PackageLeafNode* packageNode = fPackageNodes.Head()) return packageNode->Read(request); @@ -182,7 +182,7 @@ LeafNode::Read(io_request* request) status_t -LeafNode::ReadSymlink(void* buffer, size_t* bufferSize) +UnpackingLeafNode::ReadSymlink(void* buffer, size_t* bufferSize) { PackageLeafNode* packageNode = fPackageNodes.Head(); if (packageNode == NULL) @@ -203,7 +203,7 @@ LeafNode::ReadSymlink(void* buffer, size_t* bufferSize) status_t -LeafNode::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) +UnpackingLeafNode::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) { return UnpackingAttributeDirectoryCookie::Open(fPackageNodes.Head(), _cookie); @@ -211,7 +211,7 @@ LeafNode::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) status_t -LeafNode::OpenAttribute(const char* name, int openMode, +UnpackingLeafNode::OpenAttribute(const char* name, int openMode, AttributeCookie*& _cookie) { return UnpackingAttributeCookie::Open(fPackageNodes.Head(), name, openMode, diff --git a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h similarity index 90% rename from src/add-ons/kernel/file_systems/packagefs/LeafNode.h rename to src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h index 2e427b3b75..a933bb98e9 100644 --- a/src/add-ons/kernel/file_systems/packagefs/LeafNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h @@ -11,10 +11,10 @@ #include "UnpackingNode.h" -class LeafNode : public Node, public UnpackingNode { +class UnpackingLeafNode : public Node, public UnpackingNode { public: - LeafNode(ino_t id); - virtual ~LeafNode(); + UnpackingLeafNode(ino_t id); + virtual ~UnpackingLeafNode(); virtual status_t Init(Directory* parent, const char* name); diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 1ee70f9349..19d546fbf3 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -32,13 +32,13 @@ #include "DebugSupport.h" #include "Directory.h" -#include "LeafNode.h" #include "kernel_interface.h" #include "PackageDirectory.h" #include "PackageFile.h" #include "PackageFSRoot.h" #include "PackageSymlink.h" #include "Resolvable.h" +#include "UnpackingLeafNode.h" #include "Version.h" @@ -1068,7 +1068,7 @@ Volume::_CreateUnpackingNode(mode_t mode, Directory* parent, const char* name, { UnpackingNode* unpackingNode; if (S_ISREG(mode) || S_ISLNK(mode)) - unpackingNode = new(std::nothrow) LeafNode(fNextNodeID++); + unpackingNode = new(std::nothrow) UnpackingLeafNode(fNextNodeID++); else if (S_ISDIR(mode)) unpackingNode = new(std::nothrow) Directory(fNextNodeID++); else From 511b4fe8b36aaefb5a8a709d1b36ab9728dced76 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 23:33:23 +0200 Subject: [PATCH 0083/1170] Pull derived UnpackingDirectory out of Directory Move all package specifics from now abstract Directory to new derived class UnpackingDirectory and adjust the Volume implementation accordingly. This concludes the Node/Directory refactoring. Neither class is aware of packages anymore. --- .../file_systems/packagefs/Directory.cpp | 137 ------------ .../kernel/file_systems/packagefs/Directory.h | 38 +--- .../kernel/file_systems/packagefs/Jamfile | 1 + .../packagefs/UnpackingDirectory.cpp | 195 ++++++++++++++++++ .../packagefs/UnpackingDirectory.h | 63 ++++++ .../kernel/file_systems/packagefs/Volume.cpp | 4 +- 6 files changed, 263 insertions(+), 175 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp index 141c6ce85e..0e773888fe 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp @@ -54,111 +54,6 @@ Directory::VFSUninit() } -mode_t -Directory::Mode() const -{ - if (PackageDirectory* packageDirectory = fPackageDirectories.Head()) - return packageDirectory->Mode(); - return S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; -} - - -uid_t -Directory::UserID() const -{ - if (PackageDirectory* packageDirectory = fPackageDirectories.Head()) - return packageDirectory->UserID(); - return 0; -} - - -gid_t -Directory::GroupID() const -{ - if (PackageDirectory* packageDirectory = fPackageDirectories.Head()) - return packageDirectory->GroupID(); - return 0; -} - - -timespec -Directory::ModifiedTime() const -{ - if (PackageDirectory* packageDirectory = fPackageDirectories.Head()) - return packageDirectory->ModifiedTime(); - - timespec time = { 0, 0 }; - return time; -} - - -off_t -Directory::FileSize() const -{ - return 0; -} - - -Node* -Directory::GetNode() -{ - return this; -} - - -status_t -Directory::AddPackageNode(PackageNode* packageNode) -{ - if (!S_ISDIR(packageNode->Mode())) - return B_BAD_VALUE; - - PackageDirectory* packageDirectory - = dynamic_cast(packageNode); - - PackageDirectory* other = fPackageDirectories.Head(); - bool isNewest = other == NULL - || packageDirectory->ModifiedTime() > other->ModifiedTime(); - - if (isNewest) - fPackageDirectories.Insert(other, packageDirectory); - else - fPackageDirectories.Add(packageDirectory); - - return B_OK; -} - - -void -Directory::RemovePackageNode(PackageNode* packageNode) -{ - bool isNewest = packageNode == fPackageDirectories.Head(); - fPackageDirectories.Remove(dynamic_cast(packageNode)); - - // when removing the newest node, we need to find the next node (the list - // is not sorted) - PackageDirectory* newestNode = fPackageDirectories.Head(); - if (isNewest && newestNode != NULL) { - PackageDirectoryList::Iterator it = fPackageDirectories.GetIterator(); - it.Next(); - // skip the first one - while (PackageDirectory* otherNode = it.Next()) { - if (otherNode->ModifiedTime() > newestNode->ModifiedTime()) - newestNode = otherNode; - } - - fPackageDirectories.Remove(newestNode); - fPackageDirectories.Insert(fPackageDirectories.Head(), newestNode); - } -} - - -PackageNode* -Directory::GetPackageNode() -{ - return fPackageDirectories.Head(); -} - - status_t Directory::Read(off_t offset, void* buffer, size_t* bufferSize) { @@ -180,23 +75,6 @@ Directory::ReadSymlink(void* buffer, size_t* bufferSize) } -status_t -Directory::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) -{ - return UnpackingAttributeDirectoryCookie::Open(fPackageDirectories.Head(), - _cookie); -} - - -status_t -Directory::OpenAttribute(const char* name, int openMode, - AttributeCookie*& _cookie) -{ - return UnpackingAttributeCookie::Open(fPackageDirectories.Head(), name, - openMode, _cookie); -} - - void Directory::AddChild(Node* node) { @@ -243,18 +121,3 @@ Directory::RemoveDirectoryIterator(DirectoryIterator* iterator) { fIterators.Remove(iterator); } - - -RootDirectory::RootDirectory(ino_t id, const timespec& modifiedTime) - : - Directory(id), - fModifiedTime(modifiedTime) -{ -} - - -timespec -RootDirectory::ModifiedTime() const -{ - return fModifiedTime; -} diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.h b/src/add-ons/kernel/file_systems/packagefs/Directory.h index f9c9ac173f..e4909c8568 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.h +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.h @@ -7,8 +7,6 @@ #include "Node.h" -#include "PackageDirectory.h" -#include "UnpackingNode.h" struct DirectoryIterator : DoublyLinkedListLinkImpl { @@ -24,7 +22,7 @@ struct DirectoryIterator : DoublyLinkedListLinkImpl { typedef DoublyLinkedList DirectoryIteratorList; -class Directory : public Node, public UnpackingNode { +class Directory : public Node { public: Directory(ino_t id); virtual ~Directory(); @@ -34,30 +32,11 @@ public: virtual status_t VFSInit(dev_t deviceID); virtual void VFSUninit(); - virtual mode_t Mode() const; - virtual uid_t UserID() const; - virtual gid_t GroupID() const; - virtual timespec ModifiedTime() const; - virtual off_t FileSize() const; - - virtual Node* GetNode(); - - virtual status_t AddPackageNode(PackageNode* packageNode); - virtual void RemovePackageNode(PackageNode* packageNode); - - virtual PackageNode* GetPackageNode(); - virtual status_t Read(off_t offset, void* buffer, size_t* bufferSize); virtual status_t Read(io_request* request); - virtual status_t ReadSymlink(void* buffer, - size_t* bufferSize); - - virtual status_t OpenAttributeDirectory( - AttributeDirectoryCookie*& _cookie); - virtual status_t OpenAttribute(const char* name, int openMode, - AttributeCookie*& _cookie); + virtual status_t ReadSymlink(void* buffer, size_t* bufferSize); void AddChild(Node* node); void RemoveChild(Node* node); @@ -74,7 +53,6 @@ public: private: NodeNameHashTable fChildTable; NodeList fChildList; - PackageDirectoryList fPackageDirectories; DirectoryIteratorList fIterators; }; @@ -93,16 +71,4 @@ Directory::NextChild(Node* node) const } -class RootDirectory : public Directory { -public: - RootDirectory(ino_t id, - const timespec& modifiedTime); - - virtual timespec ModifiedTime() const; - -private: - timespec fModifiedTime; -}; - - #endif // DIRECTORY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index 3c88293997..2c28c97616 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -29,6 +29,7 @@ HAIKU_PACKAGE_FS_SOURCES = Resolvable.cpp UnpackingAttributeCookie.cpp UnpackingAttributeDirectoryCookie.cpp + UnpackingDirectory.cpp UnpackingLeafNode.cpp UnpackingNode.cpp Version.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp new file mode 100644 index 0000000000..b92a54c196 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp @@ -0,0 +1,195 @@ +/* + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "UnpackingDirectory.h" + +#include "DebugSupport.h" +#include "UnpackingAttributeCookie.h" +#include "UnpackingAttributeDirectoryCookie.h" +#include "Utils.h" + + +// #pragma mark - UnpackingDirectory + + +UnpackingDirectory::UnpackingDirectory(ino_t id) + : + Directory(id) +{ +} + + +UnpackingDirectory::~UnpackingDirectory() +{ +} + + +status_t +UnpackingDirectory::Init(Directory* parent, const char* name) +{ + return Directory::Init(parent, name); +} + + +mode_t +UnpackingDirectory::Mode() const +{ + if (PackageDirectory* packageDirectory = fPackageDirectories.Head()) + return packageDirectory->Mode(); + return S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; +} + + +uid_t +UnpackingDirectory::UserID() const +{ + if (PackageDirectory* packageDirectory = fPackageDirectories.Head()) + return packageDirectory->UserID(); + return 0; +} + + +gid_t +UnpackingDirectory::GroupID() const +{ + if (PackageDirectory* packageDirectory = fPackageDirectories.Head()) + return packageDirectory->GroupID(); + return 0; +} + + +timespec +UnpackingDirectory::ModifiedTime() const +{ + if (PackageDirectory* packageDirectory = fPackageDirectories.Head()) + return packageDirectory->ModifiedTime(); + + timespec time = { 0, 0 }; + return time; +} + + +off_t +UnpackingDirectory::FileSize() const +{ + return 0; +} + + +Node* +UnpackingDirectory::GetNode() +{ + return this; +} + + +status_t +UnpackingDirectory::AddPackageNode(PackageNode* packageNode) +{ + if (!S_ISDIR(packageNode->Mode())) + return B_BAD_VALUE; + + PackageDirectory* packageDirectory + = dynamic_cast(packageNode); + + PackageDirectory* other = fPackageDirectories.Head(); + bool isNewest = other == NULL + || packageDirectory->ModifiedTime() > other->ModifiedTime(); + + if (isNewest) + fPackageDirectories.Insert(other, packageDirectory); + else + fPackageDirectories.Add(packageDirectory); + + return B_OK; +} + + +void +UnpackingDirectory::RemovePackageNode(PackageNode* packageNode) +{ + bool isNewest = packageNode == fPackageDirectories.Head(); + fPackageDirectories.Remove(dynamic_cast(packageNode)); + + // when removing the newest node, we need to find the next node (the list + // is not sorted) + PackageDirectory* newestNode = fPackageDirectories.Head(); + if (isNewest && newestNode != NULL) { + PackageDirectoryList::Iterator it = fPackageDirectories.GetIterator(); + it.Next(); + // skip the first one + while (PackageDirectory* otherNode = it.Next()) { + if (otherNode->ModifiedTime() > newestNode->ModifiedTime()) + newestNode = otherNode; + } + + fPackageDirectories.Remove(newestNode); + fPackageDirectories.Insert(fPackageDirectories.Head(), newestNode); + } +} + + +PackageNode* +UnpackingDirectory::GetPackageNode() +{ + return fPackageDirectories.Head(); +} + + +status_t +UnpackingDirectory::Read(off_t offset, void* buffer, size_t* bufferSize) +{ + return B_IS_A_DIRECTORY; +} + + +status_t +UnpackingDirectory::Read(io_request* request) +{ + return B_IS_A_DIRECTORY; +} + + +status_t +UnpackingDirectory::ReadSymlink(void* buffer, size_t* bufferSize) +{ + return B_IS_A_DIRECTORY; +} + + +status_t +UnpackingDirectory::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) +{ + return UnpackingAttributeDirectoryCookie::Open(fPackageDirectories.Head(), + _cookie); +} + + +status_t +UnpackingDirectory::OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie) +{ + return UnpackingAttributeCookie::Open(fPackageDirectories.Head(), name, + openMode, _cookie); +} + + +// #pragma mark - RootDirectory + + +RootDirectory::RootDirectory(ino_t id, const timespec& modifiedTime) + : + UnpackingDirectory(id), + fModifiedTime(modifiedTime) +{ +} + + +timespec +RootDirectory::ModifiedTime() const +{ + return fModifiedTime; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h new file mode 100644 index 0000000000..2977ab1d90 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h @@ -0,0 +1,63 @@ +/* + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef UNPACKING_DIRECTORY_H +#define UNPACKING_DIRECTORY_H + + +#include "Directory.h" +#include "PackageDirectory.h" +#include "UnpackingNode.h" + + +class UnpackingDirectory : public Directory, public UnpackingNode { +public: + UnpackingDirectory(ino_t id); + virtual ~UnpackingDirectory(); + + virtual status_t Init(Directory* parent, const char* name); + + virtual mode_t Mode() const; + virtual uid_t UserID() const; + virtual gid_t GroupID() const; + virtual timespec ModifiedTime() const; + virtual off_t FileSize() const; + + virtual Node* GetNode(); + + virtual status_t AddPackageNode(PackageNode* packageNode); + virtual void RemovePackageNode(PackageNode* packageNode); + + virtual PackageNode* GetPackageNode(); + + virtual status_t Read(off_t offset, void* buffer, + size_t* bufferSize); + virtual status_t Read(io_request* request); + + virtual status_t ReadSymlink(void* buffer, + size_t* bufferSize); + + virtual status_t OpenAttributeDirectory( + AttributeDirectoryCookie*& _cookie); + virtual status_t OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie); + +private: + PackageDirectoryList fPackageDirectories; +}; + + +class RootDirectory : public UnpackingDirectory { +public: + RootDirectory(ino_t id, + const timespec& modifiedTime); + + virtual timespec ModifiedTime() const; + +private: + timespec fModifiedTime; +}; + + +#endif // UNPACKING_DIRECTORY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 19d546fbf3..4672543f97 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -31,7 +31,6 @@ #include #include "DebugSupport.h" -#include "Directory.h" #include "kernel_interface.h" #include "PackageDirectory.h" #include "PackageFile.h" @@ -39,6 +38,7 @@ #include "PackageSymlink.h" #include "Resolvable.h" #include "UnpackingLeafNode.h" +#include "UnpackingDirectory.h" #include "Version.h" @@ -1070,7 +1070,7 @@ Volume::_CreateUnpackingNode(mode_t mode, Directory* parent, const char* name, if (S_ISREG(mode) || S_ISLNK(mode)) unpackingNode = new(std::nothrow) UnpackingLeafNode(fNextNodeID++); else if (S_ISDIR(mode)) - unpackingNode = new(std::nothrow) Directory(fNextNodeID++); + unpackingNode = new(std::nothrow) UnpackingDirectory(fNextNodeID++); else RETURN_ERROR(B_UNSUPPORTED); From 5d5bdb495e4270c1826754e57e25e58816cce39a Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 23 Jun 2011 22:32:46 +0200 Subject: [PATCH 0084/1170] Update copyright year --- src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp index 41e6ca6df6..5364d78b89 100644 --- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp @@ -1,5 +1,5 @@ /* - * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. + * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de. * Distributed under the terms of the MIT License. */ From 5663e914c2970d0a7fa08c99347edb39c8cfd33f Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 00:05:37 +0200 Subject: [PATCH 0085/1170] UnpackingDirectory: Remove unnessary methods Remove Read() and ReadSymlink() methods which are already implemented in Directory. --- .../packagefs/UnpackingDirectory.cpp | 21 ------------------- .../packagefs/UnpackingDirectory.h | 7 ------- 2 files changed, 28 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp index b92a54c196..9d6046edaf 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp @@ -139,27 +139,6 @@ UnpackingDirectory::GetPackageNode() } -status_t -UnpackingDirectory::Read(off_t offset, void* buffer, size_t* bufferSize) -{ - return B_IS_A_DIRECTORY; -} - - -status_t -UnpackingDirectory::Read(io_request* request) -{ - return B_IS_A_DIRECTORY; -} - - -status_t -UnpackingDirectory::ReadSymlink(void* buffer, size_t* bufferSize) -{ - return B_IS_A_DIRECTORY; -} - - status_t UnpackingDirectory::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) { diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h index 2977ab1d90..79fcd8f5dc 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h @@ -31,13 +31,6 @@ public: virtual PackageNode* GetPackageNode(); - virtual status_t Read(off_t offset, void* buffer, - size_t* bufferSize); - virtual status_t Read(io_request* request); - - virtual status_t ReadSymlink(void* buffer, - size_t* bufferSize); - virtual status_t OpenAttributeDirectory( AttributeDirectoryCookie*& _cookie); virtual status_t OpenAttribute(const char* name, int openMode, From ffc66d8dd7ed88062eba71386d61e8b310f42d6d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 01:04:32 +0200 Subject: [PATCH 0086/1170] Specify mount type when mounting packagefs --- src/system/kernel/fs/vfs_boot.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/system/kernel/fs/vfs_boot.cpp b/src/system/kernel/fs/vfs_boot.cpp index f603239e79..6f233c4981 100644 --- a/src/system/kernel/fs/vfs_boot.cpp +++ b/src/system/kernel/fs/vfs_boot.cpp @@ -514,7 +514,7 @@ vfs_mount_boot_file_system(kernel_args* args) dev_t systemPackageMount = _kern_mount("/boot/system", NULL, kPackageFSName, 0, - "packages /boot/system/packages; shine-through system", + "packages /boot/system/packages; type system", 0 /* unused argument length */); if (systemPackageMount < 0) { panic("Failed to mount system packagefs: %s", From dce13a0a8cdc1fa99f47d2b1e0cc2f70aeb423a3 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 01:08:18 +0200 Subject: [PATCH 0087/1170] Node: Add setters for ID and parent --- src/add-ons/kernel/file_systems/packagefs/Node.cpp | 14 ++++++++++++++ src/add-ons/kernel/file_systems/packagefs/Node.h | 3 +++ 2 files changed, 17 insertions(+) diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.cpp b/src/add-ons/kernel/file_systems/packagefs/Node.cpp index 2238cac148..7f79d62c6c 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Node.cpp @@ -40,3 +40,17 @@ Node::Init(Directory* parent, const char* name) return B_OK; } + + +void +Node::SetID(ino_t id) +{ + fID = id; +} + + +void +Node::SetParent(Directory* parent) +{ + fParent = parent; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h index 9b0dc31efe..d192122ab0 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.h +++ b/src/add-ons/kernel/file_systems/packagefs/Node.h @@ -47,6 +47,9 @@ public: virtual status_t VFSInit(dev_t deviceID) = 0; virtual void VFSUninit() = 0; + void SetID(ino_t id); + void SetParent(Directory* parent); + virtual mode_t Mode() const = 0; virtual uid_t UserID() const = 0; virtual gid_t GroupID() const = 0; From b8a96de92993a211fef83f249dd815e7ffa0014d Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 01:08:33 +0200 Subject: [PATCH 0088/1170] Add yet empty package-links directory * Add PackageLinksDirectory Directory subclass. Currently not doing anything. * PackageFSRoot: Create a PackageLinksDirectory. * Volume: Add/remove the package links directory for the system volume. --- .../kernel/file_systems/packagefs/Jamfile | 1 + .../file_systems/packagefs/PackageFSRoot.cpp | 16 ++- .../file_systems/packagefs/PackageFSRoot.h | 6 + .../packagefs/PackageLinksDirectory.cpp | 116 ++++++++++++++++++ .../packagefs/PackageLinksDirectory.h | 35 ++++++ .../kernel/file_systems/packagefs/Volume.cpp | 40 +++++- .../kernel/file_systems/packagefs/Volume.h | 3 + 7 files changed, 214 insertions(+), 3 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index 2c28c97616..757707b913 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -23,6 +23,7 @@ HAIKU_PACKAGE_FS_SOURCES = PackageFile.cpp PackageFSRoot.cpp PackageLeafNode.cpp + PackageLinksDirectory.cpp PackageNode.cpp PackageNodeAttribute.cpp PackageSymlink.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp index e91adafa05..923c23df4c 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp @@ -11,6 +11,10 @@ #include #include "DebugSupport.h" +#include "PackageLinksDirectory.h" + + +static const char* const kPackageLinksDirectoryName = "package-links"; mutex PackageFSRoot::sRootListLock = MUTEX_INITIALIZER("packagefs root list"); @@ -21,7 +25,8 @@ PackageFSRoot::PackageFSRoot(dev_t deviceID, ino_t nodeID) : fDeviceID(deviceID), fNodeID(nodeID), - fSystemVolume(NULL) + fSystemVolume(NULL), + fPackageLinksDirectory(NULL) { rw_lock_init(&fLock, "packagefs root"); } @@ -53,6 +58,15 @@ PackageFSRoot::Init() if (error != B_OK) RETURN_ERROR(error); + // create package links directory + fPackageLinksDirectory = new(std::nothrow) PackageLinksDirectory; + if (fPackageLinksDirectory == NULL) + return B_NO_MEMORY; + + error = fPackageLinksDirectory->Init(NULL, kPackageLinksDirectoryName); + if (error != B_OK) + RETURN_ERROR(error); + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h index 9f08229971..bca3f11b61 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h @@ -17,6 +17,9 @@ #include "Volume.h" +class PackageLinksDirectory; + + class PackageFSRoot : private BReferenceable, public DoublyLinkedListLinkImpl { public: @@ -45,6 +48,8 @@ public: bool IsCustom() const { return fDeviceID < 0; } Volume* SystemVolume() const; + PackageLinksDirectory* GetPackageLinksDirectory() const + { return fPackageLinksDirectory; } private: typedef DoublyLinkedList RootList; @@ -69,6 +74,7 @@ private: VolumeList fVolumes; Volume* fSystemVolume; PackageFamilyHashTable fPackageFamilies; + PackageLinksDirectory* fPackageLinksDirectory; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp new file mode 100644 index 0000000000..29a544068f --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp @@ -0,0 +1,116 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "PackageLinksDirectory.h" + +#include "AttributeDirectoryCookie.h" + + +namespace { + +class EmptyAttributeDirectoryCookie : public AttributeDirectoryCookie { +public: + virtual status_t Close() + { + return B_OK; + } + + virtual status_t Read(dev_t volumeID, ino_t nodeID, struct dirent* buffer, + size_t bufferSize, uint32* _count) + { + *_count = 0; + return B_OK; + } + + virtual status_t Rewind() + { + return B_OK; + } +}; + + +} // unnamed namespace + + +PackageLinksDirectory::PackageLinksDirectory() + : + Directory(0) + // the ID needs to be assigned later, when added to a volume +{ + bigtime_t timeMicros = real_time_clock_usecs(); + + fModifiedTime.tv_sec = timeMicros / 1000000; + fModifiedTime.tv_nsec = (timeMicros % 1000000) * 1000; +} + + +PackageLinksDirectory::~PackageLinksDirectory() +{ +} + + +status_t +PackageLinksDirectory::Init(Directory* parent, const char* name) +{ + return Directory::Init(parent, name); +} + + +mode_t +PackageLinksDirectory::Mode() const +{ + return S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; +} + + +uid_t +PackageLinksDirectory::UserID() const +{ + return 0; +} + + +gid_t +PackageLinksDirectory::GroupID() const +{ + return 0; +} + + +timespec +PackageLinksDirectory::ModifiedTime() const +{ + return fModifiedTime; +} + + +off_t +PackageLinksDirectory::FileSize() const +{ + return 0; +} + + +status_t +PackageLinksDirectory::OpenAttributeDirectory( + AttributeDirectoryCookie*& _cookie) +{ + AttributeDirectoryCookie* cookie + = new(std::nothrow) EmptyAttributeDirectoryCookie; + if (cookie == NULL) + return B_NO_MEMORY; + + _cookie = cookie; + return B_OK; +} + + +status_t +PackageLinksDirectory::OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie) +{ + return B_ENTRY_NOT_FOUND; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h new file mode 100644 index 0000000000..44b583efbc --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h @@ -0,0 +1,35 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef PACKAGE_LINKS_DIRECTORY_H +#define PACKAGE_LINKS_DIRECTORY_H + + +#include "Directory.h" + + +class PackageLinksDirectory : public Directory { +public: + PackageLinksDirectory(); + virtual ~PackageLinksDirectory(); + + virtual status_t Init(Directory* parent, const char* name); + + virtual mode_t Mode() const; + virtual uid_t UserID() const; + virtual gid_t GroupID() const; + virtual timespec ModifiedTime() const; + virtual off_t FileSize() const; + + virtual status_t OpenAttributeDirectory( + AttributeDirectoryCookie*& _cookie); + virtual status_t OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie); + +private: + timespec fModifiedTime; +}; + + +#endif // PACKAGE_LINKS_DIRECTORY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 4672543f97..6d14b6f330 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -35,6 +35,7 @@ #include "PackageDirectory.h" #include "PackageFile.h" #include "PackageFSRoot.h" +#include "PackageLinksDirectory.h" #include "PackageSymlink.h" #include "Resolvable.h" #include "UnpackingLeafNode.h" @@ -447,8 +448,12 @@ Volume::~Volume() node = next; } - if (fPackageFSRoot != NULL) + if (fPackageFSRoot != NULL) { + if (this == fPackageFSRoot->SystemVolume()) + _RemovePackageLinksDirectory(); + fPackageFSRoot->UnregisterVolume(this); + } if (fRootDirectory != NULL) fRootDirectory->ReleaseReference(); @@ -1375,6 +1380,37 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting) status_t Volume::_AddPackageLinksDirectory() { -// TODO:... + // called when mounting, so we don't need to lock the volume + + PackageLinksDirectory* packageLinksDirectory + = fPackageFSRoot->GetPackageLinksDirectory(); + + NodeWriteLocker rootDirectoryWriteLocker(fRootDirectory); + NodeWriteLocker packageLinksDirectoryWriteLocker(packageLinksDirectory); + + packageLinksDirectory->SetID(fNextNodeID++); + packageLinksDirectory->SetParent(fRootDirectory); + + fRootDirectory->AddChild(packageLinksDirectory); + fNodes.Insert(packageLinksDirectory); + packageLinksDirectory->AcquireReference(); + return B_OK; } + + +void +Volume::_RemovePackageLinksDirectory() +{ + PackageLinksDirectory* packageLinksDirectory + = fPackageFSRoot->GetPackageLinksDirectory(); + + VolumeWriteLocker volumeLocker(this); + NodeWriteLocker rootDirectoryWriteLocker(fRootDirectory); + NodeWriteLocker packageLinksDirectoryWriteLocker(packageLinksDirectory); + + if (packageLinksDirectory->Parent() == fRootDirectory) { + _RemoveNode(packageLinksDirectory); + packageLinksDirectory->SetParent(NULL); + } +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h index e7e5a3a867..7dc209f4af 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h @@ -144,7 +144,10 @@ private: status_t _InitMountType(const char* mountType); status_t _CreateShineThroughDirectories( const char* shineThroughSetting); + status_t _AddPackageLinksDirectory(); + void _RemovePackageLinksDirectory(); + private: mutable rw_lock fLock; fs_volume* fFSVolume; From 7e57d125231aa57c336d056bab12048ead402131 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 01:20:41 +0200 Subject: [PATCH 0089/1170] Move PackageFamily table to PackageLinksDirectory --- .../file_systems/packagefs/PackageFSRoot.cpp | 47 ++------------- .../file_systems/packagefs/PackageFSRoot.h | 2 - .../packagefs/PackageLinksDirectory.cpp | 58 +++++++++++++++++++ .../packagefs/PackageLinksDirectory.h | 5 ++ 4 files changed, 67 insertions(+), 45 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp index 923c23df4c..6684de86d8 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp @@ -54,16 +54,13 @@ PackageFSRoot::GlobalUninit() status_t PackageFSRoot::Init() { - status_t error = fPackageFamilies.Init(); - if (error != B_OK) - RETURN_ERROR(error); - // create package links directory fPackageLinksDirectory = new(std::nothrow) PackageLinksDirectory; if (fPackageLinksDirectory == NULL) return B_NO_MEMORY; - error = fPackageLinksDirectory->Init(NULL, kPackageLinksDirectoryName); + status_t error = fPackageLinksDirectory->Init(NULL, + kPackageLinksDirectoryName); if (error != B_OK) RETURN_ERROR(error); @@ -162,50 +159,14 @@ PackageFSRoot::UnregisterVolume(Volume* volume) status_t PackageFSRoot::AddPackage(Package* package) { - // Create a package family -- there might already be one, but since that's - // unlikely, we don't bother to check and recheck later. - PackageFamily* packageFamily = new(std::nothrow) PackageFamily; - if (packageFamily == NULL) - return B_NO_MEMORY; - ObjectDeleter packageFamilyDeleter(packageFamily); - - status_t error = packageFamily->Init(package); - if (error != B_OK) - RETURN_ERROR(error); - - // add the family - PackageFSRootWriteLocker writeLocker(this); - if (PackageFamily* otherPackageFamily - = fPackageFamilies.Lookup(packageFamily->Name())) { - packageFamily->RemovePackage(package); - packageFamily = otherPackageFamily; - packageFamily->AddPackage(package); - } else - fPackageFamilies.Insert(packageFamilyDeleter.Detach()); - -// TODO:... - - return B_OK; + return fPackageLinksDirectory->AddPackage(package); } void PackageFSRoot::RemovePackage(Package* package) { - PackageFSRootWriteLocker writeLocker(this); - - PackageFamily* packageFamily = package->Family(); - if (packageFamily == NULL) - return; - - packageFamily->RemovePackage(package); - - if (packageFamily->IsEmpty()) { - fPackageFamilies.Remove(packageFamily); - delete packageFamily; - } - -// TODO:... + fPackageLinksDirectory->RemovePackage(package); } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h index bca3f11b61..18d6618c49 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h @@ -13,7 +13,6 @@ #include -#include "PackageFamily.h" #include "Volume.h" @@ -73,7 +72,6 @@ private: ino_t fNodeID; VolumeList fVolumes; Volume* fSystemVolume; - PackageFamilyHashTable fPackageFamilies; PackageLinksDirectory* fPackageLinksDirectory; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp index 29a544068f..d45d5407e8 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp @@ -6,7 +6,10 @@ #include "PackageLinksDirectory.h" +#include + #include "AttributeDirectoryCookie.h" +#include "DebugSupport.h" namespace { @@ -55,6 +58,10 @@ PackageLinksDirectory::~PackageLinksDirectory() status_t PackageLinksDirectory::Init(Directory* parent, const char* name) { + status_t error = fPackageFamilies.Init(); + if (error != B_OK) + RETURN_ERROR(error); + return Directory::Init(parent, name); } @@ -114,3 +121,54 @@ PackageLinksDirectory::OpenAttribute(const char* name, int openMode, { return B_ENTRY_NOT_FOUND; } + + +status_t +PackageLinksDirectory::AddPackage(Package* package) +{ + // Create a package family -- there might already be one, but since that's + // unlikely, we don't bother to check and recheck later. + PackageFamily* packageFamily = new(std::nothrow) PackageFamily; + if (packageFamily == NULL) + return B_NO_MEMORY; + ObjectDeleter packageFamilyDeleter(packageFamily); + + status_t error = packageFamily->Init(package); + if (error != B_OK) + RETURN_ERROR(error); + + // add the family + NodeWriteLocker writeLocker(this); + if (PackageFamily* otherPackageFamily + = fPackageFamilies.Lookup(packageFamily->Name())) { + packageFamily->RemovePackage(package); + packageFamily = otherPackageFamily; + packageFamily->AddPackage(package); + } else + fPackageFamilies.Insert(packageFamilyDeleter.Detach()); + +// TODO:... + + return B_OK; +} + + +void +PackageLinksDirectory::RemovePackage(Package* package) +{ + NodeWriteLocker writeLocker(this); + + PackageFamily* packageFamily = package->Family(); + if (packageFamily == NULL) + return; + + packageFamily->RemovePackage(package); + + if (packageFamily->IsEmpty()) { + fPackageFamilies.Remove(packageFamily); + delete packageFamily; + } + +// TODO:... +} + diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h index 44b583efbc..0368c80a70 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h @@ -7,6 +7,7 @@ #include "Directory.h" +#include "PackageFamily.h" class PackageLinksDirectory : public Directory { @@ -27,8 +28,12 @@ public: virtual status_t OpenAttribute(const char* name, int openMode, AttributeCookie*& _cookie); + status_t AddPackage(Package* package); + void RemovePackage(Package* package); + private: timespec fModifiedTime; + PackageFamilyHashTable fPackageFamilies; }; From a2fc40be04897a8bd7be45e1e1a9296c5aab042f Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 01:37:49 +0200 Subject: [PATCH 0090/1170] Move EmptyAttributeDirectoryCookie to own files --- .../EmptyAttributeDirectoryCookie.cpp | 30 +++++++++++++++++++ .../packagefs/EmptyAttributeDirectoryCookie.h | 22 ++++++++++++++ .../kernel/file_systems/packagefs/Jamfile | 1 + .../packagefs/PackageLinksDirectory.cpp | 28 +---------------- 4 files changed, 54 insertions(+), 27 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.h diff --git a/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.cpp new file mode 100644 index 0000000000..dd0da85c5f --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.cpp @@ -0,0 +1,30 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "EmptyAttributeDirectoryCookie.h" + + +status_t +EmptyAttributeDirectoryCookie::Close() +{ + return B_OK; +} + + +status_t +EmptyAttributeDirectoryCookie::Read(dev_t volumeID, ino_t nodeID, + struct dirent* buffer, size_t bufferSize, uint32* _count) +{ + *_count = 0; + return B_OK; +} + + +status_t +EmptyAttributeDirectoryCookie::Rewind() +{ + return B_OK; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.h b/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.h new file mode 100644 index 0000000000..699b3d5687 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.h @@ -0,0 +1,22 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef EMPTY_ATTRIBUTE_DIRECTORY_COOKIE_H +#define EMPTY_ATTRIBUTE_DIRECTORY_COOKIE_H + + +#include "AttributeDirectoryCookie.h" + + +class EmptyAttributeDirectoryCookie : public AttributeDirectoryCookie { +public: + virtual status_t Close(); + virtual status_t Read(dev_t volumeID, ino_t nodeID, + struct dirent* buffer, size_t bufferSize, + uint32* _count); + virtual status_t Rewind(); +}; + + +#endif // EMPTY_ATTRIBUTE_DIRECTORY_COOKIE_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index 757707b913..0f5ef9500e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -13,6 +13,7 @@ HAIKU_PACKAGE_FS_SOURCES = DebugSupport.cpp Dependency.cpp Directory.cpp + EmptyAttributeDirectoryCookie.cpp GlobalFactory.cpp kernel_interface.cpp Node.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp index d45d5407e8..71e58b774e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp @@ -8,36 +8,10 @@ #include -#include "AttributeDirectoryCookie.h" +#include "EmptyAttributeDirectoryCookie.h" #include "DebugSupport.h" -namespace { - -class EmptyAttributeDirectoryCookie : public AttributeDirectoryCookie { -public: - virtual status_t Close() - { - return B_OK; - } - - virtual status_t Read(dev_t volumeID, ino_t nodeID, struct dirent* buffer, - size_t bufferSize, uint32* _count) - { - *_count = 0; - return B_OK; - } - - virtual status_t Rewind() - { - return B_OK; - } -}; - - -} // unnamed namespace - - PackageLinksDirectory::PackageLinksDirectory() : Directory(0) From 05d7d4818e11f22044e134c680fe650347281481 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 01:42:26 +0200 Subject: [PATCH 0091/1170] Add support function get_real_time() --- .../packagefs/PackageLinksDirectory.cpp | 6 ++---- src/add-ons/kernel/file_systems/packagefs/Utils.h | 13 +++++++++++++ 2 files changed, 15 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp index 71e58b774e..48a9ac835f 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp @@ -10,6 +10,7 @@ #include "EmptyAttributeDirectoryCookie.h" #include "DebugSupport.h" +#include "Utils.h" PackageLinksDirectory::PackageLinksDirectory() @@ -17,10 +18,7 @@ PackageLinksDirectory::PackageLinksDirectory() Directory(0) // the ID needs to be assigned later, when added to a volume { - bigtime_t timeMicros = real_time_clock_usecs(); - - fModifiedTime.tv_sec = timeMicros / 1000000; - fModifiedTime.tv_nsec = (timeMicros % 1000000) * 1000; + get_real_time(fModifiedTime); } diff --git a/src/add-ons/kernel/file_systems/packagefs/Utils.h b/src/add-ons/kernel/file_systems/packagefs/Utils.h index e81b475cba..2a9359368e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Utils.h +++ b/src/add-ons/kernel/file_systems/packagefs/Utils.h @@ -8,6 +8,9 @@ #include #include +#include + +#include inline bool operator<(const timespec& a, const timespec& b) @@ -38,4 +41,14 @@ set_dirent_name(struct dirent* buffer, size_t bufferSize, const char* name, } +static inline void +get_real_time(timespec& time) +{ + bigtime_t timeMicros = real_time_clock_usecs(); + + time.tv_sec = timeMicros / 1000000; + time.tv_nsec = (timeMicros % 1000000) * 1000; +} + + #endif // UTILS_H From 4031a32accd2bba7bca7c8e93494e95564ae3d60 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 02:15:56 +0200 Subject: [PATCH 0092/1170] WIP: Create empty package links directories * Rename PackageFamily to PackageLinkDirectory and derive from Directory. * PackageLinksDirectory: Add the PackageLinkDirectory objects as children and remove the no longer needed hash table (we use the Directory's child hash table). --- .../kernel/file_systems/packagefs/Jamfile | 2 +- .../kernel/file_systems/packagefs/Package.cpp | 2 +- .../kernel/file_systems/packagefs/Package.h | 13 +- .../file_systems/packagefs/PackageFamily.cpp | 78 --------- .../file_systems/packagefs/PackageFamily.h | 71 -------- .../packagefs/PackageLinkDirectory.cpp | 151 ++++++++++++++++++ .../packagefs/PackageLinkDirectory.h | 44 +++++ .../packagefs/PackageLinksDirectory.cpp | 57 ++++--- .../packagefs/PackageLinksDirectory.h | 5 +- 9 files changed, 238 insertions(+), 185 deletions(-) delete mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageFamily.cpp delete mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageFamily.h create mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index 0f5ef9500e..9431073366 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -20,10 +20,10 @@ HAIKU_PACKAGE_FS_SOURCES = Package.cpp PackageDirectory.cpp PackageDomain.cpp - PackageFamily.cpp PackageFile.cpp PackageFSRoot.cpp PackageLeafNode.cpp + PackageLinkDirectory.cpp PackageLinksDirectory.cpp PackageNode.cpp PackageNodeAttribute.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.cpp b/src/add-ons/kernel/file_systems/packagefs/Package.cpp index 0221ce1ed4..487ffd0fdf 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Package.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Package.cpp @@ -25,7 +25,7 @@ Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID) fFileName(NULL), fName(NULL), fVersion(NULL), - fFamily(NULL), + fLinkDirectory(NULL), fFD(-1), fOpenCount(0), fNodeID(nodeID), diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.h b/src/add-ons/kernel/file_systems/packagefs/Package.h index 7d63ac27d1..9ccc759164 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Package.h +++ b/src/add-ons/kernel/file_systems/packagefs/Package.h @@ -20,7 +20,7 @@ class PackageDomain; -class PackageFamily; +class PackageLinkDirectory; class Version; @@ -44,10 +44,11 @@ public: ::Version* Version() const { return fVersion; } - void SetFamily(PackageFamily* family) - { fFamily = family; } - PackageFamily* Family() const - { return fFamily; } + void SetLinkDirectory( + PackageLinkDirectory* linkDirectory) + { fLinkDirectory = linkDirectory; } + PackageLinkDirectory* LinkDirectory() const + { return fLinkDirectory; } Package*& FileNameHashTableNext() { return fFileNameHashTableNext; } @@ -67,7 +68,7 @@ private: char* fFileName; char* fName; ::Version* fVersion; - PackageFamily* fFamily; + PackageLinkDirectory* fLinkDirectory; int fFD; uint32 fOpenCount; Package* fFileNameHashTableNext; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFamily.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFamily.cpp deleted file mode 100644 index 18ca55b67b..0000000000 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFamily.cpp +++ /dev/null @@ -1,78 +0,0 @@ -/* - * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. - * Distributed under the terms of the MIT License. - */ - - -#include "PackageFamily.h" - -#include -#include - -#include "DebugSupport.h" -#include "Version.h" - - -PackageFamily::PackageFamily() - : - fName(NULL) -{ -} - - -PackageFamily::~PackageFamily() -{ - while (Package* package = fPackages.RemoveHead()) - package->SetFamily(NULL); - - free(fName); -} - - -status_t -PackageFamily::Init(Package* package) -{ - // compute the allocation size needed for the versioned name - size_t nameLength = strlen(package->Name()); - size_t size = nameLength + 1; - - Version* version = package->Version(); - if (version != NULL) { - size += 1 + version->ToString(NULL, 0); - // + 1 for the '-' - } - - // allocate the name and compose it - fName = (char*)malloc(size); - if (fName == NULL) - return B_NO_MEMORY; - - memcpy(fName, package->Name(), nameLength + 1); - if (version != NULL) { - fName[nameLength] = '-'; - version->ToString(fName + nameLength + 1, size - nameLength - 1); - } - - // add the package - AddPackage(package); - - return B_OK; -} - - -void -PackageFamily::AddPackage(Package* package) -{ - fPackages.Add(package); - package->SetFamily(this); -} - - -void -PackageFamily::RemovePackage(Package* package) -{ - ASSERT(package->Family() == this); - - package->SetFamily(NULL); - fPackages.Remove(package); -} diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFamily.h b/src/add-ons/kernel/file_systems/packagefs/PackageFamily.h deleted file mode 100644 index 33939a0b54..0000000000 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFamily.h +++ /dev/null @@ -1,71 +0,0 @@ -/* - * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. - * Distributed under the terms of the MIT License. - */ -#ifndef PACKAGE_FAMILY_H -#define PACKAGE_FAMILY_H - - -#include - -#include "Package.h" - - -/*! A set of equally named and versioned packages. - This should only happen when the same package is installed in multiple - domains (e.g. common and home). -*/ -class PackageFamily { -public: - PackageFamily(); - ~PackageFamily(); - - status_t Init(Package* package); - - const char* Name() const { return fName; } - - void AddPackage(Package* package); - void RemovePackage(Package* package); - - bool IsEmpty() const - { return fPackages.IsEmpty(); } - - PackageFamily*& HashNext() { return fHashNext; } - -private: - PackageFamily* fHashNext; - char* fName; - PackageList fPackages; -}; - - -struct PackageFamilyHashDefinition { - typedef const char* KeyType; - typedef PackageFamily ValueType; - - size_t HashKey(const char* key) const - { - return hash_hash_string(key); - } - - size_t Hash(const PackageFamily* value) const - { - return HashKey(value->Name()); - } - - bool Compare(const char* key, const PackageFamily* value) const - { - return strcmp(value->Name(), key) == 0; - } - - PackageFamily*& GetLink(PackageFamily* value) const - { - return value->HashNext(); - } -}; - - -typedef BOpenHashTable PackageFamilyHashTable; - - -#endif // PACKAGE_FAMILY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp new file mode 100644 index 0000000000..fa735f3196 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp @@ -0,0 +1,151 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "PackageLinkDirectory.h" + +#include + +#include "EmptyAttributeDirectoryCookie.h" +#include "DebugSupport.h" +#include "Utils.h" +#include "Version.h" + + +PackageLinkDirectory::PackageLinkDirectory() + : + Directory(0) + // the ID needs to be assigned later, when added to a volume +{ + get_real_time(fModifiedTime); +} + + +PackageLinkDirectory::~PackageLinkDirectory() +{ +} + + +status_t +PackageLinkDirectory::Init(Directory* parent, Package* package) +{ + // compute the allocation size needed for the versioned name + size_t nameLength = strlen(package->Name()); + size_t size = nameLength + 1; + + Version* version = package->Version(); + if (version != NULL) { + size += 1 + version->ToString(NULL, 0); + // + 1 for the '-' + } + + // allocate the name and compose it + char* name = (char*)malloc(size); + if (name == NULL) + return B_NO_MEMORY; + MemoryDeleter nameDeleter(name); + + memcpy(name, package->Name(), nameLength + 1); + if (version != NULL) { + name[nameLength] = '-'; + version->ToString(name + nameLength + 1, size - nameLength - 1); + } + + // init the directory/node + status_t error = Init(parent, name); + // TODO: This copies the name unnecessarily! + if (error != B_OK) + RETURN_ERROR(error); + + // add the package + AddPackage(package); + + return B_OK; +} + + +status_t +PackageLinkDirectory::Init(Directory* parent, const char* name) +{ + return Directory::Init(parent, name); +} + + +mode_t +PackageLinkDirectory::Mode() const +{ + return S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; +} + + +uid_t +PackageLinkDirectory::UserID() const +{ + return 0; +} + + +gid_t +PackageLinkDirectory::GroupID() const +{ + return 0; +} + + +timespec +PackageLinkDirectory::ModifiedTime() const +{ + return fModifiedTime; +} + + +off_t +PackageLinkDirectory::FileSize() const +{ + return 0; +} + + +status_t +PackageLinkDirectory::OpenAttributeDirectory( + AttributeDirectoryCookie*& _cookie) +{ + AttributeDirectoryCookie* cookie + = new(std::nothrow) EmptyAttributeDirectoryCookie; + if (cookie == NULL) + return B_NO_MEMORY; + + _cookie = cookie; + return B_OK; +} + + +status_t +PackageLinkDirectory::OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie) +{ + return B_ENTRY_NOT_FOUND; +} + + +void +PackageLinkDirectory::AddPackage(Package* package) +{ + // TODO: Add in priority order! + fPackages.Add(package); + package->SetLinkDirectory(this); +} + + +void +PackageLinkDirectory::RemovePackage(Package* package) +{ + + ASSERT(package->LinkDirectory() == this); + + package->SetLinkDirectory(NULL); + fPackages.Remove(package); + // TODO: Check whether that was the top priority package! +} diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h new file mode 100644 index 0000000000..6b8841f340 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h @@ -0,0 +1,44 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef PACKAGE_LINK_DIRECTORY_H +#define PACKAGE_LINK_DIRECTORY_H + + +#include "Directory.h" +#include "Package.h" + + +class PackageLinkDirectory : public Directory { +public: + PackageLinkDirectory(); + virtual ~PackageLinkDirectory(); + + status_t Init(Directory* parent, Package* package); + virtual status_t Init(Directory* parent, const char* name); + + virtual mode_t Mode() const; + virtual uid_t UserID() const; + virtual gid_t GroupID() const; + virtual timespec ModifiedTime() const; + virtual off_t FileSize() const; + + virtual status_t OpenAttributeDirectory( + AttributeDirectoryCookie*& _cookie); + virtual status_t OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie); + + void AddPackage(Package* package); + void RemovePackage(Package* package); + + bool IsEmpty() const + { return fPackages.IsEmpty(); } + +private: + timespec fModifiedTime; + PackageList fPackages; +}; + + +#endif // PACKAGE_LINK_DIRECTORY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp index 48a9ac835f..c37182dec6 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp @@ -10,6 +10,7 @@ #include "EmptyAttributeDirectoryCookie.h" #include "DebugSupport.h" +#include "PackageLinkDirectory.h" #include "Utils.h" @@ -30,10 +31,6 @@ PackageLinksDirectory::~PackageLinksDirectory() status_t PackageLinksDirectory::Init(Directory* parent, const char* name) { - status_t error = fPackageFamilies.Init(); - if (error != B_OK) - RETURN_ERROR(error); - return Directory::Init(parent, name); } @@ -98,26 +95,32 @@ PackageLinksDirectory::OpenAttribute(const char* name, int openMode, status_t PackageLinksDirectory::AddPackage(Package* package) { - // Create a package family -- there might already be one, but since that's - // unlikely, we don't bother to check and recheck later. - PackageFamily* packageFamily = new(std::nothrow) PackageFamily; - if (packageFamily == NULL) + // Create a package link directory -- there might already be one, but since + // that's unlikely, we don't bother to check and recheck later. + PackageLinkDirectory* linkDirectory + = new(std::nothrow) PackageLinkDirectory; + if (linkDirectory == NULL) return B_NO_MEMORY; - ObjectDeleter packageFamilyDeleter(packageFamily); + BReference linkDirectoryReference(linkDirectory, + true); - status_t error = packageFamily->Init(package); + status_t error = linkDirectory->Init(this, package); if (error != B_OK) RETURN_ERROR(error); - // add the family + // add the link directory NodeWriteLocker writeLocker(this); - if (PackageFamily* otherPackageFamily - = fPackageFamilies.Lookup(packageFamily->Name())) { - packageFamily->RemovePackage(package); - packageFamily = otherPackageFamily; - packageFamily->AddPackage(package); + if (Node* child = FindChild(linkDirectory->Name())) { + PackageLinkDirectory* otherLinkDirectory + = dynamic_cast(child); + if (otherLinkDirectory != NULL) + RETURN_ERROR(B_BAD_VALUE); + + linkDirectory->RemovePackage(package); + linkDirectory = otherLinkDirectory; + linkDirectory->AddPackage(package); } else - fPackageFamilies.Insert(packageFamilyDeleter.Detach()); + AddChild(linkDirectory); // TODO:... @@ -128,18 +131,20 @@ PackageLinksDirectory::AddPackage(Package* package) void PackageLinksDirectory::RemovePackage(Package* package) { - NodeWriteLocker writeLocker(this); - - PackageFamily* packageFamily = package->Family(); - if (packageFamily == NULL) + // get the package's link directory and remove the package from it + PackageLinkDirectory* linkDirectory = package->LinkDirectory(); + if (linkDirectory == NULL) return; - packageFamily->RemovePackage(package); + BReference linkDirectoryReference(linkDirectory); - if (packageFamily->IsEmpty()) { - fPackageFamilies.Remove(packageFamily); - delete packageFamily; - } + NodeWriteLocker writeLocker(this); + + linkDirectory->RemovePackage(package); + + // if empty, remove the link directory itself + if (linkDirectory->IsEmpty()) + RemoveChild(linkDirectory); // TODO:... } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h index 0368c80a70..c1659ee324 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h @@ -7,7 +7,9 @@ #include "Directory.h" -#include "PackageFamily.h" + + +class Package; class PackageLinksDirectory : public Directory { @@ -33,7 +35,6 @@ public: private: timespec fModifiedTime; - PackageFamilyHashTable fPackageFamilies; }; From 3e7333b7c188f2193a1bc5109c101461f33197b9 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 03:08:10 +0200 Subject: [PATCH 0093/1170] Add package link directories to system volume * Add PackageLinksListener interface. It is used by PackageLink[s]Directory to notify a listener about changes. * Volume does now implement PackageLinksListener and recursively adds/ removes package link directories. This makes the package link directories appear at least. They are still empty. --- .../kernel/file_systems/packagefs/Jamfile | 1 + .../packagefs/PackageLinkDirectory.cpp | 28 ++++++- .../packagefs/PackageLinkDirectory.h | 9 ++- .../packagefs/PackageLinksDirectory.cpp | 24 ++++-- .../packagefs/PackageLinksDirectory.h | 5 ++ .../packagefs/PackageLinksListener.cpp | 13 ++++ .../packagefs/PackageLinksListener.h | 23 ++++++ .../kernel/file_systems/packagefs/Volume.cpp | 75 +++++++++++++++++-- .../kernel/file_systems/packagefs/Volume.h | 15 +++- 9 files changed, 173 insertions(+), 20 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.h diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index 9431073366..d9a68ab980 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -25,6 +25,7 @@ HAIKU_PACKAGE_FS_SOURCES = PackageLeafNode.cpp PackageLinkDirectory.cpp PackageLinksDirectory.cpp + PackageLinksListener.cpp PackageNode.cpp PackageNodeAttribute.cpp PackageSymlink.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp index fa735f3196..eb9879ee72 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp @@ -10,6 +10,7 @@ #include "EmptyAttributeDirectoryCookie.h" #include "DebugSupport.h" +#include "PackageLinksListener.h" #include "Utils.h" #include "Version.h" @@ -60,7 +61,7 @@ PackageLinkDirectory::Init(Directory* parent, Package* package) RETURN_ERROR(error); // add the package - AddPackage(package); + AddPackage(package, NULL); return B_OK; } @@ -131,21 +132,40 @@ PackageLinkDirectory::OpenAttribute(const char* name, int openMode, void -PackageLinkDirectory::AddPackage(Package* package) +PackageLinkDirectory::AddPackage(Package* package, + PackageLinksListener* listener) { + NodeWriteLocker writeLocker(this); + + if (listener != NULL) + listener->PackageLinkDirectoryRemoved(this); + // TODO: Add in priority order! fPackages.Add(package); package->SetLinkDirectory(this); + + if (listener != NULL) + listener->PackageLinkDirectoryAdded(this); + // TODO: The notifications should only happen as necessary! } void -PackageLinkDirectory::RemovePackage(Package* package) +PackageLinkDirectory::RemovePackage(Package* package, + PackageLinksListener* listener) { - ASSERT(package->LinkDirectory() == this); + NodeWriteLocker writeLocker(this); + + if (listener != NULL) + listener->PackageLinkDirectoryRemoved(this); + package->SetLinkDirectory(NULL); fPackages.Remove(package); // TODO: Check whether that was the top priority package! + + if (listener != NULL && !IsEmpty()) + listener->PackageLinkDirectoryAdded(this); + // TODO: The notifications should only happen as necessary! } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h index 6b8841f340..8fbaf8fa4c 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h @@ -10,6 +10,9 @@ #include "Package.h" +class PackageLinksListener; + + class PackageLinkDirectory : public Directory { public: PackageLinkDirectory(); @@ -29,8 +32,10 @@ public: virtual status_t OpenAttribute(const char* name, int openMode, AttributeCookie*& _cookie); - void AddPackage(Package* package); - void RemovePackage(Package* package); + void AddPackage(Package* package, + PackageLinksListener* listener); + void RemovePackage(Package* package, + PackageLinksListener* listener); bool IsEmpty() const { return fPackages.IsEmpty(); } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp index c37182dec6..b787d1717d 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp @@ -11,12 +11,14 @@ #include "EmptyAttributeDirectoryCookie.h" #include "DebugSupport.h" #include "PackageLinkDirectory.h" +#include "PackageLinksListener.h" #include "Utils.h" PackageLinksDirectory::PackageLinksDirectory() : - Directory(0) + Directory(0), + fListener(NULL) // the ID needs to be assigned later, when added to a volume { get_real_time(fModifiedTime); @@ -111,18 +113,26 @@ PackageLinksDirectory::AddPackage(Package* package) // add the link directory NodeWriteLocker writeLocker(this); if (Node* child = FindChild(linkDirectory->Name())) { + // There already is an entry with the name. PackageLinkDirectory* otherLinkDirectory = dynamic_cast(child); if (otherLinkDirectory != NULL) RETURN_ERROR(B_BAD_VALUE); - linkDirectory->RemovePackage(package); + // There's already a package link directory. Delete the one we created + // and add the package to the pre-existing one. + linkDirectory->RemovePackage(package, NULL); linkDirectory = otherLinkDirectory; - linkDirectory->AddPackage(package); - } else + linkDirectory->AddPackage(package, fListener); + } else { + // No entry is in the way, so just add the link directory. AddChild(linkDirectory); -// TODO:... + if (fListener != NULL) { + NodeWriteLocker linkDirectoryWriteLocker(linkDirectory); + fListener->PackageLinkDirectoryAdded(linkDirectory); + } + } return B_OK; } @@ -140,12 +150,10 @@ PackageLinksDirectory::RemovePackage(Package* package) NodeWriteLocker writeLocker(this); - linkDirectory->RemovePackage(package); + linkDirectory->RemovePackage(package, fListener); // if empty, remove the link directory itself if (linkDirectory->IsEmpty()) RemoveChild(linkDirectory); - -// TODO:... } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h index c1659ee324..00cea75715 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h @@ -10,6 +10,7 @@ class Package; +class PackageLinksListener; class PackageLinksDirectory : public Directory { @@ -30,11 +31,15 @@ public: virtual status_t OpenAttribute(const char* name, int openMode, AttributeCookie*& _cookie); + void SetListener(PackageLinksListener* listener) + { fListener = listener; } + status_t AddPackage(Package* package); void RemovePackage(Package* package); private: timespec fModifiedTime; + PackageLinksListener* fListener; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.cpp new file mode 100644 index 0000000000..0849fc7968 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.cpp @@ -0,0 +1,13 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "PackageLinksListener.h" + + + +PackageLinksListener::~PackageLinksListener() +{ +} diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.h new file mode 100644 index 0000000000..e97bf752d1 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.h @@ -0,0 +1,23 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef PACKAGE_LINKS_LISTENER_H +#define PACKAGE_LINKS_LISTENER_H + + +class PackageLinkDirectory; + + +class PackageLinksListener { +public: + virtual ~PackageLinksListener(); + + virtual void PackageLinkDirectoryAdded( + PackageLinkDirectory* directory) = 0; + virtual void PackageLinkDirectoryRemoved( + PackageLinkDirectory* directory) = 0; +}; + + +#endif // PACKAGE_LINKS_LISTENER_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 6d14b6f330..332d72eb28 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -35,6 +35,7 @@ #include "PackageDirectory.h" #include "PackageFile.h" #include "PackageFSRoot.h" +#include "PackageLinkDirectory.h" #include "PackageLinksDirectory.h" #include "PackageSymlink.h" #include "Resolvable.h" @@ -619,6 +620,20 @@ Volume::AddPackageDomain(const char* path) } +void +Volume::PackageLinkDirectoryAdded(PackageLinkDirectory* directory) +{ + _AddPackageLinksNode(directory); +} + + +void +Volume::PackageLinkDirectoryRemoved(PackageLinkDirectory* directory) +{ + _RemovePackageLinksNode(directory); +} + + /*static*/ status_t Volume::_PackageLoaderEntry(void* data) { @@ -734,6 +749,7 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify) } // add the packages to the node tree + VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); VolumeWriteLocker volumeLocker(this); for (PackageFileNameHashTable::Iterator it = domain->Packages().GetIterator(); Package* package = it.Next();) { @@ -1216,6 +1232,7 @@ Volume::_DomainEntryCreated(PackageDomain* domain, dev_t deviceID, if (error != B_OK) return; + VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); VolumeWriteLocker volumeLocker(this); domain->AddPackage(package); @@ -1244,6 +1261,7 @@ Volume::_DomainEntryRemoved(PackageDomain* domain, dev_t deviceID, BReference packageReference(package); // remove the package + VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); VolumeWriteLocker volumeLocker(this); _RemovePackageContent(package, NULL, true); domain->RemovePackage(package); @@ -1388,12 +1406,12 @@ Volume::_AddPackageLinksDirectory() NodeWriteLocker rootDirectoryWriteLocker(fRootDirectory); NodeWriteLocker packageLinksDirectoryWriteLocker(packageLinksDirectory); - packageLinksDirectory->SetID(fNextNodeID++); packageLinksDirectory->SetParent(fRootDirectory); - fRootDirectory->AddChild(packageLinksDirectory); - fNodes.Insert(packageLinksDirectory); - packageLinksDirectory->AcquireReference(); + + _AddPackageLinksNode(packageLinksDirectory); + + packageLinksDirectory->SetListener(this); return B_OK; } @@ -1410,7 +1428,54 @@ Volume::_RemovePackageLinksDirectory() NodeWriteLocker packageLinksDirectoryWriteLocker(packageLinksDirectory); if (packageLinksDirectory->Parent() == fRootDirectory) { - _RemoveNode(packageLinksDirectory); + packageLinksDirectory->SetListener(NULL); + _RemovePackageLinksNode(packageLinksDirectory); packageLinksDirectory->SetParent(NULL); } } + + +void +Volume::_AddPackageLinksNode(Node* node) +{ + node->SetID(fNextNodeID++); + + fNodes.Insert(node); + node->AcquireReference(); + + // If this is a directory, recursively add descendants. The directory tree + // for the package links isn't deep, so we can do recursion. + if (Directory* directory = dynamic_cast(node)) { + for (Node* child = directory->FirstChild(); child != NULL; + child = directory->NextChild(child)) { + NodeWriteLocker childWriteLocker(child); + _AddPackageLinksNode(child); + } + } +} + + +void +Volume::_RemovePackageLinksNode(Node* node) +{ + // If this is a directory, recursively remove descendants. The directory + // tree for the package links isn't deep, so we can do recursion. + if (Directory* directory = dynamic_cast(node)) { + for (Node* child = directory->FirstChild(); child != NULL; + child = directory->NextChild(child)) { + NodeWriteLocker childWriteLocker(child); + _RemovePackageLinksNode(child); + } + } + + _RemoveNode(node); +} + + +inline Volume* +Volume::_SystemVolumeIfNotSelf() const +{ + if (Volume* systemVolume = fPackageFSRoot->SystemVolume()) + return systemVolume == this ? NULL : systemVolume; + return NULL; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h index 7dc209f4af..f516f0fb44 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h @@ -16,6 +16,7 @@ #include "Node.h" #include "PackageDomain.h" +#include "PackageLinksListener.h" class Directory; @@ -32,7 +33,8 @@ enum MountType { }; -class Volume : public DoublyLinkedListLinkImpl { +class Volume : public DoublyLinkedListLinkImpl, + private PackageLinksListener { public: Volume(fs_volume* fsVolume); ~Volume(); @@ -72,6 +74,13 @@ public: status_t AddPackageDomain(const char* path); +private: + // PackageLinksListener + virtual void PackageLinkDirectoryAdded( + PackageLinkDirectory* directory); + virtual void PackageLinkDirectoryRemoved( + PackageLinkDirectory* directory); + private: struct Job; struct AddPackageDomainJob; @@ -147,6 +156,10 @@ private: status_t _AddPackageLinksDirectory(); void _RemovePackageLinksDirectory(); + void _AddPackageLinksNode(Node* node); + void _RemovePackageLinksNode(Node* node); + + inline Volume* _SystemVolumeIfNotSelf() const; private: mutable rw_lock fLock; From 1becdcc7c8711d12d309527c6c449b18c4765788 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 11:30:32 +0200 Subject: [PATCH 0094/1170] Empty Node::VFS{Init(),Uninit}() implementations --- .../kernel/file_systems/packagefs/Directory.cpp | 13 ------------- .../kernel/file_systems/packagefs/Directory.h | 3 --- src/add-ons/kernel/file_systems/packagefs/Node.cpp | 13 +++++++++++++ src/add-ons/kernel/file_systems/packagefs/Node.h | 4 ++-- 4 files changed, 15 insertions(+), 18 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp index 0e773888fe..20d36a31d2 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp @@ -41,19 +41,6 @@ Directory::Init(Directory* parent, const char* name) } -status_t -Directory::VFSInit(dev_t deviceID) -{ - return B_OK; -} - - -void -Directory::VFSUninit() -{ -} - - status_t Directory::Read(off_t offset, void* buffer, size_t* bufferSize) { diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.h b/src/add-ons/kernel/file_systems/packagefs/Directory.h index e4909c8568..1b30aad3b0 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.h +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.h @@ -29,9 +29,6 @@ public: virtual status_t Init(Directory* parent, const char* name); - virtual status_t VFSInit(dev_t deviceID); - virtual void VFSUninit(); - virtual status_t Read(off_t offset, void* buffer, size_t* bufferSize); virtual status_t Read(io_request* request); diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.cpp b/src/add-ons/kernel/file_systems/packagefs/Node.cpp index 7f79d62c6c..d685b93e8f 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Node.cpp @@ -42,6 +42,19 @@ Node::Init(Directory* parent, const char* name) } +status_t +Node::VFSInit(dev_t deviceID) +{ + return B_OK; +} + + +void +Node::VFSUninit() +{ +} + + void Node::SetID(ino_t id) { diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h index d192122ab0..80535aa928 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.h +++ b/src/add-ons/kernel/file_systems/packagefs/Node.h @@ -44,8 +44,8 @@ public: virtual status_t Init(Directory* parent, const char* name); - virtual status_t VFSInit(dev_t deviceID) = 0; - virtual void VFSUninit() = 0; + virtual status_t VFSInit(dev_t deviceID); + virtual void VFSUninit(); void SetID(ino_t id); void SetParent(Directory* parent); From 70c2780c73be60a9c2f23f722815966edca6ee3a Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 12:13:45 +0200 Subject: [PATCH 0095/1170] PackageLinksDirectory::AddPackage(): Fix check --- .../kernel/file_systems/packagefs/PackageLinksDirectory.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp index b787d1717d..56a0514eca 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp @@ -116,7 +116,7 @@ PackageLinksDirectory::AddPackage(Package* package) // There already is an entry with the name. PackageLinkDirectory* otherLinkDirectory = dynamic_cast(child); - if (otherLinkDirectory != NULL) + if (otherLinkDirectory == NULL) RETURN_ERROR(B_BAD_VALUE); // There's already a package link directory. Delete the one we created From 1d8edd93e23d4450560e5c74c568172d70502344 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 12:15:20 +0200 Subject: [PATCH 0096/1170] Create self package link --- .../packagefs/PackageLinkDirectory.cpp | 138 +++++++++++++++++- .../packagefs/PackageLinkDirectory.h | 4 + 2 files changed, 141 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp index eb9879ee72..15701f0866 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp @@ -6,6 +6,9 @@ #include "PackageLinkDirectory.h" +#include +#include + #include #include "EmptyAttributeDirectoryCookie.h" @@ -13,6 +16,126 @@ #include "PackageLinksListener.h" #include "Utils.h" #include "Version.h" +#include "Volume.h" + + +static const char* const kSelfLinkName = ".self"; +static const char* const kSystemLinkPath = "../.."; +static const char* const kCommonLinkPath = "../../../common"; +static const char* const kHomeLinkPath = "../../../home/config"; + + +static const char* +link_path_for_mount_type(MountType type) +{ + switch (type) { + case MOUNT_TYPE_SYSTEM: + return kSystemLinkPath; + case MOUNT_TYPE_COMMON: + return kCommonLinkPath; + case MOUNT_TYPE_HOME: + return kHomeLinkPath; + case MOUNT_TYPE_CUSTOM: + default: + return "?"; + } +} + + +// #pragma mark - SelfLink + + +class PackageLinkDirectory::SelfLink : public Node { +public: + SelfLink(Package* package) + : + Node(0), + fPackage(package), + fLinkPath(link_path_for_mount_type( + package->Domain()->Volume()->MountType())) + { + get_real_time(fModifiedTime); + } + + virtual ~SelfLink() + { + } + + virtual status_t Init(Directory* parent, const char* name) + { + return Node::Init(parent, name); + } + + virtual mode_t Mode() const + { + return S_IFLNK | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH + | S_IXOTH; + } + + virtual uid_t UserID() const + { + return 0; + } + + virtual gid_t GroupID() const + { + return 0; + } + + virtual timespec ModifiedTime() const + { + return fModifiedTime; + } + + virtual off_t FileSize() const + { + return strlen(fLinkPath); + } + + virtual status_t Read(off_t offset, void* buffer, size_t* bufferSize) + { + return B_BAD_VALUE; + } + + virtual status_t Read(io_request* request) + { + return B_BAD_VALUE; + } + + virtual status_t ReadSymlink(void* buffer, size_t* bufferSize) + { + size_t toCopy = std::min(strlen(fLinkPath), *bufferSize); + memcpy(buffer, fLinkPath, toCopy); + *bufferSize = toCopy; + + return B_OK; + } + + virtual status_t OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) + { + AttributeDirectoryCookie* cookie + = new(std::nothrow) EmptyAttributeDirectoryCookie; + if (cookie == NULL) + return B_NO_MEMORY; + + _cookie = cookie; + return B_OK; + } + + virtual status_t OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie) + { + return B_ENTRY_NOT_FOUND; + } + +private: + Package* fPackage; + timespec fModifiedTime; + const char* fLinkPath; +}; + + +// #pragma mark - PackageLinkDirectory PackageLinkDirectory::PackageLinkDirectory() @@ -26,12 +149,25 @@ PackageLinkDirectory::PackageLinkDirectory() PackageLinkDirectory::~PackageLinkDirectory() { + if (fSelfLink != NULL) + fSelfLink->ReleaseReference(); } status_t PackageLinkDirectory::Init(Directory* parent, Package* package) { + // create the self link + fSelfLink = new(std::nothrow) SelfLink(package); + if (fSelfLink == NULL) + return B_NO_MEMORY; + + status_t error = fSelfLink->Init(this, kSelfLinkName); + if (error != B_OK) + RETURN_ERROR(error); + + AddChild(fSelfLink); + // compute the allocation size needed for the versioned name size_t nameLength = strlen(package->Name()); size_t size = nameLength + 1; @@ -55,7 +191,7 @@ PackageLinkDirectory::Init(Directory* parent, Package* package) } // init the directory/node - status_t error = Init(parent, name); + error = Init(parent, name); // TODO: This copies the name unnecessarily! if (error != B_OK) RETURN_ERROR(error); diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h index 8fbaf8fa4c..b5fa320038 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h @@ -40,9 +40,13 @@ public: bool IsEmpty() const { return fPackages.IsEmpty(); } +private: + class SelfLink; + private: timespec fModifiedTime; PackageList fPackages; + SelfLink* fSelfLink; }; From 724fba1b0961158926033c3bf531f92483573590 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 12:42:16 +0200 Subject: [PATCH 0097/1170] Add Node::Init() flags parameter * Add Node::Init() flags: - NODE_FLAG_KEEP_NAME: Take over ownership of the name. - NODE_FLAG_CONST_NAME: Don't copy the name -- it's a constant that lives at least as long as the object. * Remove Init() implementations in derived classes that just call the base class version. --- .../file_systems/packagefs/Directory.cpp | 6 ++--- .../kernel/file_systems/packagefs/Directory.h | 3 ++- .../kernel/file_systems/packagefs/Node.cpp | 24 +++++++++++++------ .../kernel/file_systems/packagefs/Node.h | 18 +++++++++++++- .../file_systems/packagefs/PackageFSRoot.cpp | 2 +- .../packagefs/PackageLinkDirectory.cpp | 15 ++++-------- .../packagefs/PackageLinkDirectory.h | 3 ++- .../packagefs/PackageLinksDirectory.cpp | 7 ------ .../packagefs/PackageLinksDirectory.h | 2 -- .../packagefs/UnpackingDirectory.cpp | 7 ------ .../packagefs/UnpackingDirectory.h | 2 -- .../packagefs/UnpackingLeafNode.cpp | 7 ------ .../packagefs/UnpackingLeafNode.h | 2 -- .../kernel/file_systems/packagefs/Volume.cpp | 5 ++-- 14 files changed, 49 insertions(+), 54 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp index 20d36a31d2..c073dc06ba 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp @@ -31,13 +31,13 @@ Directory::~Directory() status_t -Directory::Init(Directory* parent, const char* name) +Directory::Init(Directory* parent, const char* name, uint32 flags) { - status_t error = fChildTable.Init(); + status_t error = Node::Init(parent, name, flags); if (error != B_OK) return error; - return Node::Init(parent, name); + return fChildTable.Init(); } diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.h b/src/add-ons/kernel/file_systems/packagefs/Directory.h index 1b30aad3b0..3dc604cd37 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Directory.h +++ b/src/add-ons/kernel/file_systems/packagefs/Directory.h @@ -27,7 +27,8 @@ public: Directory(ino_t id); virtual ~Directory(); - virtual status_t Init(Directory* parent, const char* name); + virtual status_t Init(Directory* parent, const char* name, + uint32 flags); virtual status_t Read(off_t offset, void* buffer, size_t* bufferSize); diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.cpp b/src/add-ons/kernel/file_systems/packagefs/Node.cpp index d685b93e8f..2ed70e2669 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Node.cpp @@ -16,7 +16,8 @@ Node::Node(ino_t id) : fID(id), fParent(NULL), - fName(NULL) + fName(NULL), + fFlags(0) { rw_lock_init(&fLock, "packagefs node"); } @@ -24,19 +25,28 @@ Node::Node(ino_t id) Node::~Node() { -PRINT("%p->Node::~Node()\n", this); - free(fName); + if ((fFlags & NODE_FLAG_OWNS_NAME) != 0) + free(fName); + rw_lock_destroy(&fLock); } status_t -Node::Init(Directory* parent, const char* name) +Node::Init(Directory* parent, const char* name, uint32 flags) { fParent = parent; - fName = strdup(name); - if (fName == NULL) - RETURN_ERROR(B_NO_MEMORY); + fFlags = flags; + + if ((flags & NODE_FLAG_CONST_NAME) != 0 + || (flags & NODE_FLAG_KEEP_NAME) != 0) { + fName = const_cast(name); + } else { + fName = strdup(name); + if (fName == NULL) + RETURN_ERROR(B_NO_MEMORY); + fFlags |= NODE_FLAG_OWNS_NAME; + } return B_OK; } diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h index 80535aa928..33ba885b48 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.h +++ b/src/add-ons/kernel/file_systems/packagefs/Node.h @@ -23,6 +23,18 @@ class Directory; class PackageNode; +// node flags +enum { + NODE_FLAG_KEEP_NAME = 0x01, + // Init(): Take over ownership of the given name (i.e. free in + // destructor). + NODE_FLAG_CONST_NAME = 0x02, + // Init(): The given name is a constant that won't go away during the + // lifetime of the object. No need to copy. + NODE_FLAG_OWNS_NAME = NODE_FLAG_CONST_NAME +}; + + class Node : public BReferenceable, public DoublyLinkedListLinkImpl { public: Node(ino_t id); @@ -42,7 +54,10 @@ public: Node*& IDHashTableNext() { return fIDHashTableNext; } - virtual status_t Init(Directory* parent, const char* name); + virtual status_t Init(Directory* parent, const char* name, + uint32 flags); + // If specified to keep the name, it does + // so also on error. virtual status_t VFSInit(dev_t deviceID); virtual void VFSUninit(); @@ -75,6 +90,7 @@ protected: char* fName; Node* fNameHashTableNext; Node* fIDHashTableNext; + uint32 fFlags; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp index 6684de86d8..aa4dcb8bae 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp @@ -60,7 +60,7 @@ PackageFSRoot::Init() return B_NO_MEMORY; status_t error = fPackageLinksDirectory->Init(NULL, - kPackageLinksDirectoryName); + kPackageLinksDirectoryName, 0); if (error != B_OK) RETURN_ERROR(error); diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp index 15701f0866..0c1aae5ed4 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp @@ -61,11 +61,6 @@ public: { } - virtual status_t Init(Directory* parent, const char* name) - { - return Node::Init(parent, name); - } - virtual mode_t Mode() const { return S_IFLNK | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH @@ -162,7 +157,7 @@ PackageLinkDirectory::Init(Directory* parent, Package* package) if (fSelfLink == NULL) return B_NO_MEMORY; - status_t error = fSelfLink->Init(this, kSelfLinkName); + status_t error = fSelfLink->Init(this, kSelfLinkName, NODE_FLAG_CONST_NAME); if (error != B_OK) RETURN_ERROR(error); @@ -182,7 +177,6 @@ PackageLinkDirectory::Init(Directory* parent, Package* package) char* name = (char*)malloc(size); if (name == NULL) return B_NO_MEMORY; - MemoryDeleter nameDeleter(name); memcpy(name, package->Name(), nameLength + 1); if (version != NULL) { @@ -191,8 +185,7 @@ PackageLinkDirectory::Init(Directory* parent, Package* package) } // init the directory/node - error = Init(parent, name); - // TODO: This copies the name unnecessarily! + error = Init(parent, name, NODE_FLAG_KEEP_NAME); if (error != B_OK) RETURN_ERROR(error); @@ -204,9 +197,9 @@ PackageLinkDirectory::Init(Directory* parent, Package* package) status_t -PackageLinkDirectory::Init(Directory* parent, const char* name) +PackageLinkDirectory::Init(Directory* parent, const char* name, uint32 flags) { - return Directory::Init(parent, name); + return Directory::Init(parent, name, flags); } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h index b5fa320038..b32c07a6e7 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h @@ -19,7 +19,8 @@ public: virtual ~PackageLinkDirectory(); status_t Init(Directory* parent, Package* package); - virtual status_t Init(Directory* parent, const char* name); + virtual status_t Init(Directory* parent, const char* name, + uint32 flags); virtual mode_t Mode() const; virtual uid_t UserID() const; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp index 56a0514eca..d7cd7f6d8b 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp @@ -30,13 +30,6 @@ PackageLinksDirectory::~PackageLinksDirectory() } -status_t -PackageLinksDirectory::Init(Directory* parent, const char* name) -{ - return Directory::Init(parent, name); -} - - mode_t PackageLinksDirectory::Mode() const { diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h index 00cea75715..4d5e3f1d0c 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h @@ -18,8 +18,6 @@ public: PackageLinksDirectory(); virtual ~PackageLinksDirectory(); - virtual status_t Init(Directory* parent, const char* name); - virtual mode_t Mode() const; virtual uid_t UserID() const; virtual gid_t GroupID() const; diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp index 9d6046edaf..dad396e1e9 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp @@ -27,13 +27,6 @@ UnpackingDirectory::~UnpackingDirectory() } -status_t -UnpackingDirectory::Init(Directory* parent, const char* name) -{ - return Directory::Init(parent, name); -} - - mode_t UnpackingDirectory::Mode() const { diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h index 79fcd8f5dc..ce2b4a8578 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h @@ -16,8 +16,6 @@ public: UnpackingDirectory(ino_t id); virtual ~UnpackingDirectory(); - virtual status_t Init(Directory* parent, const char* name); - virtual mode_t Mode() const; virtual uid_t UserID() const; virtual gid_t GroupID() const; diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp index a1af6c0c3a..6504ac718a 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp @@ -27,13 +27,6 @@ UnpackingLeafNode::~UnpackingLeafNode() } -status_t -UnpackingLeafNode::Init(Directory* parent, const char* name) -{ - return Node::Init(parent, name); -} - - status_t UnpackingLeafNode::VFSInit(dev_t deviceID) { diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h index a933bb98e9..3ebffbd28b 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h @@ -16,8 +16,6 @@ public: UnpackingLeafNode(ino_t id); virtual ~UnpackingLeafNode(); - virtual status_t Init(Directory* parent, const char* name); - virtual status_t VFSInit(dev_t deviceID); virtual void VFSUninit(); diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 332d72eb28..5cfb0bf107 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -511,7 +511,8 @@ Volume::Mount(const char* parameterString) = new(std::nothrow) ::RootDirectory(kRootDirectoryID, st.st_mtim); if (fRootDirectory == NULL) RETURN_ERROR(B_NO_MEMORY); - fRootDirectory->Init(NULL, volumeName != NULL ? volumeName : "Package FS"); + fRootDirectory->Init(NULL, volumeName != NULL ? volumeName : "Package FS", + 0); fNodes.Insert(fRootDirectory); // get our mount point @@ -1101,7 +1102,7 @@ Volume::_CreateUnpackingNode(mode_t mode, Directory* parent, const char* name, Node* node = unpackingNode->GetNode(); BReference nodeReference(node, true); - status_t error = node->Init(parent, name); + status_t error = node->Init(parent, name, 0); if (error != B_OK) RETURN_ERROR(error); From 1382ade575e55b4bd819bb2b60f8dd1999d55758 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 12:47:15 +0200 Subject: [PATCH 0098/1170] If none is given pick volume name by mount type --- .../kernel/file_systems/packagefs/Volume.cpp | 21 +++++++++++++++++-- 1 file changed, 19 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 5cfb0bf107..1080f28568 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -506,13 +506,30 @@ Volume::Mount(const char* parameterString) if (stat(packages, &st) < 0) RETURN_ERROR(B_ERROR); + // If no volume name is given, infer it from the mount type. + if (volumeName == NULL) { + switch (fMountType) { + case MOUNT_TYPE_SYSTEM: + volumeName = "system"; + break; + case MOUNT_TYPE_COMMON: + volumeName = "common"; + break; + case MOUNT_TYPE_HOME: + volumeName = "home"; + break; + case MOUNT_TYPE_CUSTOM: + volumeName = "Package FS"; + break; + } + } + // create the root node fRootDirectory = new(std::nothrow) ::RootDirectory(kRootDirectoryID, st.st_mtim); if (fRootDirectory == NULL) RETURN_ERROR(B_NO_MEMORY); - fRootDirectory->Init(NULL, volumeName != NULL ? volumeName : "Package FS", - 0); + fRootDirectory->Init(NULL, volumeName, 0); fNodes.Insert(fRootDirectory); // get our mount point From fc009a29f39d2556096fb3f28536cb53d7c7bdbf Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 13:18:55 +0200 Subject: [PATCH 0099/1170] Fix NODE_FLAG_OWNS_NAME value --- src/add-ons/kernel/file_systems/packagefs/Node.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h index 33ba885b48..fce665329e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Node.h +++ b/src/add-ons/kernel/file_systems/packagefs/Node.h @@ -31,7 +31,7 @@ enum { NODE_FLAG_CONST_NAME = 0x02, // Init(): The given name is a constant that won't go away during the // lifetime of the object. No need to copy. - NODE_FLAG_OWNS_NAME = NODE_FLAG_CONST_NAME + NODE_FLAG_OWNS_NAME = NODE_FLAG_KEEP_NAME }; From 5f80e51a9ea6c2bdc5c1db46bb55c55d0f8f9418 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 13:26:34 +0200 Subject: [PATCH 0100/1170] Fix Volume::_RemovePackageLinksNode() Don't use _RemoveNode() as it also removes the node from its parent. --- src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 1080f28568..3808fe7292 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -1486,7 +1486,8 @@ Volume::_RemovePackageLinksNode(Node* node) } } - _RemoveNode(node); + fNodes.Remove(node); + node->ReleaseReference(); } From 77574d40ee12142c4c9572143f3a4ebbe9b896ee Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 13:30:08 +0200 Subject: [PATCH 0101/1170] Init fSelfLink --- .../kernel/file_systems/packagefs/PackageLinkDirectory.cpp | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp index 0c1aae5ed4..4af01851e7 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp @@ -135,8 +135,9 @@ private: PackageLinkDirectory::PackageLinkDirectory() : - Directory(0) + Directory(0), // the ID needs to be assigned later, when added to a volume + fSelfLink(NULL) { get_real_time(fModifiedTime); } From 59acdf5045470885e5a17d4db4380915c9047a56 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 13:31:21 +0200 Subject: [PATCH 0102/1170] Volume: Remove all package contents on destruction --- .../kernel/file_systems/packagefs/Volume.cpp | 21 +++++++++++++++++-- .../kernel/file_systems/packagefs/Volume.h | 1 + 2 files changed, 20 insertions(+), 2 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 3808fe7292..7b4358c057 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -438,8 +438,8 @@ Volume::~Volume() { _TerminatePackageLoader(); - while (PackageDomain* packageDomain = fPackageDomains.RemoveHead()) - packageDomain->ReleaseReference(); + while (PackageDomain* packageDomain = fPackageDomains.Head()) + _RemovePackageDomain(packageDomain); // remove all nodes from the ID hash table Node* node = fNodes.Clear(true); @@ -638,6 +638,23 @@ Volume::AddPackageDomain(const char* path) } +void +Volume::_RemovePackageDomain(PackageDomain* domain) +{ + // remove the domain's packages from the node tree + VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); + VolumeWriteLocker volumeLocker(this); + for (PackageFileNameHashTable::Iterator it + = domain->Packages().GetIterator(); Package* package = it.Next();) { + _RemovePackageContent(package, NULL, false); + } + + // remove the domain + fPackageDomains.Remove(domain); + domain->ReleaseReference(); +} + + void Volume::PackageLinkDirectoryAdded(PackageLinkDirectory* directory) { diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h index f516f0fb44..311a2c1f08 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h @@ -107,6 +107,7 @@ private: status_t _AddInitialPackageDomain(const char* path); status_t _AddPackageDomain(PackageDomain* domain, bool notify); + void _RemovePackageDomain(PackageDomain* domain); status_t _LoadPackage(Package* package); status_t _AddPackageContent(Package* package, From fd6d5d5a51e055e88176262b2ef26097653b442c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 13:33:24 +0200 Subject: [PATCH 0103/1170] Reordered methods to match declaration order --- .../kernel/file_systems/packagefs/Volume.cpp | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 7b4358c057..809bbb310a 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -638,23 +638,6 @@ Volume::AddPackageDomain(const char* path) } -void -Volume::_RemovePackageDomain(PackageDomain* domain) -{ - // remove the domain's packages from the node tree - VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); - VolumeWriteLocker volumeLocker(this); - for (PackageFileNameHashTable::Iterator it - = domain->Packages().GetIterator(); Package* package = it.Next();) { - _RemovePackageContent(package, NULL, false); - } - - // remove the domain - fPackageDomains.Remove(domain); - domain->ReleaseReference(); -} - - void Volume::PackageLinkDirectoryAdded(PackageLinkDirectory* directory) { @@ -806,6 +789,23 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify) } +void +Volume::_RemovePackageDomain(PackageDomain* domain) +{ + // remove the domain's packages from the node tree + VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf()); + VolumeWriteLocker volumeLocker(this); + for (PackageFileNameHashTable::Iterator it + = domain->Packages().GetIterator(); Package* package = it.Next();) { + _RemovePackageContent(package, NULL, false); + } + + // remove the domain + fPackageDomains.Remove(domain); + domain->ReleaseReference(); +} + + status_t Volume::_LoadPackage(Package* package) { From 83d5997db5b40b1eced3b99e29f83f5be8000d24 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 24 Jun 2011 13:36:49 +0200 Subject: [PATCH 0104/1170] Add node monitoring for package link directories --- src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 6 ++++++ 1 file changed, 6 insertions(+) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 809bbb310a..b2cb66ba17 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -642,6 +642,9 @@ void Volume::PackageLinkDirectoryAdded(PackageLinkDirectory* directory) { _AddPackageLinksNode(directory); + + notify_entry_created(ID(), directory->Parent()->ID(), directory->Name(), + directory->ID()); } @@ -649,6 +652,9 @@ void Volume::PackageLinkDirectoryRemoved(PackageLinkDirectory* directory) { _RemovePackageLinksNode(directory); + + notify_entry_removed(ID(), directory->Parent()->ID(), directory->Name(), + directory->ID()); } From 35eeebddc470b92183aaadaf3e791ccfc63b55fc Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 01:59:46 +0200 Subject: [PATCH 0105/1170] Missing locking when adding/removing package nodes --- src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index b2cb66ba17..6ea71622bc 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -1029,6 +1029,7 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode, } BReference nodeReference(node); + NodeWriteLocker nodeWriteLocker(node); status_t error = unpackingNode->AddPackageNode(packageNode); if (error != B_OK) { @@ -1075,6 +1076,7 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode, return; BReference nodeReference(node); + NodeWriteLocker nodeWriteLocker(node); PackageNode* headPackageNode = unpackingNode->GetPackageNode(); unpackingNode->RemovePackageNode(packageNode); From cd81fea02d586348a71c12d152bf65751984be4f Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 02:32:32 +0200 Subject: [PATCH 0106/1170] Fix package link updates/node monitoring * PackageLinksListener: Rename methods from *Directory*() to *Node*() and change parameter to Node*. Also add a *Changed() method. * PackageLinkDirectory: Update only when necessary and what is necessary (currently only the self link). --- .../packagefs/PackageLinkDirectory.cpp | 109 +++++++++++++----- .../packagefs/PackageLinkDirectory.h | 3 + .../packagefs/PackageLinksDirectory.cpp | 2 +- .../packagefs/PackageLinksListener.h | 13 ++- .../kernel/file_systems/packagefs/Volume.cpp | 21 ++-- .../kernel/file_systems/packagefs/Volume.h | 8 +- 6 files changed, 107 insertions(+), 49 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp index 4af01851e7..ee4ba52ef1 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include #include "EmptyAttributeDirectoryCookie.h" @@ -49,18 +51,22 @@ class PackageLinkDirectory::SelfLink : public Node { public: SelfLink(Package* package) : - Node(0), - fPackage(package), - fLinkPath(link_path_for_mount_type( - package->Domain()->Volume()->MountType())) + Node(0) { - get_real_time(fModifiedTime); + Update(package); } virtual ~SelfLink() { } + void Update(Package* package) + { + fLinkPath = link_path_for_mount_type( + package->Domain()->Volume()->MountType()); + get_real_time(fModifiedTime); + } + virtual mode_t Mode() const { return S_IFLNK | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH @@ -124,7 +130,6 @@ public: } private: - Package* fPackage; timespec fModifiedTime; const char* fLinkPath; }; @@ -153,17 +158,6 @@ PackageLinkDirectory::~PackageLinkDirectory() status_t PackageLinkDirectory::Init(Directory* parent, Package* package) { - // create the self link - fSelfLink = new(std::nothrow) SelfLink(package); - if (fSelfLink == NULL) - return B_NO_MEMORY; - - status_t error = fSelfLink->Init(this, kSelfLinkName, NODE_FLAG_CONST_NAME); - if (error != B_OK) - RETURN_ERROR(error); - - AddChild(fSelfLink); - // compute the allocation size needed for the versioned name size_t nameLength = strlen(package->Name()); size_t size = nameLength + 1; @@ -186,7 +180,7 @@ PackageLinkDirectory::Init(Directory* parent, Package* package) } // init the directory/node - error = Init(parent, name, NODE_FLAG_KEEP_NAME); + status_t error = Init(parent, name, NODE_FLAG_KEEP_NAME); if (error != B_OK) RETURN_ERROR(error); @@ -267,16 +261,21 @@ PackageLinkDirectory::AddPackage(Package* package, { NodeWriteLocker writeLocker(this); - if (listener != NULL) - listener->PackageLinkDirectoryRemoved(this); + // Find the insertion point in the list. We sort by mount type -- the more + // specific the higher the priority. + MountType mountType = package->Domain()->Volume()->MountType(); + Package* otherPackage = NULL; + for (PackageList::Iterator it = fPackages.GetIterator(); + (otherPackage = it.Next()) != NULL;) { + if (otherPackage->Domain()->Volume()->MountType() <= mountType) + break; + } - // TODO: Add in priority order! - fPackages.Add(package); + fPackages.InsertBefore(otherPackage, package); package->SetLinkDirectory(this); - if (listener != NULL) - listener->PackageLinkDirectoryAdded(this); - // TODO: The notifications should only happen as necessary! + if (package == fPackages.Head()) + _Update(listener); } @@ -288,14 +287,62 @@ PackageLinkDirectory::RemovePackage(Package* package, NodeWriteLocker writeLocker(this); - if (listener != NULL) - listener->PackageLinkDirectoryRemoved(this); + bool firstPackage = package == fPackages.Head(); package->SetLinkDirectory(NULL); fPackages.Remove(package); - // TODO: Check whether that was the top priority package! - if (listener != NULL && !IsEmpty()) - listener->PackageLinkDirectoryAdded(this); - // TODO: The notifications should only happen as necessary! + if (firstPackage) + _Update(listener); +} + + +status_t +PackageLinkDirectory::_Update(PackageLinksListener* listener) +{ + // check, if empty + Package* package = fPackages.Head(); + if (package == NULL) { + // remove self link, if any + if (fSelfLink != NULL) { + NodeWriteLocker selfLinkLocker(fSelfLink); + if (listener != NULL) + listener->PackageLinkNodeRemoved(fSelfLink); + + RemoveChild(fSelfLink); + fSelfLink->ReleaseReference(); + fSelfLink = NULL; + } + + return B_OK; + } + + // create/update self link + if (fSelfLink == NULL) { + fSelfLink = new(std::nothrow) SelfLink(package); + if (fSelfLink == NULL) + return B_NO_MEMORY; + + status_t error = fSelfLink->Init(this, kSelfLinkName, + NODE_FLAG_CONST_NAME); + if (error != B_OK) + RETURN_ERROR(error); + + AddChild(fSelfLink); + + if (listener != NULL) { + NodeWriteLocker selfLinkLocker(fSelfLink); + listener->PackageLinkNodeAdded(fSelfLink); + } + } else { + NodeWriteLocker selfLinkLocker(fSelfLink); + fSelfLink->Update(package); + + if (listener != NULL) { + listener->PackageLinkNodeChanged(fSelfLink, + B_STAT_SIZE | B_STAT_MODIFICATION_TIME); + } + } + + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h index b32c07a6e7..ee87220167 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h @@ -44,6 +44,9 @@ public: private: class SelfLink; +private: + status_t _Update(PackageLinksListener* listener); + private: timespec fModifiedTime; PackageList fPackages; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp index d7cd7f6d8b..848eb5af91 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp @@ -123,7 +123,7 @@ PackageLinksDirectory::AddPackage(Package* package) if (fListener != NULL) { NodeWriteLocker linkDirectoryWriteLocker(linkDirectory); - fListener->PackageLinkDirectoryAdded(linkDirectory); + fListener->PackageLinkNodeAdded(linkDirectory); } } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.h index e97bf752d1..4d3e7644ed 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.h @@ -6,17 +6,20 @@ #define PACKAGE_LINKS_LISTENER_H -class PackageLinkDirectory; +#include + + +class Node; class PackageLinksListener { public: virtual ~PackageLinksListener(); - virtual void PackageLinkDirectoryAdded( - PackageLinkDirectory* directory) = 0; - virtual void PackageLinkDirectoryRemoved( - PackageLinkDirectory* directory) = 0; + virtual void PackageLinkNodeAdded(Node* node) = 0; + virtual void PackageLinkNodeRemoved(Node* node) = 0; + virtual void PackageLinkNodeChanged(Node* node, + uint32 statFields) = 0; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 6ea71622bc..3ed87091ab 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -639,22 +639,27 @@ Volume::AddPackageDomain(const char* path) void -Volume::PackageLinkDirectoryAdded(PackageLinkDirectory* directory) +Volume::PackageLinkNodeAdded(Node* node) { - _AddPackageLinksNode(directory); + _AddPackageLinksNode(node); - notify_entry_created(ID(), directory->Parent()->ID(), directory->Name(), - directory->ID()); + notify_entry_created(ID(), node->Parent()->ID(), node->Name(), node->ID()); } void -Volume::PackageLinkDirectoryRemoved(PackageLinkDirectory* directory) +Volume::PackageLinkNodeRemoved(Node* node) { - _RemovePackageLinksNode(directory); + _RemovePackageLinksNode(node); - notify_entry_removed(ID(), directory->Parent()->ID(), directory->Name(), - directory->ID()); + notify_entry_removed(ID(), node->Parent()->ID(), node->Name(), node->ID()); +} + + +void +Volume::PackageLinkNodeChanged(Node* node, uint32 statFields) +{ + notify_stat_changed(ID(), node->ID(), statFields); } diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h index 311a2c1f08..c293aab9ed 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.h +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h @@ -76,10 +76,10 @@ public: private: // PackageLinksListener - virtual void PackageLinkDirectoryAdded( - PackageLinkDirectory* directory); - virtual void PackageLinkDirectoryRemoved( - PackageLinkDirectory* directory); + virtual void PackageLinkNodeAdded(Node* node); + virtual void PackageLinkNodeRemoved(Node* node); + virtual void PackageLinkNodeChanged(Node* node, + uint32 statFields); private: struct Job; From 38a7f76509ef229e8ebcabce002ee6fe5a13a5ca Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 03:02:46 +0200 Subject: [PATCH 0107/1170] Add TODOs regarding broken add/remove behavior --- src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 3ed87091ab..cbbfa1470f 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -1033,6 +1033,13 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode, newNode = true; } + // TODO: The non-new part is broken for files. If a node is already known to + // the VFS, we can't just change the file content. The file might be an + // executable or library that is currently in use (i.e. mapped) and when + // just changing the file content we break things horribly. In fact we don't + // even do that correctly in UnpackingLeafNode::AddPackageNode() -- neither + // the former nor the new head package node is notified. + BReference nodeReference(node); NodeWriteLocker nodeWriteLocker(node); @@ -1083,6 +1090,9 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode, BReference nodeReference(node); NodeWriteLocker nodeWriteLocker(node); + // TODO: This is broken for files that are in use. Cf. _AddPackageNode() for + // details. + PackageNode* headPackageNode = unpackingNode->GetPackageNode(); unpackingNode->RemovePackageNode(packageNode); From 9320567ed2407276a14f86ec44fbe088b13e8e1f Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 16:39:05 +0200 Subject: [PATCH 0108/1170] WIP towards dependency package links * Add ResolvableFamily and DependencyFamily classes for grouping equally named resolvables/dependencies. * Add hash tables to PackageFSRoot to track resolvables and dependencies. That is done in {Add,Remove}Package. * Resolvable does now have a list of Dependency objects, the ones it satisfies. --- .../file_systems/packagefs/Dependency.cpp | 1 + .../file_systems/packagefs/Dependency.h | 21 ++++ .../file_systems/packagefs/DependencyFamily.h | 97 +++++++++++++++ .../kernel/file_systems/packagefs/Jamfile | 1 + .../kernel/file_systems/packagefs/Package.h | 6 +- .../file_systems/packagefs/PackageFSRoot.cpp | 116 +++++++++++++++++- .../file_systems/packagefs/PackageFSRoot.h | 10 ++ .../file_systems/packagefs/Resolvable.cpp | 34 ++++- .../file_systems/packagefs/Resolvable.h | 30 ++++- .../packagefs/ResolvableFamily.cpp | 46 +++++++ .../file_systems/packagefs/ResolvableFamily.h | 85 +++++++++++++ 11 files changed, 441 insertions(+), 6 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/DependencyFamily.h create mode 100644 src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.h diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp index 4b8762caa2..45897c4223 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp @@ -15,6 +15,7 @@ Dependency::Dependency(Package* package) : fPackage(package), + fFamily(NULL), fResolvable(NULL), fName(NULL), fVersion(NULL), diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.h b/src/add-ons/kernel/file_systems/packagefs/Dependency.h index e2027f8d1b..142b274dca 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Dependency.h +++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.h @@ -13,6 +13,7 @@ #include +class DependencyFamily; class Package; class Resolvable; class Version; @@ -34,21 +35,41 @@ public: // version is optional; object takes over // ownership + void SetFamily(DependencyFamily* family) + { fFamily = family; } + DependencyFamily* Family() const + { return fFamily; } + void SetResolvable(::Resolvable* resolvable) { fResolvable = resolvable; } ::Resolvable* Resolvable() const { return fResolvable; } + const char* Name() const { return fName; } + private: Package* fPackage; + DependencyFamily* fFamily; ::Resolvable* fResolvable; char* fName; Version* fVersion; BPackageResolvableOperator fVersionOperator; + +public: // conceptually package private + DoublyLinkedListLink fFamilyListLink; + DoublyLinkedListLink fResolvableListLink; }; typedef DoublyLinkedList DependencyList; +typedef DoublyLinkedList > FamilyDependencyList; + +typedef DoublyLinkedList > ResolvableDependencyList; + #endif // DEPENDENCY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/DependencyFamily.h b/src/add-ons/kernel/file_systems/packagefs/DependencyFamily.h new file mode 100644 index 0000000000..3971bc07f7 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/DependencyFamily.h @@ -0,0 +1,97 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef DEPENDENCY_FAMILY_H +#define DEPENDENCY_FAMILY_H + + +#include +#include + +#include "Dependency.h" + + +class DependencyFamily { +public: + void AddDependency(Dependency* dependency); + void RemoveDependency(Dependency* dependency); + + const char* Name() const; + + bool IsLastDependency(Dependency* dependency) const; + + DependencyFamily*& HashLink() { return fHashLink; } + +private: + DependencyFamily* fHashLink; + FamilyDependencyList fDependencies; +}; + + +inline void +DependencyFamily::AddDependency(Dependency* dependency) +{ + fDependencies.Add(dependency); + dependency->SetFamily(this); +} + + +inline void +DependencyFamily::RemoveDependency(Dependency* dependency) +{ + dependency->SetFamily(NULL); + fDependencies.Remove(dependency); +} + + +inline const char* +DependencyFamily::Name() const +{ + Dependency* head = fDependencies.Head(); + return head != NULL ? head->Name() : NULL; +} + + +inline bool +DependencyFamily::IsLastDependency(Dependency* dependency) const +{ + return fDependencies.Head() == dependency + && fDependencies.Tail() == dependency; +} + + +// #pragma mark - DependencyFamilyHashDefinition + + +struct DependencyFamilyHashDefinition { + typedef const char* KeyType; + typedef DependencyFamily ValueType; + + size_t HashKey(const char* key) const + { + return key != NULL ? hash_hash_string(key) : 0; + } + + size_t Hash(const DependencyFamily* value) const + { + return HashKey(value->Name()); + } + + bool Compare(const char* key, const DependencyFamily* value) const + { + return strcmp(value->Name(), key) == 0; + } + + DependencyFamily*& GetLink(DependencyFamily* value) const + { + return value->HashLink(); + } +}; + + +typedef BOpenHashTable + DependencyFamilyHashTable; + + +#endif // DEPENDENCY_FAMILY_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index d9a68ab980..2a726cf622 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -30,6 +30,7 @@ HAIKU_PACKAGE_FS_SOURCES = PackageNodeAttribute.cpp PackageSymlink.cpp Resolvable.cpp + ResolvableFamily.cpp UnpackingAttributeCookie.cpp UnpackingAttributeDirectoryCookie.cpp UnpackingDirectory.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.h b/src/add-ons/kernel/file_systems/packagefs/Package.h index 9ccc759164..d6ec920c0e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Package.h +++ b/src/add-ons/kernel/file_systems/packagefs/Package.h @@ -60,7 +60,11 @@ public: int Open(); void Close(); - const PackageNodeList& Nodes() const { return fNodes; } + const PackageNodeList& Nodes() const { return fNodes; } + const ResolvableList& Resolvables() const + { return fResolvables; } + const DependencyList& Dependencies() const + { return fDependencies; } private: mutex fLock; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp index aa4dcb8bae..3d05e7cad4 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp @@ -64,6 +64,14 @@ PackageFSRoot::Init() if (error != B_OK) RETURN_ERROR(error); + error = fResolvables.Init(); + if (error != B_OK) + RETURN_ERROR(error); + + error = fDependencies.Init(); + if (error != B_OK) + RETURN_ERROR(error); + return B_OK; } @@ -159,14 +167,24 @@ PackageFSRoot::UnregisterVolume(Volume* volume) status_t PackageFSRoot::AddPackage(Package* package) { - return fPackageLinksDirectory->AddPackage(package); + PackageFSRootWriteLocker writeLocker(this); + + status_t error = _AddPackage(package); + if (error != B_OK) { + _RemovePackage(package); + RETURN_ERROR(error); + } + + return B_OK; } void PackageFSRoot::RemovePackage(Package* package) { - fPackageLinksDirectory->RemovePackage(package); + PackageFSRootWriteLocker writeLocker(this); + + _RemovePackage(package); } @@ -209,6 +227,100 @@ PackageFSRoot::_RemoveVolume(Volume* volume) } +status_t +PackageFSRoot::_AddPackage(Package* package) +{ + ResolvableDependencyList dependenciesToUpdate; + + // register resolvables + for (ResolvableList::ConstIterator it + = package->Resolvables().GetIterator(); + Resolvable* resolvable = it.Next();) { + if (ResolvableFamily* family + = fResolvables.Lookup(resolvable->Name())) { + family->AddResolvable(resolvable, dependenciesToUpdate); + } else { + ResolvableFamily* family = new(std::nothrow) ResolvableFamily; + if (family == NULL) + return B_NO_MEMORY; + + family->AddResolvable(resolvable, dependenciesToUpdate); + fResolvables.Insert(family); + } + } + + // register dependencies + for (DependencyList::ConstIterator it + = package->Dependencies().GetIterator(); + Dependency* dependency = it.Next();) { + if (DependencyFamily* family + = fDependencies.Lookup(dependency->Name())) { + family->AddDependency(dependency); + } else { + DependencyFamily* family = new(std::nothrow) DependencyFamily; + if (family == NULL) + return B_NO_MEMORY; + + family->AddDependency(dependency); + fDependencies.Insert(family); + } + + dependenciesToUpdate.Add(dependency); + } + + return fPackageLinksDirectory->AddPackage(package); +} + + +void +PackageFSRoot::_RemovePackage(Package* package) +{ + fPackageLinksDirectory->RemovePackage(package); + + // unregister dependencies + for (DependencyList::ConstIterator it + = package->Dependencies().GetIterator(); + Dependency* dependency = it.Next();) { + if (DependencyFamily* family = dependency->Family()) { + if (family->IsLastDependency(dependency)) { + fDependencies.Remove(family); + family->RemoveDependency(dependency); + delete family; + } else + family->RemoveDependency(dependency); + } + } + + // unregister resolvables + ResolvableDependencyList dependenciesToUpdate; + + for (ResolvableList::ConstIterator it + = package->Resolvables().GetIterator(); + Resolvable* resolvable = it.Next();) { + if (ResolvableFamily* family = resolvable->Family()) { + if (family->IsLastResolvable(resolvable)) { + fResolvables.Remove(family); + family->RemoveResolvable(resolvable, dependenciesToUpdate); + delete family; + } else + family->RemoveResolvable(resolvable, dependenciesToUpdate); + } + } + + _ResolveDependencies(dependenciesToUpdate); +} + + +void +PackageFSRoot::_ResolveDependencies(ResolvableDependencyList& dependencies) +{ + if (dependencies.IsEmpty()) + return; + + // TODO:... +} + + /*static*/ status_t PackageFSRoot::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, PackageFSRoot*& _root) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h index 18d6618c49..acdaf9e128 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h @@ -13,6 +13,8 @@ #include +#include "DependencyFamily.h" +#include "ResolvableFamily.h" #include "Volume.h" @@ -58,6 +60,12 @@ private: status_t _AddVolume(Volume* volume); void _RemoveVolume(Volume* volume); + status_t _AddPackage(Package* package); + void _RemovePackage(Package* package); + + void _ResolveDependencies( + ResolvableDependencyList& dependencies); + static status_t _GetOrCreateRoot(dev_t deviceID, ino_t nodeID, PackageFSRoot*& _root); static PackageFSRoot* _FindRootLocked(dev_t deviceID, ino_t nodeID); @@ -73,6 +81,8 @@ private: VolumeList fVolumes; Volume* fSystemVolume; PackageLinksDirectory* fPackageLinksDirectory; + ResolvableFamilyHashTable fResolvables; + DependencyFamilyHashTable fDependencies; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp b/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp index 7e00edb05f..d0cfc17d70 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp @@ -11,9 +11,10 @@ #include "Version.h" -Resolvable::Resolvable(Package* package) +Resolvable::Resolvable(::Package* package) : fPackage(package), + fFamily(NULL), fName(NULL), fVersion(NULL) { @@ -38,3 +39,34 @@ Resolvable::Init(const char* name, Version* version) return B_OK; } + + +void +Resolvable::AddDependency(Dependency* dependency) +{ + fDependencies.Add(dependency); + dependency->SetResolvable(this); +} + + +void +Resolvable::RemoveDependency(Dependency* dependency) +{ + fDependencies.Remove(dependency); + dependency->SetResolvable(NULL); +} + + +void +Resolvable::MoveDependencies(ResolvableDependencyList& dependencies) +{ + if (fDependencies.IsEmpty()) + return; + + for (ResolvableDependencyList::Iterator it = fDependencies.GetIterator(); + Dependency* dependency = it.Next();) { + dependency->SetResolvable(NULL); + } + + dependencies.MoveFrom(&fDependencies); +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Resolvable.h b/src/add-ons/kernel/file_systems/packagefs/Resolvable.h index e73f6affc8..f68a4e3b80 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Resolvable.h +++ b/src/add-ons/kernel/file_systems/packagefs/Resolvable.h @@ -10,29 +10,55 @@ #include +#include "Dependency.h" + class Package; +class ResolvableFamily; class Version; class Resolvable : public BReferenceable, public DoublyLinkedListLinkImpl { public: - Resolvable(Package* package); + Resolvable(::Package* package); virtual ~Resolvable(); status_t Init(const char* name, Version* version); // version is optional; object takes over // ownership (even in case of error) + ::Package* Package() const { return fPackage; } + + void SetFamily(ResolvableFamily* family) + { fFamily = family; } + ResolvableFamily* Family() const + { return fFamily; } + + const char* Name() const { return fName; } + + void AddDependency(Dependency* dependency); + void RemoveDependency(Dependency* dependency); + void MoveDependencies( + ResolvableDependencyList& dependencies); + private: - Package* fPackage; + ::Package* fPackage; + ResolvableFamily* fFamily; char* fName; Version* fVersion; + ResolvableDependencyList fDependencies; + +public: // conceptually package private + DoublyLinkedListLink fFamilyListLink; }; typedef DoublyLinkedList ResolvableList; +typedef DoublyLinkedList > FamilyResolvableList; + #endif // RESOLVABLE_H diff --git a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp new file mode 100644 index 0000000000..ab9060f204 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp @@ -0,0 +1,46 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "ResolvableFamily.h" + +#include "Package.h" +#include "Volume.h" + + +void +ResolvableFamily::AddResolvable(Resolvable* resolvable, + ResolvableDependencyList& dependenciesToUpdate) +{ + // Find the insertion point in the list. We sort by mount type -- the more + // specific the higher the priority. + MountType mountType + = resolvable->Package()->Domain()->Volume()->MountType(); + Resolvable* otherResolvable = NULL; + for (FamilyResolvableList::Iterator it = fResolvables.GetIterator(); + (otherResolvable = it.Next()) != NULL;) { + if (otherResolvable->Package()->Domain()->Volume()->MountType() + <= mountType) { + break; + } + } + + fResolvables.InsertBefore(otherResolvable, resolvable); + resolvable->SetFamily(this); + + // all dependencies after the inserted resolvable potentially need to be + // updated + while ((resolvable = fResolvables.GetNext(resolvable)) != NULL) + resolvable->MoveDependencies(dependenciesToUpdate); +} + + +void +ResolvableFamily::RemoveResolvable(Resolvable* resolvable, + ResolvableDependencyList& dependenciesToUpdate) +{ + resolvable->SetFamily(NULL); + fResolvables.Remove(resolvable); +} diff --git a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.h b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.h new file mode 100644 index 0000000000..c63c3322f8 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.h @@ -0,0 +1,85 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef RESOLVABLE_FAMILY_H +#define RESOLVABLE_FAMILY_H + + +#include +#include + +#include "Resolvable.h" + + +class ResolvableFamily { +public: + void AddResolvable(Resolvable* resolvable, + ResolvableDependencyList& + dependenciesToUpdate); + void RemoveResolvable(Resolvable* resolvable, + ResolvableDependencyList& + dependenciesToUpdate); + + const char* Name() const; + + bool IsLastResolvable(Resolvable* resolvable) const; + + ResolvableFamily*& HashLink() { return fHashLink; } + +private: + ResolvableFamily* fHashLink; + FamilyResolvableList fResolvables; +}; + + +inline const char* +ResolvableFamily::Name() const +{ + Resolvable* head = fResolvables.Head(); + return head != NULL ? head->Name() : NULL; +} + + +inline bool +ResolvableFamily::IsLastResolvable(Resolvable* resolvable) const +{ + return fResolvables.Head() == resolvable + && fResolvables.Tail() == resolvable; +} + + +// #pragma mark - ResolvableFamilyHashDefinition + + +struct ResolvableFamilyHashDefinition { + typedef const char* KeyType; + typedef ResolvableFamily ValueType; + + size_t HashKey(const char* key) const + { + return key != NULL ? hash_hash_string(key) : 0; + } + + size_t Hash(const ResolvableFamily* value) const + { + return HashKey(value->Name()); + } + + bool Compare(const char* key, const ResolvableFamily* value) const + { + return strcmp(value->Name(), key) == 0; + } + + ResolvableFamily*& GetLink(ResolvableFamily* value) const + { + return value->HashLink(); + } +}; + + +typedef BOpenHashTable + ResolvableFamilyHashTable; + + +#endif // RESOLVABLE_FAMILY_H From 5e972a60c3576edb5ae12cc6475ddda75fe9b4a5 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 17:11:08 +0200 Subject: [PATCH 0109/1170] Dependency: Add Package() getter --- src/add-ons/kernel/file_systems/packagefs/Dependency.cpp | 2 +- src/add-ons/kernel/file_systems/packagefs/Dependency.h | 7 +++++-- 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp index 45897c4223..cec8991d96 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp @@ -12,7 +12,7 @@ #include "Version.h" -Dependency::Dependency(Package* package) +Dependency::Dependency(::Package* package) : fPackage(package), fFamily(NULL), diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.h b/src/add-ons/kernel/file_systems/packagefs/Dependency.h index 142b274dca..9e06d29556 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Dependency.h +++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.h @@ -25,7 +25,7 @@ using BPackageKit::BPackageResolvableOperator; class Dependency : public BReferenceable, public DoublyLinkedListLinkImpl { public: - Dependency(Package* package); + Dependency(::Package* package); virtual ~Dependency(); status_t Init(const char* name); @@ -35,6 +35,9 @@ public: // version is optional; object takes over // ownership + ::Package* Package() const + { return fPackage; } + void SetFamily(DependencyFamily* family) { fFamily = family; } DependencyFamily* Family() const @@ -48,7 +51,7 @@ public: const char* Name() const { return fName; } private: - Package* fPackage; + ::Package* fPackage; DependencyFamily* fFamily; ::Resolvable* fResolvable; char* fName; From 8a8523274139fe2ef6088748d4023b915cbf2d46 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 17:11:33 +0200 Subject: [PATCH 0110/1170] Add Dependency::ResolvableVersionMatches() --- .../kernel/file_systems/packagefs/Dependency.cpp | 11 +++++++++++ .../kernel/file_systems/packagefs/Dependency.h | 2 ++ 2 files changed, 13 insertions(+) diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp index cec8991d96..a08ea6dd4c 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp @@ -49,3 +49,14 @@ Dependency::SetVersionRequirement(BPackageResolvableOperator op, fVersionOperator = op; fVersion = version; } + + +bool +Dependency::ResolvableVersionMatches(Version* resolvableVersion) const +{ + if (fVersion == NULL) + return true; + + return resolvableVersion != NULL + && fVersion->Compare(fVersionOperator, *resolvableVersion); +} diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.h b/src/add-ons/kernel/file_systems/packagefs/Dependency.h index 9e06d29556..0da11cc3d1 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Dependency.h +++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.h @@ -47,6 +47,8 @@ public: { fResolvable = resolvable; } ::Resolvable* Resolvable() const { return fResolvable; } + bool ResolvableVersionMatches( + Version* resolvableVersion) const; const char* Name() const { return fName; } From 0d7d1795a193cd6eb29838fb6e6db9fb685830fb Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 17:12:03 +0200 Subject: [PATCH 0111/1170] Resolvable: Add Version() getter --- src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp | 2 +- src/add-ons/kernel/file_systems/packagefs/Resolvable.h | 5 +++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp b/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp index d0cfc17d70..4af0036c42 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp @@ -29,7 +29,7 @@ Resolvable::~Resolvable() status_t -Resolvable::Init(const char* name, Version* version) +Resolvable::Init(const char* name, ::Version* version) { fVersion = version; diff --git a/src/add-ons/kernel/file_systems/packagefs/Resolvable.h b/src/add-ons/kernel/file_systems/packagefs/Resolvable.h index f68a4e3b80..302765e2cf 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Resolvable.h +++ b/src/add-ons/kernel/file_systems/packagefs/Resolvable.h @@ -24,7 +24,7 @@ public: Resolvable(::Package* package); virtual ~Resolvable(); - status_t Init(const char* name, Version* version); + status_t Init(const char* name, ::Version* version); // version is optional; object takes over // ownership (even in case of error) @@ -36,6 +36,7 @@ public: { return fFamily; } const char* Name() const { return fName; } + ::Version* Version() const { return fVersion; } void AddDependency(Dependency* dependency); void RemoveDependency(Dependency* dependency); @@ -46,7 +47,7 @@ private: ::Package* fPackage; ResolvableFamily* fFamily; char* fName; - Version* fVersion; + ::Version* fVersion; ResolvableDependencyList fDependencies; public: // conceptually package private From 4081d37dec1f26c66421857dc8a835e465e6d296 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 17:13:07 +0200 Subject: [PATCH 0112/1170] ResolvableFamily: Add ResolveDependency() --- .../file_systems/packagefs/ResolvableFamily.cpp | 15 +++++++++++++++ .../file_systems/packagefs/ResolvableFamily.h | 2 ++ 2 files changed, 17 insertions(+) diff --git a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp index ab9060f204..28de17716e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp @@ -44,3 +44,18 @@ ResolvableFamily::RemoveResolvable(Resolvable* resolvable, resolvable->SetFamily(NULL); fResolvables.Remove(resolvable); } + + +bool +ResolvableFamily::ResolveDependency(Dependency* dependency) +{ + for (FamilyResolvableList::Iterator it = fResolvables.GetIterator(); + Resolvable* resolvable = it.Next();) { + if (dependency->ResolvableVersionMatches(resolvable->Version())) { + resolvable->AddDependency(dependency); + return true; + } + } + + return false; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.h b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.h index c63c3322f8..7d0a87fcbc 100644 --- a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.h +++ b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.h @@ -21,6 +21,8 @@ public: ResolvableDependencyList& dependenciesToUpdate); + bool ResolveDependency(Dependency* dependency); + const char* Name() const; bool IsLastResolvable(Resolvable* resolvable) const; From bd66b7e67068edf56f2d1cf2bec7c3c4e654b25c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 17:13:55 +0200 Subject: [PATCH 0113/1170] Resolve dependencies to resolvables --- .../file_systems/packagefs/PackageFSRoot.cpp | 38 ++++++++++++++++++- .../file_systems/packagefs/PackageFSRoot.h | 1 + .../packagefs/PackageLinkDirectory.cpp | 8 ++++ .../packagefs/PackageLinkDirectory.h | 2 + .../packagefs/PackageLinksDirectory.cpp | 17 ++++++++- .../packagefs/PackageLinksDirectory.h | 1 + 6 files changed, 63 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp index 3d05e7cad4..a19b7f6cf5 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp @@ -268,7 +268,13 @@ PackageFSRoot::_AddPackage(Package* package) dependenciesToUpdate.Add(dependency); } - return fPackageLinksDirectory->AddPackage(package); + status_t error = fPackageLinksDirectory->AddPackage(package); + if (error != B_OK) + RETURN_ERROR(error); + + _ResolveDependencies(dependenciesToUpdate); + + return B_OK; } @@ -317,7 +323,35 @@ PackageFSRoot::_ResolveDependencies(ResolvableDependencyList& dependencies) if (dependencies.IsEmpty()) return; - // TODO:... + while (Dependency* dependency = dependencies.RemoveHead()) { + Package* package = dependency->Package(); + _ResolveDependency(dependency); + + // also resolve all other dependencies for that package + for (ResolvableDependencyList::Iterator it = dependencies.GetIterator(); + (dependency = it.Next()) != NULL;) { + if (dependency->Package() == package) { + it.Remove(); + _ResolveDependency(dependency); + } + } + + fPackageLinksDirectory->UpdatePackageDependencies(package); + } +} + + +void +PackageFSRoot::_ResolveDependency(Dependency* dependency) +{ + // get the resolvable family for the dependency + ResolvableFamily* resolvableFamily + = fResolvables.Lookup(dependency->Name()); + if (resolvableFamily == NULL) + return; + + // let the family resolve the dependency + resolvableFamily->ResolveDependency(dependency); } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h index acdaf9e128..510f7144e7 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.h @@ -65,6 +65,7 @@ private: void _ResolveDependencies( ResolvableDependencyList& dependencies); + void _ResolveDependency(Dependency* dependency); static status_t _GetOrCreateRoot(dev_t deviceID, ino_t nodeID, PackageFSRoot*& _root); diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp index ee4ba52ef1..c864940e0e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp @@ -297,6 +297,14 @@ PackageLinkDirectory::RemovePackage(Package* package, } +void +PackageLinkDirectory::UpdatePackageDependencies(Package* package, + PackageLinksListener* listener) +{ +// TODO:... +} + + status_t PackageLinkDirectory::_Update(PackageLinksListener* listener) { diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h index ee87220167..afc8c5f9eb 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h @@ -37,6 +37,8 @@ public: PackageLinksListener* listener); void RemovePackage(Package* package, PackageLinksListener* listener); + void UpdatePackageDependencies(Package* package, + PackageLinksListener* listener); bool IsEmpty() const { return fPackages.IsEmpty(); } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp index 848eb5af91..473c4aa888 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp @@ -134,6 +134,8 @@ PackageLinksDirectory::AddPackage(Package* package) void PackageLinksDirectory::RemovePackage(Package* package) { + NodeWriteLocker writeLocker(this); + // get the package's link directory and remove the package from it PackageLinkDirectory* linkDirectory = package->LinkDirectory(); if (linkDirectory == NULL) @@ -141,8 +143,6 @@ PackageLinksDirectory::RemovePackage(Package* package) BReference linkDirectoryReference(linkDirectory); - NodeWriteLocker writeLocker(this); - linkDirectory->RemovePackage(package, fListener); // if empty, remove the link directory itself @@ -150,3 +150,16 @@ PackageLinksDirectory::RemovePackage(Package* package) RemoveChild(linkDirectory); } + +void +PackageLinksDirectory::UpdatePackageDependencies(Package* package) +{ + NodeWriteLocker writeLocker(this); + + PackageLinkDirectory* linkDirectory = package->LinkDirectory(); + if (linkDirectory == NULL) + return; + + linkDirectory->UpdatePackageDependencies(package, fListener); +} + diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h index 4d5e3f1d0c..8d509038b8 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h @@ -34,6 +34,7 @@ public: status_t AddPackage(Package* package); void RemovePackage(Package* package); + void UpdatePackageDependencies(Package* package); private: timespec fModifiedTime; From a39e95cd73139d85c43cbece88fa5ffa22e73129 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 18:28:38 +0200 Subject: [PATCH 0114/1170] Move PackageLinkDirectory::Link to own file And rename it to PackageLinkSymlink. --- .../kernel/file_systems/packagefs/Jamfile | 1 + .../packagefs/PackageLinkDirectory.cpp | 124 +------------- .../packagefs/PackageLinkDirectory.h | 5 +- .../packagefs/PackageLinkSymlink.cpp | 154 ++++++++++++++++++ .../packagefs/PackageLinkSymlink.h | 47 ++++++ 5 files changed, 207 insertions(+), 124 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index 2a726cf622..fb5a9ff0a0 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -26,6 +26,7 @@ HAIKU_PACKAGE_FS_SOURCES = PackageLinkDirectory.cpp PackageLinksDirectory.cpp PackageLinksListener.cpp + PackageLinkSymlink.cpp PackageNode.cpp PackageNodeAttribute.cpp PackageSymlink.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp index c864940e0e..49aa597de6 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp @@ -6,7 +6,6 @@ #include "PackageLinkDirectory.h" -#include #include #include @@ -22,120 +21,6 @@ static const char* const kSelfLinkName = ".self"; -static const char* const kSystemLinkPath = "../.."; -static const char* const kCommonLinkPath = "../../../common"; -static const char* const kHomeLinkPath = "../../../home/config"; - - -static const char* -link_path_for_mount_type(MountType type) -{ - switch (type) { - case MOUNT_TYPE_SYSTEM: - return kSystemLinkPath; - case MOUNT_TYPE_COMMON: - return kCommonLinkPath; - case MOUNT_TYPE_HOME: - return kHomeLinkPath; - case MOUNT_TYPE_CUSTOM: - default: - return "?"; - } -} - - -// #pragma mark - SelfLink - - -class PackageLinkDirectory::SelfLink : public Node { -public: - SelfLink(Package* package) - : - Node(0) - { - Update(package); - } - - virtual ~SelfLink() - { - } - - void Update(Package* package) - { - fLinkPath = link_path_for_mount_type( - package->Domain()->Volume()->MountType()); - get_real_time(fModifiedTime); - } - - virtual mode_t Mode() const - { - return S_IFLNK | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH - | S_IXOTH; - } - - virtual uid_t UserID() const - { - return 0; - } - - virtual gid_t GroupID() const - { - return 0; - } - - virtual timespec ModifiedTime() const - { - return fModifiedTime; - } - - virtual off_t FileSize() const - { - return strlen(fLinkPath); - } - - virtual status_t Read(off_t offset, void* buffer, size_t* bufferSize) - { - return B_BAD_VALUE; - } - - virtual status_t Read(io_request* request) - { - return B_BAD_VALUE; - } - - virtual status_t ReadSymlink(void* buffer, size_t* bufferSize) - { - size_t toCopy = std::min(strlen(fLinkPath), *bufferSize); - memcpy(buffer, fLinkPath, toCopy); - *bufferSize = toCopy; - - return B_OK; - } - - virtual status_t OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) - { - AttributeDirectoryCookie* cookie - = new(std::nothrow) EmptyAttributeDirectoryCookie; - if (cookie == NULL) - return B_NO_MEMORY; - - _cookie = cookie; - return B_OK; - } - - virtual status_t OpenAttribute(const char* name, int openMode, - AttributeCookie*& _cookie) - { - return B_ENTRY_NOT_FOUND; - } - -private: - timespec fModifiedTime; - const char* fLinkPath; -}; - - -// #pragma mark - PackageLinkDirectory PackageLinkDirectory::PackageLinkDirectory() @@ -327,7 +212,7 @@ PackageLinkDirectory::_Update(PackageLinksListener* listener) // create/update self link if (fSelfLink == NULL) { - fSelfLink = new(std::nothrow) SelfLink(package); + fSelfLink = new(std::nothrow) Link(package); if (fSelfLink == NULL) return B_NO_MEMORY; @@ -344,12 +229,7 @@ PackageLinkDirectory::_Update(PackageLinksListener* listener) } } else { NodeWriteLocker selfLinkLocker(fSelfLink); - fSelfLink->Update(package); - - if (listener != NULL) { - listener->PackageLinkNodeChanged(fSelfLink, - B_STAT_SIZE | B_STAT_MODIFICATION_TIME); - } + fSelfLink->Update(package, listener); } return B_OK; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h index afc8c5f9eb..f98529b863 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h @@ -8,6 +8,7 @@ #include "Directory.h" #include "Package.h" +#include "PackageLinkSymlink.h" class PackageLinksListener; @@ -44,7 +45,7 @@ public: { return fPackages.IsEmpty(); } private: - class SelfLink; + typedef PackageLinkSymlink Link; private: status_t _Update(PackageLinksListener* listener); @@ -52,7 +53,7 @@ private: private: timespec fModifiedTime; PackageList fPackages; - SelfLink* fSelfLink; + Link* fSelfLink; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp new file mode 100644 index 0000000000..9ae5b07863 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp @@ -0,0 +1,154 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "PackageLinkSymlink.h" + +#include + +#include + +#include "EmptyAttributeDirectoryCookie.h" +#include "DebugSupport.h" +#include "PackageLinksListener.h" +#include "Utils.h" +#include "Volume.h" + + +static const char* const kSystemLinkPath = "../.."; +static const char* const kCommonLinkPath = "../../../common"; +static const char* const kHomeLinkPath = "../../../home/config"; + + +static const char* +link_path_for_mount_type(MountType type) +{ + switch (type) { + case MOUNT_TYPE_SYSTEM: + return kSystemLinkPath; + case MOUNT_TYPE_COMMON: + return kCommonLinkPath; + case MOUNT_TYPE_HOME: + return kHomeLinkPath; + case MOUNT_TYPE_CUSTOM: + default: + return "?"; + } +} + + +// #pragma mark - + + +PackageLinkSymlink::PackageLinkSymlink(Package* package) + : + Node(0) +{ + Update(package, NULL); +} + + +PackageLinkSymlink::~PackageLinkSymlink() +{ +} + + +void +PackageLinkSymlink::Update(Package* package, PackageLinksListener* listener) +{ + if (package != NULL) { + fLinkPath = link_path_for_mount_type( + package->Domain()->Volume()->MountType()); + } else + fLinkPath = "?"; + + get_real_time(fModifiedTime); + + if (listener != NULL) { + listener->PackageLinkNodeChanged(this, + B_STAT_SIZE | B_STAT_MODIFICATION_TIME); + } +} + + +mode_t +PackageLinkSymlink::Mode() const +{ + return S_IFLNK | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH; +} + + +uid_t +PackageLinkSymlink::UserID() const +{ + return 0; +} + + +gid_t +PackageLinkSymlink::GroupID() const +{ + return 0; +} + + +timespec +PackageLinkSymlink::ModifiedTime() const +{ + return fModifiedTime; +} + + +off_t +PackageLinkSymlink::FileSize() const +{ + return strlen(fLinkPath); +} + + +status_t +PackageLinkSymlink::Read(off_t offset, void* buffer, size_t* bufferSize) +{ + return B_BAD_VALUE; +} + + +status_t +PackageLinkSymlink::Read(io_request* request) +{ + return B_BAD_VALUE; +} + + +status_t +PackageLinkSymlink::ReadSymlink(void* buffer, size_t* bufferSize) +{ + size_t toCopy = std::min(strlen(fLinkPath), *bufferSize); + memcpy(buffer, fLinkPath, toCopy); + *bufferSize = toCopy; + + return B_OK; +} + + +status_t +PackageLinkSymlink::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie) +{ + AttributeDirectoryCookie* cookie + = new(std::nothrow) EmptyAttributeDirectoryCookie; + if (cookie == NULL) + return B_NO_MEMORY; + + _cookie = cookie; + return B_OK; +} + + +status_t +PackageLinkSymlink::OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie) +{ + return B_ENTRY_NOT_FOUND; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h new file mode 100644 index 0000000000..91e687e71c --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h @@ -0,0 +1,47 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef PACKAGE_LINK_SYMLINK_H +#define PACKAGE_LINK_SYMLINK_H + + +#include "Node.h" + + +class Package; +class PackageLinksListener; + + +class PackageLinkSymlink : public Node { +public: + PackageLinkSymlink(Package* package); + virtual ~PackageLinkSymlink(); + + void Update(Package* package, + PackageLinksListener* listener); + + virtual mode_t Mode() const; + virtual uid_t UserID() const; + virtual gid_t GroupID() const; + virtual timespec ModifiedTime() const; + virtual off_t FileSize() const; + + virtual status_t Read(off_t offset, void* buffer, + size_t* bufferSize); + virtual status_t Read(io_request* request); + + virtual status_t ReadSymlink(void* buffer, size_t* bufferSize); + + virtual status_t OpenAttributeDirectory( + AttributeDirectoryCookie*& _cookie); + virtual status_t OpenAttribute(const char* name, int openMode, + AttributeCookie*& _cookie); + +private: + timespec fModifiedTime; + const char* fLinkPath; +}; + + +#endif // PACKAGE_LINK_SYMLINK_H From dd9554ae693e18520e6345f261626f130786e030 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 18:32:06 +0200 Subject: [PATCH 0115/1170] Add dependency package links The links appear, but the dependency resolution doesn't seem to work correctly yet. --- .../packagefs/PackageLinkDirectory.cpp | 74 ++++++++++++++++++- .../packagefs/PackageLinkDirectory.h | 18 +++++ 2 files changed, 91 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp index 49aa597de6..86fab0f19b 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp @@ -37,6 +37,9 @@ PackageLinkDirectory::~PackageLinkDirectory() { if (fSelfLink != NULL) fSelfLink->ReleaseReference(); + + while (DependencyLink* link = fDependencyLinks.RemoveHead()) + link->ReleaseReference(); } @@ -186,13 +189,32 @@ void PackageLinkDirectory::UpdatePackageDependencies(Package* package, PackageLinksListener* listener) { -// TODO:... + ASSERT(package->LinkDirectory() == this); + + NodeWriteLocker writeLocker(this); + + // We only need to update, if that head package is affected. + if (package != fPackages.Head()) + return; + + _UpdateDependencies(listener); } status_t PackageLinkDirectory::_Update(PackageLinksListener* listener) { + // Always remove all dependency links -- if there's still a package, they + // will be re-created below. + while (DependencyLink* link = fDependencyLinks.RemoveHead()) { + NodeWriteLocker selfLinkLocker(link); + if (listener != NULL) + listener->PackageLinkNodeRemoved(link); + + RemoveChild(link); + link->ReleaseReference(); + } + // check, if empty Package* package = fPackages.Head(); if (package == NULL) { @@ -232,5 +254,55 @@ PackageLinkDirectory::_Update(PackageLinksListener* listener) fSelfLink->Update(package, listener); } + // update the dependency links + return _UpdateDependencies(listener); +} + + +status_t +PackageLinkDirectory::_UpdateDependencies(PackageLinksListener* listener) +{ + Package* package = fPackages.Head(); + if (package == NULL) + return B_OK; + + // Iterate through the package's dependencies + for (DependencyList::ConstIterator it + = package->Dependencies().GetIterator(); + Dependency* dependency = it.Next();) { + Resolvable* resolvable = dependency->Resolvable(); + Package* resolvablePackage = resolvable != NULL + ? resolvable->Package() : NULL; + + Node* node = FindChild(dependency->Name()); + if (node != NULL) { + // link already exists -- update + DependencyLink* link = static_cast(node); + + NodeWriteLocker linkLocker(link); + link->Update(resolvablePackage, listener); + } else { + // no link for the dependency yet -- create one + DependencyLink* link = new(std::nothrow) DependencyLink( + resolvablePackage); + if (link == NULL) + return B_NO_MEMORY; + + status_t error = link->Init(this, dependency->Name(), 0); + if (error != B_OK) { + delete link; + RETURN_ERROR(error); + } + + AddChild(link); + fDependencyLinks.Add(link); + + if (listener != NULL) { + NodeWriteLocker linkLocker(link); + listener->PackageLinkNodeAdded(link); + } + } + } + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h index f98529b863..0aca0837bb 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h @@ -47,13 +47,31 @@ public: private: typedef PackageLinkSymlink Link; + struct DependencyLink : public PackageLinkSymlink { + DependencyLink(Package* package) + : + PackageLinkSymlink(package) + { + } + + DoublyLinkedListLink fPackageLinkDirectoryLink; + }; + + typedef DoublyLinkedList > + FamilyDependencyList; + private: status_t _Update(PackageLinksListener* listener); + status_t _UpdateDependencies( + PackageLinksListener* listener); private: timespec fModifiedTime; PackageList fPackages; Link* fSelfLink; + FamilyDependencyList fDependencyLinks; }; From b143a5a86161569d1fddd77c4c38cd4a93164aef Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 18:46:03 +0200 Subject: [PATCH 0116/1170] Notify when removing a package link directory --- .../file_systems/packagefs/PackageLinksDirectory.cpp | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp index 473c4aa888..be3a2a875c 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp @@ -146,8 +146,14 @@ PackageLinksDirectory::RemovePackage(Package* package) linkDirectory->RemovePackage(package, fListener); // if empty, remove the link directory itself - if (linkDirectory->IsEmpty()) + if (linkDirectory->IsEmpty()) { + if (fListener != NULL) { + NodeWriteLocker linkDirectoryWriteLocker(linkDirectory); + fListener->PackageLinkNodeRemoved(linkDirectory); + } + RemoveChild(linkDirectory); + } } From 5165b6b1d824e80008b09f1ff6319e41b20de09f Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 25 Jun 2011 19:05:10 +0200 Subject: [PATCH 0117/1170] Fix adding order dependent dependency resolution PackageFSRoot::_AddPackage(): When adding a resolvable which isn't known yet, make sure all already added matching dependencies are resolved. --- .../file_systems/packagefs/DependencyFamily.h | 13 +++++++++++++ .../kernel/file_systems/packagefs/PackageFSRoot.cpp | 6 ++++++ 2 files changed, 19 insertions(+) diff --git a/src/add-ons/kernel/file_systems/packagefs/DependencyFamily.h b/src/add-ons/kernel/file_systems/packagefs/DependencyFamily.h index 3971bc07f7..fa9daf1d0b 100644 --- a/src/add-ons/kernel/file_systems/packagefs/DependencyFamily.h +++ b/src/add-ons/kernel/file_systems/packagefs/DependencyFamily.h @@ -17,6 +17,9 @@ public: void AddDependency(Dependency* dependency); void RemoveDependency(Dependency* dependency); + void AddDependenciesToList( + ResolvableDependencyList& list) const; + const char* Name() const; bool IsLastDependency(Dependency* dependency) const; @@ -45,6 +48,16 @@ DependencyFamily::RemoveDependency(Dependency* dependency) } +inline void +DependencyFamily::AddDependenciesToList(ResolvableDependencyList& list) const +{ + for (FamilyDependencyList::ConstIterator it = fDependencies.GetIterator(); + Dependency* dependency = it.Next();) { + list.Add(dependency); + } +} + + inline const char* DependencyFamily::Name() const { diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp index a19b7f6cf5..e7e20eb5a8 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp @@ -246,6 +246,12 @@ PackageFSRoot::_AddPackage(Package* package) family->AddResolvable(resolvable, dependenciesToUpdate); fResolvables.Insert(family); + + // add pre-existing dependencies for that resolvable + if (DependencyFamily* dependencyFamily + = fDependencies.Lookup(resolvable->Name())) { + dependencyFamily->AddDependenciesToList(dependenciesToUpdate); + } } } From 835ecf5aca08b7b5334b6879659a833a06dfb281 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 26 Jun 2011 02:27:38 +0200 Subject: [PATCH 0118/1170] Fix dependency resolution on resolvable removable ResolvableFamily::RemoveResolvable(): Move the resolvable's dependencies to the update list. --- src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp index 28de17716e..c237cd59db 100644 --- a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp @@ -43,6 +43,9 @@ ResolvableFamily::RemoveResolvable(Resolvable* resolvable, { resolvable->SetFamily(NULL); fResolvables.Remove(resolvable); + + // the removed resolvable's dependencies need to be updated + resolvable->MoveDependencies(dependenciesToUpdate); } From 2d132da8dc68c7ca9bd025c458ab46ff500b243e Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 26 Jun 2011 02:28:03 +0200 Subject: [PATCH 0119/1170] Optional dependency resolution tracing --- .../file_systems/packagefs/PackageFSRoot.cpp | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp index e7e20eb5a8..4f1ae09c59 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp @@ -14,6 +14,14 @@ #include "PackageLinksDirectory.h" +//#define TRACE_DEPENDENCIES_ENABLED +#ifdef TRACE_DEPENDENCIES_ENABLED +# define TRACE_DEPENDENCIES(x...) TPRINT(x) +#else +# define TRACE_DEPENDENCIES(x...) do {} while (false) +#endif + + static const char* const kPackageLinksDirectoryName = "package-links"; @@ -230,12 +238,16 @@ PackageFSRoot::_RemoveVolume(Volume* volume) status_t PackageFSRoot::_AddPackage(Package* package) { + TRACE_DEPENDENCIES("adding package \"%s\"\n", package->Name()); + ResolvableDependencyList dependenciesToUpdate; // register resolvables for (ResolvableList::ConstIterator it = package->Resolvables().GetIterator(); Resolvable* resolvable = it.Next();) { + TRACE_DEPENDENCIES(" adding resolvable \"%s\"\n", resolvable->Name()); + if (ResolvableFamily* family = fResolvables.Lookup(resolvable->Name())) { family->AddResolvable(resolvable, dependenciesToUpdate); @@ -259,6 +271,8 @@ PackageFSRoot::_AddPackage(Package* package) for (DependencyList::ConstIterator it = package->Dependencies().GetIterator(); Dependency* dependency = it.Next();) { + TRACE_DEPENDENCIES(" adding dependency \"%s\"\n", dependency->Name()); + if (DependencyFamily* family = fDependencies.Lookup(dependency->Name())) { family->AddDependency(dependency); @@ -287,6 +301,8 @@ PackageFSRoot::_AddPackage(Package* package) void PackageFSRoot::_RemovePackage(Package* package) { + TRACE_DEPENDENCIES("removing package \"%s\"\n", package->Name()); + fPackageLinksDirectory->RemovePackage(package); // unregister dependencies @@ -294,6 +310,9 @@ PackageFSRoot::_RemovePackage(Package* package) = package->Dependencies().GetIterator(); Dependency* dependency = it.Next();) { if (DependencyFamily* family = dependency->Family()) { + TRACE_DEPENDENCIES(" removing dependency \"%s\"\n", + dependency->Name()); + if (family->IsLastDependency(dependency)) { fDependencies.Remove(family); family->RemoveDependency(dependency); @@ -310,6 +329,9 @@ PackageFSRoot::_RemovePackage(Package* package) = package->Resolvables().GetIterator(); Resolvable* resolvable = it.Next();) { if (ResolvableFamily* family = resolvable->Family()) { + TRACE_DEPENDENCIES(" removing resolvable \"%s\"\n", + resolvable->Name()); + if (family->IsLastResolvable(resolvable)) { fResolvables.Remove(family); family->RemoveResolvable(resolvable, dependenciesToUpdate); @@ -350,6 +372,8 @@ PackageFSRoot::_ResolveDependencies(ResolvableDependencyList& dependencies) void PackageFSRoot::_ResolveDependency(Dependency* dependency) { + TRACE_DEPENDENCIES(" resolving dependency \"%s\"\n", dependency->Name()); + // get the resolvable family for the dependency ResolvableFamily* resolvableFamily = fResolvables.Lookup(dependency->Name()); From c99aa60b785b10d0c43762168fc98cf14e0ce2b5 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 26 Jun 2011 03:18:11 +0200 Subject: [PATCH 0120/1170] Allow symlinks in the packages directory --- src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index cbbfa1470f..4421d04464 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -1271,7 +1271,7 @@ Volume::_DomainEntryCreated(PackageDomain* domain, dev_t deviceID, // check whether the entry is a file struct stat st; - if (fstatat(domain->DirectoryFD(), name, &st, AT_SYMLINK_NOFOLLOW) < 0 + if (fstatat(domain->DirectoryFD(), name, &st, 0) < 0 || !S_ISREG(st.st_mode)) { return; } From 2a5bef01a30464638f2c3eee60c9bbe211dac7d8 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 26 Jun 2011 03:20:58 +0200 Subject: [PATCH 0121/1170] Volume:Mount(): Better failure output Also use the FATAL() instead of the ERROR() macro, so something is printed also with debugging disabled. --- src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 4421d04464..9d3bd7108d 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -492,19 +492,21 @@ Volume::Mount(const char* parameterString) &delete_driver_settings); if (packages == NULL || packages[0] == '\0') { - ERROR("need package folder ('packages' parameter)!\n"); + FATAL("need package folder ('packages' parameter)!\n"); RETURN_ERROR(B_BAD_VALUE); } error = _InitMountType(mountType); if (error != B_OK) { - ERROR("invalid mount type: \"%s\"\n", mountType); - RETURN_ERROR(B_ERROR); + FATAL("invalid mount type: \"%s\"\n", mountType); + RETURN_ERROR(error); } struct stat st; - if (stat(packages, &st) < 0) + if (stat(packages, &st) < 0) { + FATAL("failed to stat: \"%s\": %s\n", packages, strerror(errno)); RETURN_ERROR(B_ERROR); + } // If no volume name is given, infer it from the mount type. if (volumeName == NULL) { From c6739b6af04ae36ef758e7db7a1caca0471fc6ab Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 26 Jun 2011 03:21:33 +0200 Subject: [PATCH 0122/1170] Paranoia: Handle unknown mount type --- src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 9d3bd7108d..317676c722 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -521,6 +521,7 @@ Volume::Mount(const char* parameterString) volumeName = "home"; break; case MOUNT_TYPE_CUSTOM: + default: volumeName = "Package FS"; break; } From ecf2e3d34276e387b0deb276ce391395411c89cc Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 26 Jun 2011 03:33:38 +0200 Subject: [PATCH 0123/1170] Cleanup --- .../kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp index 2c1fe25a51..212979cbdd 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp @@ -22,10 +22,7 @@ using BPackageKit::BHPKG::BBufferDataReader; -//using BPackageKit::BHPKG::BDataReader; using BPackageKit::BHPKG::BFDDataReader; -//using BPackageKit::BHPKG::BPackageData; -//using BPackageKit::BHPKG::BPackageDataReader; static status_t From a83fe53dcebb1ea7b96f714ab8f51bae636a3823 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 26 Jun 2011 04:37:30 +0200 Subject: [PATCH 0124/1170] Added default cookie Close() implementation Added trivial implementation for AttributeCookie::Close() and AttributeDirectoryCookie::Close() and removed the identical Close() implementations in derived classes. --- .../kernel/file_systems/packagefs/AttributeCookie.cpp | 7 +++++++ .../kernel/file_systems/packagefs/AttributeCookie.h | 2 +- .../file_systems/packagefs/AttributeDirectoryCookie.cpp | 7 +++++++ .../file_systems/packagefs/AttributeDirectoryCookie.h | 2 +- .../packagefs/EmptyAttributeDirectoryCookie.cpp | 7 ------- .../file_systems/packagefs/EmptyAttributeDirectoryCookie.h | 1 - .../file_systems/packagefs/UnpackingAttributeCookie.cpp | 7 ------- .../file_systems/packagefs/UnpackingAttributeCookie.h | 1 - .../packagefs/UnpackingAttributeDirectoryCookie.cpp | 7 ------- .../packagefs/UnpackingAttributeDirectoryCookie.h | 1 - 10 files changed, 16 insertions(+), 26 deletions(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.cpp index 2df7b99c4b..7a89ca4a0f 100644 --- a/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.cpp @@ -10,3 +10,10 @@ AttributeCookie::~AttributeCookie() { } + + +status_t +AttributeCookie::Close() +{ + return B_OK; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.h b/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.h index 40ee92c18f..142bdb9268 100644 --- a/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.h +++ b/src/add-ons/kernel/file_systems/packagefs/AttributeCookie.h @@ -15,7 +15,7 @@ class AttributeCookie { public: virtual ~AttributeCookie(); - virtual status_t Close() = 0; + virtual status_t Close(); virtual status_t ReadAttribute(off_t offset, void* buffer, size_t* bufferSize) = 0; virtual status_t ReadAttributeStat(struct stat* st) = 0; diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.cpp index adbdc629f0..069e465c63 100644 --- a/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.cpp @@ -10,3 +10,10 @@ AttributeDirectoryCookie::~AttributeDirectoryCookie() { } + + +status_t +AttributeDirectoryCookie::Close() +{ + return B_OK; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.h b/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.h index eb5d271e16..3e1f766b29 100644 --- a/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.h +++ b/src/add-ons/kernel/file_systems/packagefs/AttributeDirectoryCookie.h @@ -15,7 +15,7 @@ class AttributeDirectoryCookie { public: virtual ~AttributeDirectoryCookie(); - virtual status_t Close() = 0; + virtual status_t Close(); virtual status_t Read(dev_t volumeID, ino_t nodeID, struct dirent* buffer, size_t bufferSize, uint32* _count) = 0; diff --git a/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.cpp index dd0da85c5f..98a8eade0d 100644 --- a/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.cpp @@ -7,13 +7,6 @@ #include "EmptyAttributeDirectoryCookie.h" -status_t -EmptyAttributeDirectoryCookie::Close() -{ - return B_OK; -} - - status_t EmptyAttributeDirectoryCookie::Read(dev_t volumeID, ino_t nodeID, struct dirent* buffer, size_t bufferSize, uint32* _count) diff --git a/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.h b/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.h index 699b3d5687..5616591a60 100644 --- a/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.h +++ b/src/add-ons/kernel/file_systems/packagefs/EmptyAttributeDirectoryCookie.h @@ -11,7 +11,6 @@ class EmptyAttributeDirectoryCookie : public AttributeDirectoryCookie { public: - virtual status_t Close(); virtual status_t Read(dev_t volumeID, ino_t nodeID, struct dirent* buffer, size_t bufferSize, uint32* _count); diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp index 212979cbdd..632038d887 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp @@ -100,13 +100,6 @@ UnpackingAttributeCookie::Open(PackageNode* packageNode, const char* name, } -status_t -UnpackingAttributeCookie::Close() -{ - return B_OK; -} - - status_t UnpackingAttributeCookie::ReadAttribute(off_t offset, void* buffer, size_t* bufferSize) diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.h index 27fec3dbe2..9dda846775 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.h +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.h @@ -25,7 +25,6 @@ public: static status_t Open(PackageNode* packageNode, const char* name, int openMode, AttributeCookie*& _cookie); - virtual status_t Close(); virtual status_t ReadAttribute(off_t offset, void* buffer, size_t* bufferSize); virtual status_t ReadAttributeStat(struct stat* st); diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.cpp index 3a95440637..05f9b528f8 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.cpp @@ -45,13 +45,6 @@ UnpackingAttributeDirectoryCookie::Open(PackageNode* packageNode, } -status_t -UnpackingAttributeDirectoryCookie::Close() -{ - return B_OK; -} - - status_t UnpackingAttributeDirectoryCookie::Read(dev_t volumeID, ino_t nodeID, struct dirent* buffer, size_t bufferSize, uint32* _count) diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.h index 0f6bc1baf0..a0ce184c90 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.h +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.h @@ -24,7 +24,6 @@ public: static status_t Open(PackageNode* packageNode, AttributeDirectoryCookie*& _cookie); - virtual status_t Close(); virtual status_t Read(dev_t volumeID, ino_t nodeID, struct dirent* buffer, size_t bufferSize, uint32* _count); From 59e76dbe414f32cc65320b605442f97eb60296c0 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 26 Jun 2011 04:42:37 +0200 Subject: [PATCH 0125/1170] Support for auto-generated package node attributes * Add utility class AutoPackageAttributes and AttributeCookie subclass AutoPackageAttributeCookie. * UnpackingAttributeCookie::Open() does now try to create a AutoPackageAttributeCookie, when it doesn't find the attribute in the PackageNode. * Adjust UnpackingAttributeDirectoryCookie to also list auto-generated attributes. Currently the only supported attribute is "SYS:PACKAGE", which is the file name of the package containing the node. --- .../packagefs/AutoPackageAttributes.cpp | 146 ++++++++++++++++++ .../packagefs/AutoPackageAttributes.h | 38 +++++ .../kernel/file_systems/packagefs/Jamfile | 1 + .../packagefs/UnpackingAttributeCookie.cpp | 8 +- .../UnpackingAttributeDirectoryCookie.cpp | 21 ++- .../UnpackingAttributeDirectoryCookie.h | 2 + 6 files changed, 210 insertions(+), 6 deletions(-) create mode 100644 src/add-ons/kernel/file_systems/packagefs/AutoPackageAttributes.cpp create mode 100644 src/add-ons/kernel/file_systems/packagefs/AutoPackageAttributes.h diff --git a/src/add-ons/kernel/file_systems/packagefs/AutoPackageAttributes.cpp b/src/add-ons/kernel/file_systems/packagefs/AutoPackageAttributes.cpp new file mode 100644 index 0000000000..fac17f9c25 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/AutoPackageAttributes.cpp @@ -0,0 +1,146 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + + +#include "AutoPackageAttributes.h" + +#include +#include + +#include + +#include + +#include "AttributeCookie.h" +#include "DebugSupport.h" +#include "Package.h" + + +static const char* const kAttributeNames[AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT] = { + "SYS:PACKAGE" +}; + + +class AutoPackageAttributeCookie : public AttributeCookie { +public: + AutoPackageAttributeCookie(Package* package, AutoPackageAttribute attribute) + : + fPackage(package), + fAttribute(attribute) + { + fPackage->AcquireReference(); + } + + virtual ~AutoPackageAttributeCookie() + { + fPackage->ReleaseReference(); + } + + virtual status_t ReadAttribute(off_t offset, void* buffer, + size_t* bufferSize) + { + // get the attribute + off_t size; + uint32 type; + const void* value = AutoPackageAttributes::GetAttributeValue(fPackage, + fAttribute, size, type); + if (value == NULL) + return B_BAD_VALUE; + + // check and clamp offset and size + if (offset < 0 || offset > size) + return B_BAD_VALUE; + + size_t toCopy = *bufferSize; + if (offset + toCopy > size) + toCopy = size - offset; + + if (toCopy > 0) + memcpy(buffer, (const uint8*)value + offset, toCopy); + + *bufferSize = toCopy; + return B_OK; + } + + virtual status_t ReadAttributeStat(struct stat* st) + { + if (AutoPackageAttributes::GetAttributeValue(fPackage, fAttribute, + st->st_size, st->st_type) == NULL) { + return B_BAD_VALUE; + } + + return B_OK; + } + +private: + Package* fPackage; + AutoPackageAttribute fAttribute; +}; + + +/*static*/ bool +AutoPackageAttributes::AttributeForName(const char* name, + AutoPackageAttribute& _attribute) +{ + for (int i = 0; i < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT; i++) { + if (strcmp(name, kAttributeNames[i]) == 0) { + _attribute = (AutoPackageAttribute)i; + return true; + } + } + + return false; +} + + +/*static*/ const char* +AutoPackageAttributes::NameForAttribute(AutoPackageAttribute attribute) +{ + if (attribute >= 0 && attribute < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT) + return kAttributeNames[attribute]; + return NULL; +} + + +/*static*/ const void* +AutoPackageAttributes::GetAttributeValue(const Package* package, + AutoPackageAttribute attribute, off_t& _size, uint32& _type) +{ + switch (attribute) { + case AUTO_PACKAGE_ATTRIBUTE_PACKAGE: + { + const char* value = package->FileName(); + _size = strlen(value) + 1; + _type = B_STRING_TYPE; + return value; + } + + default: + return NULL; + } +} + + +/*static*/ status_t +AutoPackageAttributes::OpenCookie(Package* package, const char* name, + int openMode, AttributeCookie*& _cookie) +{ + if (package == NULL) + return B_ENTRY_NOT_FOUND; + + // get the attribute + AutoPackageAttribute attribute; + if (!AttributeForName(name, attribute)) + return B_ENTRY_NOT_FOUND; + + // allocate the cookie + AutoPackageAttributeCookie* cookie = new(std::nothrow) + AutoPackageAttributeCookie(package, attribute); + if (cookie == NULL) + RETURN_ERROR(B_NO_MEMORY); + + _cookie = cookie; + return B_OK; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/AutoPackageAttributes.h b/src/add-ons/kernel/file_systems/packagefs/AutoPackageAttributes.h new file mode 100644 index 0000000000..cbb4d05818 --- /dev/null +++ b/src/add-ons/kernel/file_systems/packagefs/AutoPackageAttributes.h @@ -0,0 +1,38 @@ +/* + * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ +#ifndef AUTO_PACKAGE_ATTRIBUTES_H +#define AUTO_PACKAGE_ATTRIBUTES_H + + +#include + + +class AttributeCookie; +class Package; + + +enum AutoPackageAttribute { + AUTO_PACKAGE_ATTRIBUTE_ENUM_FIRST, + AUTO_PACKAGE_ATTRIBUTE_PACKAGE = AUTO_PACKAGE_ATTRIBUTE_ENUM_FIRST, + + AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT +}; + + +struct AutoPackageAttributes { + static bool AttributeForName(const char* name, + AutoPackageAttribute& _attribute); + static const char* NameForAttribute( + AutoPackageAttribute attribute); + static const void* GetAttributeValue(const Package* package, + AutoPackageAttribute attribute, + off_t& _size, uint32& _type); + + static status_t OpenCookie(Package* package, const char* name, + int openMode, AttributeCookie*& _cookie); +}; + + +#endif // AUTO_PACKAGE_ATTRIBUTES_H diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile index fb5a9ff0a0..9dade89c75 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Jamfile +++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile @@ -9,6 +9,7 @@ UsePrivateHeaders shared ; HAIKU_PACKAGE_FS_SOURCES = AttributeCookie.cpp AttributeDirectoryCookie.cpp + AutoPackageAttributes.cpp BlockBufferCacheKernel.cpp DebugSupport.cpp Dependency.cpp diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp index 632038d887..8804dcbd93 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp @@ -15,6 +15,7 @@ #include +#include "AutoPackageAttributes.h" #include "DebugSupport.h" #include "GlobalFactory.h" #include "Package.h" @@ -86,8 +87,11 @@ UnpackingAttributeCookie::Open(PackageNode* packageNode, const char* name, // get the attribute PackageNodeAttribute* attribute = packageNode->FindAttribute(name); - if (attribute == NULL) - return B_ENTRY_NOT_FOUND; + if (attribute == NULL) { + // We don't know the attribute -- maybe it's an auto-generated one. + return AutoPackageAttributes::OpenCookie(packageNode->GetPackage(), + name, openMode, _cookie); + } // allocate the cookie UnpackingAttributeCookie* cookie = new(std::nothrow) diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.cpp index 05f9b528f8..ab2d3db30f 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.cpp @@ -15,7 +15,8 @@ UnpackingAttributeDirectoryCookie::UnpackingAttributeDirectoryCookie( PackageNode* packageNode) : fPackageNode(packageNode), - fAttribute(NULL) + fAttribute(NULL), + fState(AUTO_PACKAGE_ATTRIBUTE_ENUM_FIRST) { if (fPackageNode != NULL) { fPackageNode->AcquireReference(); @@ -54,7 +55,7 @@ UnpackingAttributeDirectoryCookie::Read(dev_t volumeID, ino_t nodeID, dirent* previousEntry = NULL; - while (fAttribute != NULL) { + while (fState < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT || fAttribute != NULL) { // don't read more entries than requested if (count >= maxCount) break; @@ -73,9 +74,16 @@ UnpackingAttributeDirectoryCookie::Read(dev_t volumeID, ino_t nodeID, } } + // get the attribute name + const char* name; + if (fState < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT) { + name = AutoPackageAttributes::NameForAttribute( + (AutoPackageAttribute)fState); + } else + name = fAttribute->Name(); + // fill in the entry name -- checks whether the entry fits into the // buffer - const char* name = fAttribute->Name(); if (!set_dirent_name(buffer, bufferSize, name, strlen(name))) { if (count == 0) RETURN_ERROR(B_BUFFER_OVERFLOW); @@ -91,7 +99,10 @@ UnpackingAttributeDirectoryCookie::Read(dev_t volumeID, ino_t nodeID, bufferSize -= buffer->d_reclen; buffer = (dirent*)((addr_t)buffer + buffer->d_reclen); - fAttribute = fPackageNode->Attributes().GetNext(fAttribute); + if (fState < AUTO_PACKAGE_ATTRIBUTE_ENUM_COUNT) + fState++; + else + fAttribute = fPackageNode->Attributes().GetNext(fAttribute); } *_count = count; @@ -105,5 +116,7 @@ UnpackingAttributeDirectoryCookie::Rewind() if (fPackageNode != NULL) fAttribute = fPackageNode->Attributes().Head(); + fState = AUTO_PACKAGE_ATTRIBUTE_ENUM_FIRST; + return B_OK; } diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.h index a0ce184c90..e8ff28651e 100644 --- a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.h +++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeDirectoryCookie.h @@ -7,6 +7,7 @@ #include "AttributeDirectoryCookie.h" +#include "AutoPackageAttributes.h" struct dirent; @@ -32,6 +33,7 @@ public: private: PackageNode* fPackageNode; PackageNodeAttribute* fAttribute; + uint32 fState; }; From 42ae64447ea23718ead67819e15454c931c1882b Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 27 Jun 2011 01:45:06 +0200 Subject: [PATCH 0126/1170] Fix printf() format string warnings --- src/bin/package/command_dump.cpp | 12 ++++++++---- src/bin/package/command_list.cpp | 5 +++-- 2 files changed, 11 insertions(+), 6 deletions(-) diff --git a/src/bin/package/command_dump.cpp b/src/bin/package/command_dump.cpp index 8b625d3b6a..789c32c8ec 100644 --- a/src/bin/package/command_dump.cpp +++ b/src/bin/package/command_dump.cpp @@ -74,10 +74,12 @@ private: { switch (value.type) { case B_HPKG_ATTRIBUTE_TYPE_INT: - printf("%lld (%#llx)", value.signedInt, value.signedInt); + printf("%lld (%#llx)", (long long)value.signedInt, + (long long)value.signedInt); break; case B_HPKG_ATTRIBUTE_TYPE_UINT: - printf("%llu (%#llx)", value.unsignedInt, value.unsignedInt); + printf("%llu (%#llx)", (unsigned long long)value.unsignedInt, + (unsigned long long)value.unsignedInt); break; case B_HPKG_ATTRIBUTE_TYPE_STRING: printf("\"%s\"", value.string); @@ -85,12 +87,14 @@ private: case B_HPKG_ATTRIBUTE_TYPE_RAW: switch (value.encoding) { case B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE: - printf("data: size: %llu, inline", value.data.size); + printf("data: size: %llu, inline", + (unsigned long long)value.data.size); // TODO: Print the data bytes! break; case B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP: printf("data: size: %llu, offset: %llu", - value.data.size, value.data.offset); + (unsigned long long)value.data.size, + (unsigned long long)value.data.offset); break; default: break; diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp index 9bd831c727..1d4187f033 100644 --- a/src/bin/package/command_list.cpp +++ b/src/bin/package/command_list.cpp @@ -45,7 +45,7 @@ struct PackageContentListHandler : BPackageContentHandler { // name and size printf("%-*s", indentation < 32 ? 32 - indentation : 0, entry->Name()); - printf(" %8llu", entry->Data().UncompressedSize()); + printf(" %8llu", (unsigned long long)entry->Data().UncompressedSize()); // time struct tm* time = localtime(&entry->ModifiedTime().tv_sec); @@ -89,7 +89,8 @@ struct PackageContentListHandler : BPackageContentHandler { int indentation = fLevel * 2; printf("%*s<", indentation, ""); printf("%-*s %8llu", indentation < 31 ? 31 - indentation : 0, - attribute->Name(), attribute->Data().UncompressedSize()); + attribute->Name(), + (unsigned long long)attribute->Data().UncompressedSize()); uint32 type = attribute->Type(); if (isprint(type & 0xff) && isprint((type >> 8) & 0xff) From 5f039cf037b945f5efbaa790825496f9956ee25c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 27 Jun 2011 01:46:20 +0200 Subject: [PATCH 0127/1170] Fix copy'n'paste error for minor version part --- src/add-ons/kernel/file_systems/packagefs/Version.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/Version.cpp b/src/add-ons/kernel/file_systems/packagefs/Version.cpp index 8ab800c23b..30ab3aba46 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Version.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Version.cpp @@ -61,7 +61,7 @@ Version::Init(const char* major, const char* minor, const char* micro, } if (minor != NULL) { - fMinor = strdup(major); + fMinor = strdup(minor); if (fMinor == NULL) return B_NO_MEMORY; } From ed6d59a9a983cb031077b6d541576fc8efec1cfd Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 27 Jun 2011 01:53:01 +0200 Subject: [PATCH 0128/1170] Introduce a pre-release version component * The version string pattern is now: [.[.]][-
][-]
* Introduce B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE package
  attribute.
* Add "preRelease" field to BPackageVersionData.
* Add "preRelease" property to BPackageVersion and packagefs's Version.
* Adjust package reader and writer code accordingly.
---
 headers/os/package/PackageInfoAttributes.h    |  2 +-
 headers/os/package/PackageVersion.h           |  7 ++-
 headers/os/package/hpkg/HPKGDefs.h            |  1 +
 .../package/hpkg/PackageInfoAttributeValue.h  |  1 +
 .../kernel/file_systems/packagefs/Version.cpp | 62 +++++++++++++++----
 .../kernel/file_systems/packagefs/Version.h   |  8 ++-
 .../kernel/file_systems/packagefs/Volume.cpp  |  6 +-
 src/bin/package/command_list.cpp              |  2 +
 src/bin/package_repo/command_list.cpp         |  2 +
 src/kits/package/PackageInfo.cpp              | 42 +++++++++----
 src/kits/package/PackageVersion.cpp           | 51 +++++++++++----
 .../package/hpkg/PackageContentHandler.cpp    |  1 +
 src/kits/package/hpkg/ReaderImplBase.cpp      |  6 +-
 src/kits/package/hpkg/WriterImplBase.cpp      | 10 +++
 14 files changed, 156 insertions(+), 45 deletions(-)

diff --git a/headers/os/package/PackageInfoAttributes.h b/headers/os/package/PackageInfoAttributes.h
index a6cc093953..19bb8ff3f1 100644
--- a/headers/os/package/PackageInfoAttributes.h
+++ b/headers/os/package/PackageInfoAttributes.h
@@ -16,7 +16,7 @@ enum BPackageInfoAttributeID {
 	B_PACKAGE_INFO_VENDOR,		// e.g. "Haiku Project"
 	B_PACKAGE_INFO_PACKAGER,	// e-mail address preferred
 	B_PACKAGE_INFO_ARCHITECTURE,
-	B_PACKAGE_INFO_VERSION,		// [.[.]]
+	B_PACKAGE_INFO_VERSION,		// [.[.]][-
]-
 	B_PACKAGE_INFO_COPYRIGHTS,	// list
 	B_PACKAGE_INFO_LICENSES,	// list
 	B_PACKAGE_INFO_PROVIDES,	// list of resolvables this package provides,
diff --git a/headers/os/package/PackageVersion.h b/headers/os/package/PackageVersion.h
index 376d315197..e571b64757 100644
--- a/headers/os/package/PackageVersion.h
+++ b/headers/os/package/PackageVersion.h
@@ -25,20 +25,22 @@ public:
 									const BPackageVersionData& data);
 								BPackageVersion(const BString& major,
 									const BString& minor, const BString& micro,
-									uint8 release);
+									const BString& preRelease, uint8 release);
 
 			status_t			InitCheck() const;
 
 			const BString&		Major() const;
 			const BString&		Minor() const;
 			const BString&		Micro() const;
+			const BString&		PreRelease() const;
+									// "alpha3", "beta2", "rc1" or "" if final
 			uint8				Release() const;
 
 			BString				ToString() const;
 
 			void				SetTo(const BString& major,
 									const BString& minor, const BString& micro,
-									uint8 release);
+									const BString& preRelease, uint8 release);
 			void				Clear();
 
 			int					Compare(const BPackageVersion& other) const;
@@ -49,6 +51,7 @@ private:
 			BString				fMajor;
 			BString				fMinor;
 			BString				fMicro;
+			BString				fPreRelease;
 			uint8				fRelease;
 };
 
diff --git a/headers/os/package/hpkg/HPKGDefs.h b/headers/os/package/hpkg/HPKGDefs.h
index c77a1a8ccc..aee8d9406f 100644
--- a/headers/os/package/hpkg/HPKGDefs.h
+++ b/headers/os/package/hpkg/HPKGDefs.h
@@ -110,6 +110,7 @@ enum BHPKGAttributeID {
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_REPLACES			= 37,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR	= 38,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM			= 39,
+	B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE	= 40,
 	//
 	B_HPKG_ATTRIBUTE_ID_ENUM_COUNT,
 };
diff --git a/headers/os/package/hpkg/PackageInfoAttributeValue.h b/headers/os/package/hpkg/PackageInfoAttributeValue.h
index e2edc95e36..ab38858522 100644
--- a/headers/os/package/hpkg/PackageInfoAttributeValue.h
+++ b/headers/os/package/hpkg/PackageInfoAttributeValue.h
@@ -23,6 +23,7 @@ struct BPackageVersionData {
 			const char*			major;
 			const char*			minor;
 			const char*			micro;
+			const char*			preRelease;
 			uint8				release;
 };
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Version.cpp b/src/add-ons/kernel/file_systems/packagefs/Version.cpp
index 30ab3aba46..a9b212959c 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Version.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Version.cpp
@@ -10,6 +10,7 @@
 #include 
 #include 
 
+#include 
 #include 
 
 #include 
@@ -37,6 +38,7 @@ Version::Version()
 	fMajor(NULL),
 	fMinor(NULL),
 	fMicro(NULL),
+	fPreRelease(NULL),
 	fRelease(0)
 {
 }
@@ -47,12 +49,13 @@ Version::~Version()
 	free(fMajor);
 	free(fMinor);
 	free(fMicro);
+	free(fPreRelease);
 }
 
 
 status_t
 Version::Init(const char* major, const char* minor, const char* micro,
-	uint8 release)
+	const char* preRelease, uint8 release)
 {
 	if (major != NULL) {
 		fMajor = strdup(major);
@@ -72,6 +75,12 @@ Version::Init(const char* major, const char* minor, const char* micro,
 			return B_NO_MEMORY;
 	}
 
+	if (preRelease != NULL) {
+		fPreRelease = strdup(preRelease);
+		if (fPreRelease == NULL)
+			return B_NO_MEMORY;
+	}
+
 	fRelease = release;
 
 	return B_OK;
@@ -80,13 +89,13 @@ Version::Init(const char* major, const char* minor, const char* micro,
 
 /*static*/ status_t
 Version::Create(const char* major, const char* minor, const char* micro,
-	uint8 release, Version*& _version)
+	const char* preRelease, uint8 release, Version*& _version)
 {
 	Version* version = new(std::nothrow) Version;
 	if (version == NULL)
 		return B_NO_MEMORY;
 
-	status_t error = version->Init(major, minor, micro, release);
+	status_t error = version->Init(major, minor, micro, preRelease, release);
 	if (error != B_OK) {
 		delete version;
 		return error;
@@ -112,6 +121,21 @@ Version::Compare(const Version& other) const
 	if (cmp != 0)
 		return cmp;
 
+	// The pre-version works differently: The empty string is greater than any
+	// non-empty string (e.g. "R1" is newer than "R1-rc2"). So we catch the
+	// empty string cases first.
+	if (fPreRelease == NULL) {
+		if (other.fPreRelease != NULL)
+			return 1;
+	} else if (other.fPreRelease == NULL) {
+		return -1;
+	} else {
+		// both are non-null -- compare normally
+		cmp = BPrivate::NaturalCompare(fPreRelease, other.fPreRelease);
+		if (cmp != 0)
+			return cmp;
+	}
+
 	return (int)fRelease - other.fRelease;
 }
 
@@ -147,8 +171,8 @@ Version::ToString(char* buffer, size_t bufferSize) const
 {
 	// We need to normalize the version string somewhat. If a subpart is given,
 	// make sure that also the superparts are defined, using a placeholder. This
-	// avoids clashes, e.g. if one version defines only major and one only
-	// micro.
+	// avoids clashes, e.g. if one version defines major and minor and one only
+	// major and micro.
 	const char* major = fMajor;
 	const char* minor = fMinor;
 	const char* micro = fMicro;
@@ -158,16 +182,28 @@ Version::ToString(char* buffer, size_t bufferSize) const
 	if (minor != NULL && major == NULL)
 		major = kVersionPartPlaceholder;
 
-	if (micro != NULL) {
-		return snprintf(buffer, bufferSize, "%s.%s.%s-%u", major, minor, micro,
-			fRelease);
+	size_t size = strlcpy(buffer, major, bufferSize);
+
+	if (minor != NULL) {
+		size_t offset = std::min(bufferSize, size);
+		size += snprintf(buffer + offset, bufferSize - offset, ".%s", minor);
 	}
 
-	if (minor != NULL)
-		return snprintf(buffer, bufferSize, "%s.%s-%u", major, minor, fRelease);
+	if (micro != NULL) {
+		size_t offset = std::min(bufferSize, size);
+		size += snprintf(buffer + offset, bufferSize - offset, ".%s", micro);
+	}
 
-	if (major != NULL)
-		return snprintf(buffer, bufferSize, "%s-%u", major, fRelease);
+	if (fPreRelease != NULL) {
+		size_t offset = std::min(bufferSize, size);
+		size += snprintf(buffer + offset, bufferSize - offset, "-%s",
+			fPreRelease);
+	}
 
-	return snprintf(buffer, bufferSize, "%u", fRelease);
+	if (fRelease != 0) {
+		size_t offset = std::min(bufferSize, size);
+		size += snprintf(buffer + offset, bufferSize - offset, "-%u", fRelease);
+	}
+
+	return size;
 }
diff --git a/src/add-ons/kernel/file_systems/packagefs/Version.h b/src/add-ons/kernel/file_systems/packagefs/Version.h
index 1c72731215..a78beb0a03 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Version.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Version.h
@@ -19,11 +19,12 @@ public:
 								~Version();
 
 			status_t			Init(const char* major, const char* minor,
-									const char* micro, uint8 release);
+									const char* micro, const char* preRelease,
+									uint8 release);
 
 	static	status_t			Create(const char* major, const char* minor,
-									const char* micro, uint8 release,
-									Version*& _version);
+									const char* micro, const char* preRelease,
+									uint8 release, Version*& _version);
 
 			int					Compare(const Version& other) const;
 			bool				Compare(BPackageResolvableOperator op,
@@ -37,6 +38,7 @@ private:
 			char*				fMajor;
 			char*				fMinor;
 			char*				fMicro;
+			char*				fPreRelease;
 			uint8				fRelease;
 };
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 317676c722..1733b9a27c 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -294,7 +294,7 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
 				Version* version;
 				status_t error = Version::Create(value.version.major,
 					value.version.minor, value.version.micro,
-					value.version.release, version);
+					value.version.preRelease, value.version.release, version);
 				if (error != B_OK)
 					RETURN_ERROR(error);
 
@@ -312,7 +312,7 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
 						= value.resolvable.version;
 					status_t error = Version::Create(versionInfo.major,
 						versionInfo.minor, versionInfo.micro,
-						versionInfo.release, version);
+						versionInfo.preRelease, versionInfo.release, version);
 					if (error != B_OK)
 						RETURN_ERROR(error);
 				}
@@ -354,7 +354,7 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
 						= value.resolvableExpression.version;
 					status_t error = Version::Create(versionInfo.major,
 						versionInfo.minor, versionInfo.micro,
-						versionInfo.release, version);
+						versionInfo.preRelease, versionInfo.release, version);
 					if (error != B_OK)
 						RETURN_ERROR(error);
 
diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp
index 1d4187f033..64f57e456a 100644
--- a/src/bin/package/command_list.cpp
+++ b/src/bin/package/command_list.cpp
@@ -253,6 +253,8 @@ private:
 			printf(".%s", version.minor);
 		if (version.micro != NULL && version.micro[0] != '\0')
 			printf(".%s", version.micro);
+		if (version.preRelease != NULL && version.preRelease[0] != '\0')
+			printf("-%s", version.preRelease);
 		if (version.release > 0)
 			printf("-%d", version.release);
 	}
diff --git a/src/bin/package_repo/command_list.cpp b/src/bin/package_repo/command_list.cpp
index 1d91d4b303..ad290d2065 100644
--- a/src/bin/package_repo/command_list.cpp
+++ b/src/bin/package_repo/command_list.cpp
@@ -226,6 +226,8 @@ private:
 			printf(".%s", version.minor);
 		if (version.micro != NULL && version.micro[0] != '\0')
 			printf(".%s", version.micro);
+		if (version.preRelease != NULL && version.preRelease[0] != '\0')
+			printf("-%s", version.preRelease);
 		if (version.release > 0)
 			printf("-%d", version.release);
 	}
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 4c42ad6f8c..9fd699fc67 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -349,23 +349,43 @@ BPackageInfo::Parser::_ParseVersionValue(BPackageVersion* value,
 	if (word.type != TOKEN_WORD)
 		throw ParseError("expected word (a version)", word.pos);
 
+	// get the release number
 	uint8 release = 0;
 	int32 lastDashPos = word.text.FindLast('-');
-	if (lastDashPos < 0) {
-		if (!releaseIsOptional) {
-			throw ParseError("expected release number (- suffix)",
+	if (lastDashPos >= 0) {
+		// Might be either the release number or, if that is optional, a
+		// pre-release. The former always is a number, the latter starts with a
+		// non-digit.
+		if (isdigit(word.text[lastDashPos + 1])) {
+			int number = atoi(word.text.String() + lastDashPos + 1);
+			if (number <= 0 || number > 99) {
+				throw ParseError("release number must be from 1-99",
+					word.pos + word.text.Length());
+			}
+			release = number;
+			word.text.Truncate(lastDashPos);
+			lastDashPos = word.text.FindLast('-');
+		}
+	}
+
+	if (release == 0 && !releaseIsOptional) {
+		throw ParseError("expected release number (- suffix)",
+			word.pos + word.text.Length());
+	}
+
+	// get the pre-release string
+	BString preRelease;
+	if (lastDashPos >= 0) {
+		if (isdigit(word.text[lastDashPos + 1])) {
+			throw ParseError("pre-release number must not start with a digit",
 				word.pos + word.text.Length());
 		}
-	} else {
-		int number = atoi(word.text.String() + lastDashPos + 1);
-		if (number <= 0 || number > 99) {
-			throw ParseError("release number must be from 1-99",
-				word.pos + word.text.Length());
-		}
-		release = number;
+
+		word.text.CopyInto(preRelease, lastDashPos + 1, word.text.Length());
 		word.text.Truncate(lastDashPos);
 	}
 
+	// get major, minor, and micro strings
 	BString major;
 	BString minor;
 	BString micro;
@@ -387,7 +407,7 @@ BPackageInfo::Parser::_ParseVersionValue(BPackageVersion* value,
 		}
 	}
 
-	value->SetTo(major, minor, micro, release);
+	value->SetTo(major, minor, micro, preRelease, release);
 }
 
 
diff --git a/src/kits/package/PackageVersion.cpp b/src/kits/package/PackageVersion.cpp
index 73e3c03ce3..2c1e53c2d6 100644
--- a/src/kits/package/PackageVersion.cpp
+++ b/src/kits/package/PackageVersion.cpp
@@ -29,17 +29,19 @@ BPackageVersion::BPackageVersion(const BPackageVersionData& data)
 	fMajor(data.major),
 	fMinor(data.minor),
 	fMicro(data.micro),
+	fPreRelease(data.preRelease),
 	fRelease(data.release)
 {
 }
 
 
 BPackageVersion::BPackageVersion(const BString& major, const BString& minor,
-	const BString& micro, uint8 release)
+	const BString& micro, const BString& preRelease, uint8 release)
 	:
 	fMajor(major),
 	fMinor(minor),
 	fMicro(micro),
+	fPreRelease(preRelease),
 	fRelease(release)
 {
 }
@@ -73,6 +75,13 @@ BPackageVersion::Micro() const
 }
 
 
+const BString&
+BPackageVersion::PreRelease() const
+{
+	return fPreRelease;
+}
+
+
 uint8
 BPackageVersion::Release() const
 {
@@ -83,17 +92,32 @@ BPackageVersion::Release() const
 int
 BPackageVersion::Compare(const BPackageVersion& other) const
 {
-	int majorDiff = NaturalCompare(fMajor.String(), other.fMajor.String());
-	if (majorDiff != 0)
-		return majorDiff;
+	int diff = NaturalCompare(fMajor.String(), other.fMajor.String());
+	if (diff != 0)
+		return diff;
 
-	int minorDiff = NaturalCompare(fMinor.String(), other.fMinor.String());
-	if (minorDiff != 0)
-		return minorDiff;
+	diff = NaturalCompare(fMinor.String(), other.fMinor.String());
+	if (diff != 0)
+		return diff;
 
-	int microDiff = NaturalCompare(fMicro.String(), other.fMicro.String());
-	if (microDiff != 0)
-		return microDiff;
+	diff = NaturalCompare(fMicro.String(), other.fMicro.String());
+	if (diff != 0)
+		return diff;
+
+	// The pre-version works differently: The empty string is greater than any
+	// non-empty string (e.g. "R1" is newer than "R1-rc2"). So we catch the
+	// empty string cases first.
+	if (fPreRelease.IsEmpty()) {
+		if (!other.fPreRelease.IsEmpty())
+			return 1;
+	} else if (other.fPreRelease.IsEmpty()) {
+		return -1;
+	} else {
+		// both are non-null -- compare normally
+		diff = NaturalCompare(fPreRelease.String(), other.fPreRelease.String());
+		if (diff != 0)
+			return diff;
+	}
 
 	return (int)fRelease - (int)other.fRelease;
 }
@@ -110,6 +134,9 @@ BPackageVersion::ToString() const
 			string << '.' << fMicro;
 	}
 
+	if (!fPreRelease.IsEmpty())
+		string << '-' << fPreRelease;
+
 	if (fRelease > 0)
 		string << '-' << fRelease;
 
@@ -119,11 +146,12 @@ BPackageVersion::ToString() const
 
 void
 BPackageVersion::SetTo(const BString& major, const BString& minor,
-	const BString& micro, uint8 release)
+	const BString& micro, const BString& preRelease, uint8 release)
 {
 	fMajor = major;
 	fMinor = minor;
 	fMicro = micro;
+	fPreRelease = preRelease;
 	fRelease = release;
 }
 
@@ -134,6 +162,7 @@ BPackageVersion::Clear()
 	fMajor.Truncate(0);
 	fMinor.Truncate(0);
 	fMicro.Truncate(0);
+	fPreRelease.Truncate(0);
 	fRelease = 0;
 }
 
diff --git a/src/kits/package/hpkg/PackageContentHandler.cpp b/src/kits/package/hpkg/PackageContentHandler.cpp
index c981f59d4c..8dc47c2a92 100644
--- a/src/kits/package/hpkg/PackageContentHandler.cpp
+++ b/src/kits/package/hpkg/PackageContentHandler.cpp
@@ -56,6 +56,7 @@ static const char* kAttributeNames[B_HPKG_ATTRIBUTE_ID_ENUM_COUNT + 1] = {
 	"package:replaces",
 	"package:resolvable.operator",
 	"package:checksum",
+	"package:version.prerelease",
 	NULL
 };
 
diff --git a/src/kits/package/hpkg/ReaderImplBase.cpp b/src/kits/package/hpkg/ReaderImplBase.cpp
index c10b5e0fda..e0fbe71389 100644
--- a/src/kits/package/hpkg/ReaderImplBase.cpp
+++ b/src/kits/package/hpkg/ReaderImplBase.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
  * Copyright 2011, Oliver Tappe 
  * Distributed under the terms of the MIT License.
  */
@@ -127,6 +127,10 @@ ReaderImplBase::PackageVersionAttributeHandler::HandleAttribute(
 			fPackageVersionData.micro = value.string;
 			break;
 
+		case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE:
+			fPackageVersionData.preRelease = value.string;
+			break;
+
 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_RELEASE:
 			fPackageVersionData.release = value.unsignedInt;
 			break;
diff --git a/src/kits/package/hpkg/WriterImplBase.cpp b/src/kits/package/hpkg/WriterImplBase.cpp
index 27e47bc608..c3ee95aa15 100644
--- a/src/kits/package/hpkg/WriterImplBase.cpp
+++ b/src/kits/package/hpkg/WriterImplBase.cpp
@@ -523,6 +523,16 @@ WriterImplBase::RegisterPackageVersion(PackageAttributeList& attributeList,
 		}
 	}
 
+	if (!version.PreRelease().IsEmpty()) {
+		PackageAttribute* preRelease = new PackageAttribute(
+			B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE,
+			B_HPKG_ATTRIBUTE_TYPE_STRING,
+			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
+		preRelease->string
+			= fPackageStringCache.Get(version.PreRelease().String());
+		versionMajor->children.Add(preRelease);
+	}
+
 	if (version.Release() != 0) {
 		PackageAttribute* versionRelease = new PackageAttribute(
 			B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_RELEASE,

From e1a393153da8a44f5e30f67e1276f88b2cf1ba16 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 01:55:03 +0200
Subject: [PATCH 0129/1170] Adjust system package versions

They all use package and provides version "R1-alpha3_pm-1", now.
---
 src/data/package_infos/haiku           | 4 ++--
 src/data/package_infos/haiku-devel     | 4 ++--
 src/data/package_infos/haiku-userguide | 4 ++--
 src/data/package_infos/haiku-welcome   | 4 ++--
 src/data/package_infos/makefile-engine | 4 ++--
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku
index 4fc4b09375..a7be934c94 100644
--- a/src/data/package_infos/haiku
+++ b/src/data/package_infos/haiku
@@ -1,5 +1,5 @@
 name = Haiku
-version = R1.pm1-1
+version = R1-alpha3_pm-1
 architecture = x86_gcc2
 summary = "The Haiku base system"
 description = "The Haiku base system includes all system core software, like
@@ -12,7 +12,7 @@ copyright = "2001-2011 Haiku, Inc. et al"
 licenses = [ "MIT" ]
 
 provides = [
-	haiku=R1.pm1-1
+	haiku=R1-alpha3_pm-1
 ]
 
 requires = [
diff --git a/src/data/package_infos/haiku-devel b/src/data/package_infos/haiku-devel
index b3b5b8e3a0..efc5f72047 100644
--- a/src/data/package_infos/haiku-devel
+++ b/src/data/package_infos/haiku-devel
@@ -1,5 +1,5 @@
 name = haiku-devel
-version = 1-1
+version = R1-alpha3_pm-1
 architecture = x86_gcc2
 summary = "The Haiku base system development files"
 description = "The package contains all files associated with the base system
@@ -13,7 +13,7 @@ copyright = "2001-2011 Haiku, Inc. et al"
 licenses = [ "MIT" ]
 
 provides = [
-	haiku-devel
+	haiku-devel=R1-alpha3_pm-1
 ]
 
 requires = [
diff --git a/src/data/package_infos/haiku-userguide b/src/data/package_infos/haiku-userguide
index 9829a15477..abfb63b7ac 100644
--- a/src/data/package_infos/haiku-userguide
+++ b/src/data/package_infos/haiku-userguide
@@ -1,5 +1,5 @@
 name = haiku-userguide
-version = 1-1
+version = R1-alpha3_pm-1
 architecture = any
 summary = "The Haiku user documentation"
 description = "The Haiku user documentation."
@@ -11,7 +11,7 @@ copyright = "2001-2011 Haiku, Inc. et al"
 licenses = [ "MIT" ]
 
 provides = [
-	haiku-userguide
+	haiku-userguide=R1-alpha3_pm-1
 ]
 
 requires = [
diff --git a/src/data/package_infos/haiku-welcome b/src/data/package_infos/haiku-welcome
index 23fcf51329..306b331ad3 100644
--- a/src/data/package_infos/haiku-welcome
+++ b/src/data/package_infos/haiku-welcome
@@ -1,5 +1,5 @@
 name = haiku-welcome
-version = 1-1
+version = R1-alpha3_pm-1
 architecture = any
 summary = "The Haiku welcome documentation"
 description = "The Haiku welcome documentation for new users."
@@ -11,7 +11,7 @@ copyright = "2001-2011 Haiku, Inc. et al"
 licenses = [ "MIT" ]
 
 provides = [
-	haiku-welcome
+	haiku-welcome=R1-alpha3_pm-1
 ]
 
 requires = [
diff --git a/src/data/package_infos/makefile-engine b/src/data/package_infos/makefile-engine
index ac2c65f3bd..801f5c5428 100644
--- a/src/data/package_infos/makefile-engine
+++ b/src/data/package_infos/makefile-engine
@@ -1,5 +1,5 @@
 name = makefile-engine
-version = 1-1
+version = R1-alpha3_pm-1
 architecture = any
 summary = "The makefile engine"
 description = "A simple generic makefile engine and makefile template."
@@ -11,7 +11,7 @@ copyright = "? Be Inc. 2001-2011 Haiku, Inc."
 licenses = [ "MIT" ]
 
 provides = [
-	makefile-engine
+	makefile-engine=R1-alpha3_pm-1
 ]
 
 requires = [

From b85a2681d6cc4dfba1b85af54d780e463a69b04e Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 02:29:27 +0200
Subject: [PATCH 0130/1170] Coding style: Fix indentation

---
 src/kits/package/PackageInfo.cpp | 40 ++++++++++++++++----------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 9fd699fc67..aac8492f08 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -536,39 +536,39 @@ BPackageInfo::Parser::_ParseResolvableList(
 
 			BPackageResolvableType type = B_PACKAGE_RESOLVABLE_TYPE_DEFAULT;
 			int32 colonPos = token.text.FindFirst(':');
-		if (colonPos >= 0) {
+			if (colonPos >= 0) {
 				BString typeName(token.text, colonPos);
-			for (int i = 0; i < B_PACKAGE_RESOLVABLE_TYPE_ENUM_COUNT; ++i) {
+				for (int i = 0; i < B_PACKAGE_RESOLVABLE_TYPE_ENUM_COUNT; ++i) {
 					if (typeName.ICompare(BPackageResolvable::kTypeNames[i])
 							== 0) {
-					type = (BPackageResolvableType)i;
-					break;
+						type = (BPackageResolvableType)i;
+						break;
+					}
 				}
-			}
-			if (type == B_PACKAGE_RESOLVABLE_TYPE_DEFAULT) {
-				BString error("resolvable type (:) must be one of [");
+				if (type == B_PACKAGE_RESOLVABLE_TYPE_DEFAULT) {
+					BString error("resolvable type (:) must be one of [");
 					for (int i = 1; i < B_PACKAGE_RESOLVABLE_TYPE_ENUM_COUNT;
-						++i) {
-					if (i > 1)
-						error << ",";
-					error << BPackageResolvable::kTypeNames[i];
-				}
-				error << "]";
+							++i) {
+						if (i > 1)
+							error << ",";
+						error << BPackageResolvable::kTypeNames[i];
+					}
+					error << "]";
 					throw ParseError(error, token.pos);
+				}
 			}
-		}
 
-		BPackageVersion version;
+			BPackageVersion version;
 			Token op = parser._NextToken();
-		if (op.type == TOKEN_OPERATOR_ASSIGN)
+			if (op.type == TOKEN_OPERATOR_ASSIGN)
 				parser._ParseVersionValue(&version, true);
-		else if (op.type == TOKEN_COMMA || op.type == TOKEN_CLOSE_BRACKET)
+			else if (op.type == TOKEN_COMMA || op.type == TOKEN_CLOSE_BRACKET)
 				parser._RewindTo(op);
-		else
-			throw ParseError("expected '=', comma or ']'", op.pos);
+			else
+				throw ParseError("expected '=', comma or ']'", op.pos);
 
 			value->AddItem(new BPackageResolvable(token.text, type, version));
-	}
+		}
 	} resolvableParser(*this, value);
 
 	_ParseList(resolvableParser);

From 3a56aaeeb9f478dff7ab161deade3a9e71acccc5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 03:47:12 +0200
Subject: [PATCH 0131/1170] BPackageResolvableData: Compatible version field

Add fields haveCompatibleVersion and compatibleVersion. This allows us
to have a minimum version a resolvable is backwards compatible with.
---
 headers/os/package/hpkg/PackageInfoAttributeValue.h | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/headers/os/package/hpkg/PackageInfoAttributeValue.h b/headers/os/package/hpkg/PackageInfoAttributeValue.h
index ab38858522..40055e08b3 100644
--- a/headers/os/package/hpkg/PackageInfoAttributeValue.h
+++ b/headers/os/package/hpkg/PackageInfoAttributeValue.h
@@ -32,7 +32,9 @@ struct BPackageResolvableData {
 			BPackageResolvableType	type;
 			const char*			name;
 			bool				haveVersion;
+			bool				haveCompatibleVersion;
 			BPackageVersionData	version;
+			BPackageVersionData	compatibleVersion;
 };
 
 

From c2f56ca020107fdff0c1148fb8429d3431e655c7 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 03:48:00 +0200
Subject: [PATCH 0132/1170] BPackageResolvable: Add compatibleVersion property

---
 headers/os/package/PackageResolvable.h | 15 +++++++++++----
 src/kits/package/PackageResolvable.cpp | 23 +++++++++++++++++++----
 2 files changed, 30 insertions(+), 8 deletions(-)

diff --git a/headers/os/package/PackageResolvable.h b/headers/os/package/PackageResolvable.h
index 18cf29e102..e26daa4673 100644
--- a/headers/os/package/PackageResolvable.h
+++ b/headers/os/package/PackageResolvable.h
@@ -23,10 +23,11 @@ using BHPKG::BPackageResolvableData;
 
 /*
  * Defines a resolvable (something other packages can depend upon).
- * Each resolvable is defined as a name (with an optional type prefix)
- * and an optional version.
+ * Each resolvable is defined as a name (with an optional type prefix),
+ * an optional version, and an optional compatibility version (the least
+ * version the resolvable is backwards compatible with).
  *
- * 		resolvable ::= ['=']
+ * 		resolvable ::= ['=']['compat' '>=' ]
  * 		name       ::= [':']
  * 		type       ::= 'lib' | 'cmd' | 'app' | 'add_on'
  *
@@ -39,7 +40,7 @@ using BHPKG::BPackageResolvableData;
  * String examples:
  * 		haiku=r1
  * 		lib:libssl=0.9.8i
- * 		subversion=1.5
+ * 		subversion=1.5 compat>=1.0
  * 		cmd:svn
  */
 class BPackageResolvable {
@@ -51,6 +52,8 @@ public:
 									BPackageResolvableType type
 										= B_PACKAGE_RESOLVABLE_TYPE_DEFAULT,
 									const BPackageVersion& version
+										= BPackageVersion(),
+									const BPackageVersion& compatibleVersion
 										= BPackageVersion());
 
 			status_t			InitCheck() const;
@@ -58,6 +61,7 @@ public:
 			const BString&		Name() const;
 			BPackageResolvableType	Type() const;
 			const BPackageVersion& Version() const;
+			const BPackageVersion& CompatibleVersion() const;
 
 			BString				ToString() const;
 
@@ -65,6 +69,8 @@ public:
 									BPackageResolvableType type
 										= B_PACKAGE_RESOLVABLE_TYPE_DEFAULT,
 									const BPackageVersion& version
+										= BPackageVersion(),
+									const BPackageVersion& compatibleVersion
 										= BPackageVersion());
 			void				Clear();
 
@@ -75,6 +81,7 @@ private:
 			BString				fName;
 			BPackageResolvableType	fType;
 			BPackageVersion		fVersion;
+			BPackageVersion		fCompatibleVersion;
 };
 
 
diff --git a/src/kits/package/PackageResolvable.cpp b/src/kits/package/PackageResolvable.cpp
index e04915c2cf..3c1c632ffe 100644
--- a/src/kits/package/PackageResolvable.cpp
+++ b/src/kits/package/PackageResolvable.cpp
@@ -33,17 +33,20 @@ BPackageResolvable::BPackageResolvable(const BPackageResolvableData& data)
 	:
 	fName(data.name),
 	fType(data.type),
-	fVersion(data.version)
+	fVersion(data.version),
+	fCompatibleVersion(data.compatibleVersion)
 {
 }
 
 
 BPackageResolvable::BPackageResolvable(const BString& name,
-	BPackageResolvableType type, const BPackageVersion& version)
+	BPackageResolvableType type, const BPackageVersion& version,
+	const BPackageVersion& compatibleVersion)
 	:
 	fName(name),
 	fType(type),
-	fVersion(version)
+	fVersion(version),
+	fCompatibleVersion(compatibleVersion)
 {
 }
 
@@ -76,6 +79,13 @@ BPackageResolvable::Version() const
 }
 
 
+const BPackageVersion&
+BPackageResolvable::CompatibleVersion() const
+{
+	return fCompatibleVersion;
+}
+
+
 BString
 BPackageResolvable::ToString() const
 {
@@ -85,17 +95,21 @@ BPackageResolvable::ToString() const
 	if (fVersion.InitCheck() == B_OK)
 		string << '=' << fVersion.ToString();
 
+	if (fCompatibleVersion.InitCheck() == B_OK)
+		string << " compat>=" << fCompatibleVersion.ToString();
+
 	return string;
 }
 
 
 void
 BPackageResolvable::SetTo(const BString& name, BPackageResolvableType type,
-	const BPackageVersion& version)
+	const BPackageVersion& version, const BPackageVersion& compatibleVersion)
 {
 	fName = name;
 	fType = type;
 	fVersion = version;
+	fCompatibleVersion = compatibleVersion;
 }
 
 
@@ -104,6 +118,7 @@ BPackageResolvable::Clear()
 {
 	fName.Truncate(0);
 	fVersion.Clear();
+	fCompatibleVersion.Clear();
 }
 
 

From 22e1ec0e3064a91643db5e4a62a2e35ffb3a9f11 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 03:49:12 +0200
Subject: [PATCH 0133/1170] Add package attribute for compatible version

---
 headers/os/package/hpkg/HPKGDefs.h              | 1 +
 src/kits/package/hpkg/PackageContentHandler.cpp | 1 +
 2 files changed, 2 insertions(+)

diff --git a/headers/os/package/hpkg/HPKGDefs.h b/headers/os/package/hpkg/HPKGDefs.h
index aee8d9406f..2ea360e044 100644
--- a/headers/os/package/hpkg/HPKGDefs.h
+++ b/headers/os/package/hpkg/HPKGDefs.h
@@ -111,6 +111,7 @@ enum BHPKGAttributeID {
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_RESOLVABLE_OPERATOR	= 38,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM			= 39,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE	= 40,
+	B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_COMPATIBLE	= 41,
 	//
 	B_HPKG_ATTRIBUTE_ID_ENUM_COUNT,
 };
diff --git a/src/kits/package/hpkg/PackageContentHandler.cpp b/src/kits/package/hpkg/PackageContentHandler.cpp
index 8dc47c2a92..8abfc1d996 100644
--- a/src/kits/package/hpkg/PackageContentHandler.cpp
+++ b/src/kits/package/hpkg/PackageContentHandler.cpp
@@ -57,6 +57,7 @@ static const char* kAttributeNames[B_HPKG_ATTRIBUTE_ID_ENUM_COUNT + 1] = {
 	"package:resolvable.operator",
 	"package:checksum",
 	"package:version.prerelease",
+	"package:provides.compatible",
 	NULL
 };
 

From 2db69df113612ae80e37d3d0fee6657ea4a60d50 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 03:53:12 +0200
Subject: [PATCH 0134/1170] Support for parsing the compatible version

In the .PackageInfo the compatible version for a resolvable can
optionally be given after the resolvable version via
"'compat[ible]' '>=' ".
---
 src/kits/package/PackageInfo.cpp | 18 +++++++++++++++++-
 1 file changed, 17 insertions(+), 1 deletion(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index aac8492f08..8f7a6f510a 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -558,6 +558,7 @@ BPackageInfo::Parser::_ParseResolvableList(
 				}
 			}
 
+			// parse version
 			BPackageVersion version;
 			Token op = parser._NextToken();
 			if (op.type == TOKEN_OPERATOR_ASSIGN)
@@ -567,7 +568,22 @@ BPackageInfo::Parser::_ParseResolvableList(
 			else
 				throw ParseError("expected '=', comma or ']'", op.pos);
 
-			value->AddItem(new BPackageResolvable(token.text, type, version));
+			// parse compatible version
+			BPackageVersion compatibleVersion;
+			Token compatible = parser._NextToken();
+			if (compatible.type == TOKEN_WORD
+				&& (compatible.text == "compat"
+					|| compatible.text == "compatible")) {
+				op = parser._NextToken();
+				if (op.type == TOKEN_OPERATOR_GREATER_EQUAL) {
+					parser._ParseVersionValue(&compatibleVersion, true);
+				} else
+					parser._RewindTo(compatible);
+			} else
+				parser._RewindTo(compatible);
+
+			value->AddItem(new BPackageResolvable(token.text, type, version,
+				compatibleVersion));
 		}
 	} resolvableParser(*this, value);
 

From b2709d8a0abeca4e08ed63d2f421ffac320e1a29 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 03:57:25 +0200
Subject: [PATCH 0135/1170] Write resolvable compatible version to the package

To avoid a clash with the regular version or an extra attribute level we
use the "package:provides.compatible" package attribute instead of
"package:version.major".
---
 headers/private/package/hpkg/WriterImplBase.h |  8 +++++++-
 src/kits/package/hpkg/WriterImplBase.cpp      | 12 ++++++++++--
 2 files changed, 17 insertions(+), 3 deletions(-)

diff --git a/headers/private/package/hpkg/WriterImplBase.h b/headers/private/package/hpkg/WriterImplBase.h
index 43ff745263..8108624543 100644
--- a/headers/private/package/hpkg/WriterImplBase.h
+++ b/headers/private/package/hpkg/WriterImplBase.h
@@ -154,7 +154,9 @@ protected:
 									const BPackageInfo& packageInfo);
 			void				RegisterPackageVersion(
 									PackageAttributeList& attributeList,
-									const BPackageVersion& version);
+									const BPackageVersion& version,
+									BHPKGAttributeID attributeID
+										= kDefaultVersionAttributeID);
 			void				RegisterPackageResolvableExpressionList(
 									PackageAttributeList& attributeList,
 									const BObjectList<
@@ -198,6 +200,10 @@ protected:
 
 	inline	void				SetFinished(bool finished);
 
+private:
+	static const BHPKGAttributeID kDefaultVersionAttributeID
+		= B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR;
+
 private:
 			void				_WritePackageAttributes(
 									const PackageAttributeList& attributes);
diff --git a/src/kits/package/hpkg/WriterImplBase.cpp b/src/kits/package/hpkg/WriterImplBase.cpp
index c3ee95aa15..f90f05ee57 100644
--- a/src/kits/package/hpkg/WriterImplBase.cpp
+++ b/src/kits/package/hpkg/WriterImplBase.cpp
@@ -437,6 +437,8 @@ WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList,
 	for (int i = 0; i < providesList.CountItems(); ++i) {
 		BPackageResolvable* resolvable = providesList.ItemAt(i);
 		bool hasVersion = resolvable->Version().InitCheck() == B_OK;
+		bool hasCompatibleVersion
+			= resolvable->CompatibleVersion().InitCheck() == B_OK;
 
 		PackageAttribute* provides = new PackageAttribute(
 			B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES, B_HPKG_ATTRIBUTE_TYPE_STRING,
@@ -452,6 +454,12 @@ WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList,
 
 		if (hasVersion)
 			RegisterPackageVersion(provides->children, resolvable->Version());
+
+		if (hasCompatibleVersion) {
+			RegisterPackageVersion(provides->children,
+				resolvable->CompatibleVersion(),
+				B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_COMPATIBLE);
+		}
 	}
 
 	// requires list
@@ -495,10 +503,10 @@ WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList,
 
 void
 WriterImplBase::RegisterPackageVersion(PackageAttributeList& attributeList,
-	const BPackageVersion& version)
+	const BPackageVersion& version, BHPKGAttributeID attributeID)
 {
 	PackageAttribute* versionMajor = new PackageAttribute(
-		B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR, B_HPKG_ATTRIBUTE_TYPE_STRING,
+		attributeID, B_HPKG_ATTRIBUTE_TYPE_STRING,
 		B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
 	versionMajor->string = fPackageStringCache.Get(version.Major().String());
 	attributeList.Add(versionMajor);

From ee9c9351a721c98f43475854643a3a192af763b5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 03:58:18 +0200
Subject: [PATCH 0136/1170] Support for reading compatible version attribute

---
 src/kits/package/hpkg/ReaderImplBase.cpp | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/kits/package/hpkg/ReaderImplBase.cpp b/src/kits/package/hpkg/ReaderImplBase.cpp
index e0fbe71389..ab3f7b461a 100644
--- a/src/kits/package/hpkg/ReaderImplBase.cpp
+++ b/src/kits/package/hpkg/ReaderImplBase.cpp
@@ -199,6 +199,19 @@ ReaderImplBase::PackageResolvableAttributeHandler::HandleAttribute(
 			}
 			break;
 
+		case B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_COMPATIBLE:
+			fPackageInfoValue.resolvable.haveCompatibleVersion = true;
+			fPackageInfoValue.resolvable.compatibleVersion.major = value.string;
+			if (_handler != NULL) {
+				*_handler
+					= new(std::nothrow) PackageVersionAttributeHandler(
+						fPackageInfoValue,
+						fPackageInfoValue.resolvable.compatibleVersion, false);
+				if (*_handler == NULL)
+					return B_NO_MEMORY;
+			}
+			break;
+
 		default:
 			context->errorOutput->PrintError("Error: Invalid package "
 				"attribute section: unexpected package attribute id %d "

From 71120ca73d3d16c1256dc57de00cfc0832b1b637 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 03:58:58 +0200
Subject: [PATCH 0137/1170] Print the resolvables' compatible version

---
 src/bin/package/command_list.cpp | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp
index 64f57e456a..82a5ee53ef 100644
--- a/src/bin/package/command_list.cpp
+++ b/src/bin/package/command_list.cpp
@@ -170,6 +170,11 @@ struct PackageContentListHandler : BPackageContentHandler {
 					printf(" = ");
 					_PrintPackageVersion(value.resolvable.version);
 				}
+				if (value.resolvable.haveCompatibleVersion) {
+					printf(" (compatible >= ");
+					_PrintPackageVersion(value.resolvable.compatibleVersion);
+					printf(")");
+				}
 				printf("\n");
 				break;
 

From 89f1807be6ffdd03aa60603326aad9bfc6303619 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 03:59:27 +0200
Subject: [PATCH 0138/1170] Add compatible version support to packagefs

---
 .../file_systems/packagefs/Dependency.cpp     | 20 +++++++++++++++++++
 .../file_systems/packagefs/Dependency.h       |  2 ++
 .../file_systems/packagefs/Resolvable.cpp     |  8 ++++++--
 .../file_systems/packagefs/Resolvable.h       | 11 +++++++---
 .../packagefs/ResolvableFamily.cpp            |  4 +++-
 .../kernel/file_systems/packagefs/Volume.cpp  | 16 ++++++++++++++-
 6 files changed, 54 insertions(+), 7 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp
index a08ea6dd4c..8bf1c17741 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp
@@ -60,3 +60,23 @@ Dependency::ResolvableVersionMatches(Version* resolvableVersion) const
 	return resolvableVersion != NULL
 		&& fVersion->Compare(fVersionOperator, *resolvableVersion);
 }
+
+
+bool
+Dependency::ResolvableCompatibleVersionMatches(Version* resolvableVersion) const
+{
+	if (fVersion == NULL)
+		return true;
+
+	// Only compare the versions, if the operator indicates that our version is
+	// some kind of minimum required version. Only in that case the resolvable's
+	// actual version is required to be greater (or equal) and the backwards
+	// compatibility check makes sense.
+	if (fVersionOperator == B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL
+		|| fVersionOperator == B_PACKAGE_RESOLVABLE_OP_GREATER) {
+		return resolvableVersion != NULL
+			&& fVersion->Compare(fVersionOperator, *resolvableVersion);
+	}
+
+	return true;
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.h b/src/add-ons/kernel/file_systems/packagefs/Dependency.h
index 0da11cc3d1..bab31c2d5b 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Dependency.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.h
@@ -49,6 +49,8 @@ public:
 									{ return fResolvable; }
 			bool				ResolvableVersionMatches(
 									Version* resolvableVersion) const;
+			bool				ResolvableCompatibleVersionMatches(
+									Version* resolvableVersion) const;
 
 			const char*			Name() const	{ return fName; }
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp b/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp
index 4af0036c42..43a7414d0f 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Resolvable.cpp
@@ -16,7 +16,8 @@ Resolvable::Resolvable(::Package* package)
 	fPackage(package),
 	fFamily(NULL),
 	fName(NULL),
-	fVersion(NULL)
+	fVersion(NULL),
+	fCompatibleVersion(NULL)
 {
 }
 
@@ -25,13 +26,16 @@ Resolvable::~Resolvable()
 {
 	free(fName);
 	delete fVersion;
+	delete fCompatibleVersion;
 }
 
 
 status_t
-Resolvable::Init(const char* name, ::Version* version)
+Resolvable::Init(const char* name, ::Version* version,
+	::Version* compatibleVersion)
 {
 	fVersion = version;
+	fCompatibleVersion = compatibleVersion;
 
 	fName = strdup(name);
 	if (fName == NULL)
diff --git a/src/add-ons/kernel/file_systems/packagefs/Resolvable.h b/src/add-ons/kernel/file_systems/packagefs/Resolvable.h
index 302765e2cf..87d4509f61 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Resolvable.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Resolvable.h
@@ -24,9 +24,11 @@ public:
 								Resolvable(::Package* package);
 	virtual						~Resolvable();
 
-			status_t			Init(const char* name, ::Version* version);
-									// version is optional; object takes over
-									// ownership (even in case of error)
+			status_t			Init(const char* name, ::Version* version,
+									::Version* compatibleVersion);
+									// version and compatibleVersion are
+									// optional; object takes over ownership
+									// (even in case of error)
 
 			::Package*			Package() const	{ return fPackage; }
 
@@ -37,6 +39,8 @@ public:
 
 			const char*			Name() const	{ return fName; }
 			::Version*			Version() const	{ return fVersion; }
+			::Version*			CompatibleVersion() const
+									{ return fCompatibleVersion; }
 
 			void				AddDependency(Dependency* dependency);
 			void				RemoveDependency(Dependency* dependency);
@@ -48,6 +52,7 @@ private:
 			ResolvableFamily*	fFamily;
 			char*				fName;
 			::Version*			fVersion;
+			::Version*			fCompatibleVersion;
 			ResolvableDependencyList fDependencies;
 
 public:	// conceptually package private
diff --git a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp
index c237cd59db..f396eb6b03 100644
--- a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp
@@ -54,7 +54,9 @@ ResolvableFamily::ResolveDependency(Dependency* dependency)
 {
 	for (FamilyResolvableList::Iterator it = fResolvables.GetIterator();
 			Resolvable* resolvable = it.Next();) {
-		if (dependency->ResolvableVersionMatches(resolvable->Version())) {
+		if (dependency->ResolvableVersionMatches(resolvable->Version())
+			&& dependency->ResolvableCompatibleVersionMatches(
+				resolvable->CompatibleVersion())) {
 			resolvable->AddDependency(dependency);
 			return true;
 		}
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 1733b9a27c..b7cee76095 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -318,6 +318,20 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
 				}
 				ObjectDeleter versionDeleter(version);
 
+				// create a version object, if a compatible version is specified
+				Version* compatibleVersion = NULL;
+				if (value.resolvable.haveCompatibleVersion) {
+					const BPackageVersionData& versionInfo
+						= value.resolvable.compatibleVersion;
+					status_t error = Version::Create(versionInfo.major,
+						versionInfo.minor, versionInfo.micro,
+						versionInfo.preRelease, versionInfo.release, version);
+					if (error != B_OK)
+						RETURN_ERROR(error);
+				}
+				ObjectDeleter compatibleVersionDeleter(
+					compatibleVersion);
+
 				// create the resolvable
 				Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage);
 				if (resolvable == NULL)
@@ -325,7 +339,7 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
 				ObjectDeleter resolvableDeleter(resolvable);
 
 				status_t error = resolvable->Init(value.resolvable.name,
-					versionDeleter.Detach());
+					versionDeleter.Detach(), compatibleVersionDeleter.Detach());
 				if (error != B_OK)
 					RETURN_ERROR(error);
 

From 2ae9a147cac20560d6d0445e8ddf1a31c3f04e26 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 03:59:55 +0200
Subject: [PATCH 0139/1170] Declare the system package as backwards compatible

---
 src/data/package_infos/haiku | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku
index a7be934c94..79c640e6ff 100644
--- a/src/data/package_infos/haiku
+++ b/src/data/package_infos/haiku
@@ -12,7 +12,7 @@ copyright = "2001-2011 Haiku, Inc. et al"
 licenses = [ "MIT" ]
 
 provides = [
-	haiku=R1-alpha3_pm-1
+	haiku=R1-alpha3_pm-1 compat>=R1-alpha1
 ]
 
 requires = [

From ba1bc0a4ffb6bbaca8257ccad75e80b08020f4ac Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 04:07:16 +0200
Subject: [PATCH 0140/1170] Small cleanup

---
 src/kits/package/PackageInfo.cpp | 20 ++++++++++----------
 1 file changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 8f7a6f510a..8e4b304cb6 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -448,28 +448,28 @@ BPackageInfo::Parser::_ParseStringList(BObjectList* value,
 		BObjectList* value;
 		bool allowQuotedStrings;
 
-		StringParser(BObjectList* value_, bool allowQuotedStrings_)
+		StringParser(BObjectList* value, bool allowQuotedStrings)
 			:
-			value(value_),
-			allowQuotedStrings(allowQuotedStrings_)
+			value(value),
+			allowQuotedStrings(allowQuotedStrings)
 		{
 		}
 
 		virtual void operator()(const Token& token)
 		{
-		if (allowQuotedStrings) {
+			if (allowQuotedStrings) {
 				if (token.type != TOKEN_QUOTED_STRING
 					&& token.type != TOKEN_WORD) {
 					throw ParseError("expected quoted-string or word",
 						token.pos);
 				}
-		} else {
-			if (token.type != TOKEN_WORD)
-				throw ParseError("expected word", token.pos);
-		}
+			} else {
+				if (token.type != TOKEN_WORD)
+					throw ParseError("expected word", token.pos);
+			}
 
-		value->AddItem(new BString(token.text));
-	}
+			value->AddItem(new BString(token.text));
+		}
 	} stringParser(value, allowQuotedStrings);
 
 	_ParseList(stringParser);

From acdcba84ec9426c2d9cad20360f922d519cd1a25 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 04:31:40 +0200
Subject: [PATCH 0141/1170] Remove "copyright" and "license" keywords

There's "copyrights" and "licenses" which can be used.
---
 src/kits/package/PackageInfo.cpp | 10 ----------
 1 file changed, 10 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 8e4b304cb6..8067b5cce5 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -741,11 +741,6 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 			_ParseVersionValue(&version, false);
 			packageInfo->SetVersion(version);
 			seen[B_PACKAGE_INFO_VERSION] = true;
-		} else if (t.text.ICompare("copyright") == 0) {
-			BString copyright;
-			_ParseStringValue(©right);
-			packageInfo->AddCopyright(copyright);
-			seen[B_PACKAGE_INFO_COPYRIGHTS] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_COPYRIGHTS]) == 0) {
 			if (seen[B_PACKAGE_INFO_COPYRIGHTS]) {
 				BString error = BString(names[B_PACKAGE_INFO_COPYRIGHTS])
@@ -759,11 +754,6 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 			for (int i = 0; i < count; ++i)
 				packageInfo->AddCopyright(*(copyrightList.ItemAt(i)));
 			seen[B_PACKAGE_INFO_COPYRIGHTS] = true;
-		} else if (t.text.ICompare("license") == 0) {
-			BString license;
-			_ParseStringValue(&license);
-			packageInfo->AddLicense(license);
-			seen[B_PACKAGE_INFO_LICENSES] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_LICENSES]) == 0) {
 			if (seen[B_PACKAGE_INFO_LICENSES]) {
 				BString error = BString(names[B_PACKAGE_INFO_LICENSES])

From 78ceed51225d370576ae9f460d935b66fcc4c748 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 04:34:10 +0200
Subject: [PATCH 0142/1170] Allow single-element string/flag lists without []

As syntactic sugar string and flag lists no longer need to be enclosed
in brackets when they have exactly one element.
---
 src/kits/package/PackageInfo.cpp | 23 +++++++++++++++--------
 1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 8067b5cce5..f8e1565c4f 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -79,7 +79,8 @@ private:
 									BPackageArchitecture* value);
 			void				_ParseVersionValue(BPackageVersion* value,
 									bool releaseIsOptional);
-			void				_ParseList(ListElementParser& elementParser);
+			void				_ParseList(ListElementParser& elementParser,
+									bool allowSingleNonListElement);
 			void				_ParseStringList(BObjectList* value,
 									bool allowQuotedStrings = true);
 			void				_ParseResolvableList(
@@ -412,11 +413,17 @@ BPackageInfo::Parser::_ParseVersionValue(BPackageVersion* value,
 
 
 void
-BPackageInfo::Parser::_ParseList(ListElementParser& elementParser)
+BPackageInfo::Parser::_ParseList(ListElementParser& elementParser,
+	bool allowSingleNonListElement)
 {
 	Token openBracket = _NextToken();
-	if (openBracket.type != TOKEN_OPEN_BRACKET)
-		throw ParseError("expected start of list ('[')", openBracket.pos);
+	if (openBracket.type != TOKEN_OPEN_BRACKET) {
+		if (!allowSingleNonListElement)
+			throw ParseError("expected start of list ('[')", openBracket.pos);
+
+		elementParser(openBracket);
+		return;
+	}
 
 	bool needComma = false;
 	while (true) {
@@ -472,7 +479,7 @@ BPackageInfo::Parser::_ParseStringList(BObjectList* value,
 		}
 	} stringParser(value, allowQuotedStrings);
 
-	_ParseList(stringParser);
+	_ParseList(stringParser, true);
 }
 
 
@@ -505,7 +512,7 @@ BPackageInfo::Parser::_ParseFlags()
 	}
 	} flagParser;
 
-	_ParseList(flagParser);
+	_ParseList(flagParser, true);
 
 	return flagParser.flags;
 }
@@ -587,7 +594,7 @@ BPackageInfo::Parser::_ParseResolvableList(
 		}
 	} resolvableParser(*this, value);
 
-	_ParseList(resolvableParser);
+	_ParseList(resolvableParser, false);
 }
 
 
@@ -639,7 +646,7 @@ BPackageInfo::Parser::_ParseResolvableExprList(
 	}
 	} resolvableExpressionParser(*this, value);
 
-	_ParseList(resolvableExpressionParser);
+	_ParseList(resolvableExpressionParser, false);
 }
 
 

From 36145114ae7f4d412ba7e34b13b1fd282c3c0e54 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 04:35:50 +0200
Subject: [PATCH 0143/1170] Adjust "copyright"/"licenses" fields

Use the plural keyword name and omit brackets when only one element is
specified.
---
 src/data/package_infos/haiku           | 4 ++--
 src/data/package_infos/haiku-devel     | 4 ++--
 src/data/package_infos/haiku-userguide | 4 ++--
 src/data/package_infos/haiku-welcome   | 4 ++--
 src/data/package_infos/makefile-engine | 4 ++--
 5 files changed, 10 insertions(+), 10 deletions(-)

diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku
index 79c640e6ff..4f005d57dc 100644
--- a/src/data/package_infos/haiku
+++ b/src/data/package_infos/haiku
@@ -8,8 +8,8 @@ boot loader, kernel, the system libraries, servers, and applications."
 packager = "Ingo Weinhold "
 vendor = "Haiku Project"
 
-copyright = "2001-2011 Haiku, Inc. et al"
-licenses = [ "MIT" ]
+copyrights = "2001-2011 Haiku, Inc. et al"
+licenses = [ "MIT" , "GNU LGPL v2.1" ]
 
 provides = [
 	haiku=R1-alpha3_pm-1 compat>=R1-alpha1
diff --git a/src/data/package_infos/haiku-devel b/src/data/package_infos/haiku-devel
index efc5f72047..653533d649 100644
--- a/src/data/package_infos/haiku-devel
+++ b/src/data/package_infos/haiku-devel
@@ -9,8 +9,8 @@ header files, etc."
 packager = "The Haiku build system"
 vendor = "Haiku Project"
 
-copyright = "2001-2011 Haiku, Inc. et al"
-licenses = [ "MIT" ]
+copyrights = "2001-2011 Haiku, Inc. et al"
+licenses = "MIT"
 
 provides = [
 	haiku-devel=R1-alpha3_pm-1
diff --git a/src/data/package_infos/haiku-userguide b/src/data/package_infos/haiku-userguide
index abfb63b7ac..3f4a88ce8e 100644
--- a/src/data/package_infos/haiku-userguide
+++ b/src/data/package_infos/haiku-userguide
@@ -7,8 +7,8 @@ description = "The Haiku user documentation."
 packager = "The Haiku build system"
 vendor = "Haiku Project"
 
-copyright = "2001-2011 Haiku, Inc. et al"
-licenses = [ "MIT" ]
+copyrights = "2001-2011 Haiku, Inc. et al"
+licenses = "MIT"
 
 provides = [
 	haiku-userguide=R1-alpha3_pm-1
diff --git a/src/data/package_infos/haiku-welcome b/src/data/package_infos/haiku-welcome
index 306b331ad3..c85397e1b1 100644
--- a/src/data/package_infos/haiku-welcome
+++ b/src/data/package_infos/haiku-welcome
@@ -7,8 +7,8 @@ description = "The Haiku welcome documentation for new users."
 packager = "The Haiku build system"
 vendor = "Haiku Project"
 
-copyright = "2001-2011 Haiku, Inc. et al"
-licenses = [ "MIT" ]
+copyrights = "2001-2011 Haiku, Inc. et al"
+licenses = "MIT"
 
 provides = [
 	haiku-welcome=R1-alpha3_pm-1
diff --git a/src/data/package_infos/makefile-engine b/src/data/package_infos/makefile-engine
index 801f5c5428..0ab5b4834f 100644
--- a/src/data/package_infos/makefile-engine
+++ b/src/data/package_infos/makefile-engine
@@ -7,8 +7,8 @@ description = "A simple generic makefile engine and makefile template."
 packager = "The Haiku build system"
 vendor = "Be Inc., Haiku Project"
 
-copyright = "? Be Inc. 2001-2011 Haiku, Inc."
-licenses = [ "MIT" ]
+copyrights = "? Be Inc. 2001-2011 Haiku, Inc."
+licenses = "MIT"
 
 provides = [
 	makefile-engine=R1-alpha3_pm-1

From 2ec6e02711808ba732299d5d5f1ac074b774b282 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 06:22:44 +0200
Subject: [PATCH 0144/1170] Small cleanup

---
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 8 --------
 1 file changed, 8 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index b7cee76095..c000130e10 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -279,13 +279,6 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
 		const BPackageInfoAttributeValue& value)
 	{
 		switch (value.attributeID) {
-//            union {
-//                 uint64          unsignedInt;
-//                 const char*     string;
-//                 BPackageVersionData version;
-//                 BPackageResolvableData resolvable;
-//                 BPackageResolvableExpressionData resolvableExpression;
-//             };
 			case B_PACKAGE_INFO_NAME:
 				return fPackage->SetName(value.string);
 
@@ -385,7 +378,6 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
 				break;
 		}
 
-		// TODO!
 		return B_OK;
 	}
 

From eadc3c844da335809e728635ff76a298a9d0d999 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 06:50:39 +0200
Subject: [PATCH 0145/1170] Add architecture property to Package

---
 .../kernel/file_systems/packagefs/Package.cpp | 20 +++++++++++++++++++
 .../kernel/file_systems/packagefs/Package.h   | 13 ++++++++++++
 2 files changed, 33 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.cpp b/src/add-ons/kernel/file_systems/packagefs/Package.cpp
index 487ffd0fdf..9e4b43bb1f 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Package.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Package.cpp
@@ -19,12 +19,20 @@
 #include "Version.h"
 
 
+const char* const kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
+	"any",
+	"x86",
+	"x86_gcc2",
+};
+
+
 Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID)
 	:
 	fDomain(domain),
 	fFileName(NULL),
 	fName(NULL),
 	fVersion(NULL),
+	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
 	fLinkDirectory(NULL),
 	fFD(-1),
 	fOpenCount(0),
@@ -89,6 +97,18 @@ Package::SetVersion(::Version* version)
 }
 
 
+const char*
+Package::ArchitectureName() const
+{
+	if (fArchitecture < 0
+		|| fArchitecture >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
+		return NULL;
+	}
+
+	return kArchitectureNames[fArchitecture];
+}
+
+
 void
 Package::AddNode(PackageNode* node)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.h b/src/add-ons/kernel/file_systems/packagefs/Package.h
index d6ec920c0e..ff7a6522b0 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Package.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Package.h
@@ -6,6 +6,8 @@
 #define PACKAGE_H
 
 
+#include 
+
 #include 
 
 #include 
@@ -19,6 +21,9 @@
 #include "Resolvable.h"
 
 
+using BPackageKit::BPackageArchitecture;
+
+
 class PackageDomain;
 class PackageLinkDirectory;
 class Version;
@@ -44,6 +49,13 @@ public:
 			::Version*			Version() const
 									{ return fVersion; }
 
+			void				SetArchitecture(
+									BPackageArchitecture architecture)
+									{ fArchitecture = architecture; }
+			BPackageArchitecture Architecture() const
+									{ return fArchitecture; }
+			const char*			ArchitectureName() const;
+
 			void				SetLinkDirectory(
 									PackageLinkDirectory* linkDirectory)
 									{ fLinkDirectory = linkDirectory; }
@@ -72,6 +84,7 @@ private:
 			char*				fFileName;
 			char*				fName;
 			::Version*			fVersion;
+			BPackageArchitecture fArchitecture;
 			PackageLinkDirectory* fLinkDirectory;
 			int					fFD;
 			uint32				fOpenCount;

From ba926f35547e9e75613ad35f8b7901e9e7845a62 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 06:51:02 +0200
Subject: [PATCH 0146/1170] Extract architecture from package file

---
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index c000130e10..a1b300fc7e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -296,6 +296,14 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
 				break;
 			}
 
+			case B_PACKAGE_INFO_ARCHITECTURE:
+				if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT)
+					RETURN_ERROR(B_BAD_VALUE);
+
+				fPackage->SetArchitecture(
+					(BPackageArchitecture)value.unsignedInt);
+				break;
+
 			case B_PACKAGE_INFO_PROVIDES:
 			{
 				// create a version object, if a version is specified

From 7e346f16778a21926ca172008241d52f9f517222 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 06:51:40 +0200
Subject: [PATCH 0147/1170] Include architecture in package links dir names

---
 .../file_systems/packagefs/PackageLinkDirectory.cpp | 13 +++++++++++++
 1 file changed, 13 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
index 86fab0f19b..8b88e14eea 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
@@ -56,17 +56,30 @@ PackageLinkDirectory::Init(Directory* parent, Package* package)
 			// + 1 for the '-'
 	}
 
+	const char* architecture = package->ArchitectureName();
+	if (architecture != NULL) {
+		size += 1 + strlen(architecture);
+			// + 1 for the '-'
+	}
+
 	// allocate the name and compose it
 	char* name = (char*)malloc(size);
 	if (name == NULL)
 		return B_NO_MEMORY;
 
 	memcpy(name, package->Name(), nameLength + 1);
+
 	if (version != NULL) {
 		name[nameLength] = '-';
 		version->ToString(name + nameLength + 1, size - nameLength - 1);
 	}
 
+	if (architecture != NULL) {
+		nameLength += strlen(name + nameLength);
+		name[nameLength] = '-';
+		strlcpy(name + nameLength + 1, architecture, size - nameLength - 1);
+	}
+
 	// init the directory/node
 	status_t error = Init(parent, name, NODE_FLAG_KEEP_NAME);
 	if (error != B_OK)

From 91698de99472aeb71a48fe1428acc8e24aaf2c8a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 19:12:35 +0200
Subject: [PATCH 0148/1170] Make .PackageInfo more driver-settings-ish

* Use braces instead of brackets for lists.
* Semicolons and newlines separate items now. Remove handling for comma.
* Allow '\'' as quotation character.
* Remove assignment after variable name.

This should make the .PackageInfo format driver settings compatible, but
not vice versa. It is still stricter.
---
 src/kits/package/PackageInfo.cpp | 83 ++++++++++++++++----------------
 1 file changed, 41 insertions(+), 42 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index f8e1565c4f..52f2e89f2a 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -32,9 +32,9 @@ enum TokenType {
 	TOKEN_OPERATOR_NOT_EQUAL,
 	TOKEN_OPERATOR_GREATER_EQUAL,
 	TOKEN_OPERATOR_GREATER,
-	TOKEN_OPEN_BRACKET,
-	TOKEN_CLOSE_BRACKET,
-	TOKEN_COMMA,
+	TOKEN_OPEN_BRACE,
+	TOKEN_CLOSE_BRACE,
+	TOKEN_ITEM_SEPARATOR,
 	//
 	TOKEN_EOF,
 };
@@ -205,32 +205,39 @@ BPackageInfo::Parser::Parse(const BString& packageInfoString,
 BPackageInfo::Parser::Token
 BPackageInfo::Parser::_NextToken()
 {
-	// eat any whitespace or comments
+	// Eat any whitespace or comments. Also eat ';' -- they have the same
+	// function as newlines. We remember the last encountered ';' or '\n' and
+	// return it as a token afterwards.
+	const char* itemSeparatorPos = NULL;
 	bool inComment = false;
-	while ((inComment && *fPos != '\0') || isspace(*fPos) || *fPos == '#') {
-		if (*fPos == '#')
+	while ((inComment && *fPos != '\0') || isspace(*fPos) || *fPos == ';'
+		|| *fPos == '#') {
+		if (*fPos == '#') {
 			inComment = true;
-		else if (*fPos == '\n')
+		} else if (*fPos == '\n') {
+			itemSeparatorPos = fPos;
 			inComment = false;
+		} else if (!inComment && *fPos == ';')
+			itemSeparatorPos = fPos;
 		fPos++;
 	}
 
+	if (itemSeparatorPos != NULL) {
+		return Token(TOKEN_ITEM_SEPARATOR, itemSeparatorPos);
+	}
+
 	const char* tokenPos = fPos;
 	switch (*fPos) {
 		case '\0':
 			return Token(TOKEN_EOF, fPos);
 
-		case ',':
+		case '{':
 			fPos++;
-			return Token(TOKEN_COMMA, tokenPos);
+			return Token(TOKEN_OPEN_BRACE, tokenPos);
 
-		case '[':
+		case '}':
 			fPos++;
-			return Token(TOKEN_OPEN_BRACKET, tokenPos);
-
-		case ']':
-			fPos++;
-			return Token(TOKEN_CLOSE_BRACKET, tokenPos);
+			return Token(TOKEN_CLOSE_BRACE, tokenPos);
 
 		case '<':
 			fPos++;
@@ -264,19 +271,21 @@ BPackageInfo::Parser::_NextToken()
 			return Token(TOKEN_OPERATOR_GREATER, tokenPos, 1);
 
 		case '"':
+		case '\'':
 		{
+			char quoteChar = *fPos;
 			fPos++;
 			const char* start = fPos;
 			// anything until the next quote is part of the value
 			bool lastWasEscape = false;
-			while ((*fPos != '"' || lastWasEscape) && *fPos != '\0') {
+			while ((*fPos != quoteChar || lastWasEscape) && *fPos != '\0') {
 				if (lastWasEscape)
 					lastWasEscape = false;
 				else if (*fPos == '\\')
 					lastWasEscape = true;
 				fPos++;
 			}
-			if (*fPos != '"')
+			if (*fPos != quoteChar)
 				throw ParseError("unterminated quoted-string", tokenPos);
 			const char* end = fPos++;
 			return Token(TOKEN_QUOTED_STRING, start, end - start);
@@ -417,7 +426,7 @@ BPackageInfo::Parser::_ParseList(ListElementParser& elementParser,
 	bool allowSingleNonListElement)
 {
 	Token openBracket = _NextToken();
-	if (openBracket.type != TOKEN_OPEN_BRACKET) {
+	if (openBracket.type != TOKEN_OPEN_BRACE) {
 		if (!allowSingleNonListElement)
 			throw ParseError("expected start of list ('[')", openBracket.pos);
 
@@ -425,22 +434,13 @@ BPackageInfo::Parser::_ParseList(ListElementParser& elementParser,
 		return;
 	}
 
-	bool needComma = false;
 	while (true) {
 		Token token = _NextToken();
-		if (token.type == TOKEN_CLOSE_BRACKET)
+		if (token.type == TOKEN_CLOSE_BRACE)
 			return;
 
-		if (needComma) {
-			if (token.type != TOKEN_COMMA)
-				throw ParseError("expected comma", token.pos);
-			token = _NextToken();
-			if (token.type == TOKEN_CLOSE_BRACKET) {
-				// silently skip trailing comma at end of list
-				return;
-			}
-		} else
-			needComma = true;
+		if (token.type == TOKEN_ITEM_SEPARATOR)
+			continue;
 
 		elementParser(token);
 	}
@@ -568,11 +568,12 @@ BPackageInfo::Parser::_ParseResolvableList(
 			// parse version
 			BPackageVersion version;
 			Token op = parser._NextToken();
-			if (op.type == TOKEN_OPERATOR_ASSIGN)
+			if (op.type == TOKEN_OPERATOR_ASSIGN) {
 				parser._ParseVersionValue(&version, true);
-			else if (op.type == TOKEN_COMMA || op.type == TOKEN_CLOSE_BRACKET)
+			} else if (op.type == TOKEN_ITEM_SEPARATOR
+				|| op.type == TOKEN_CLOSE_BRACE) {
 				parser._RewindTo(op);
-			else
+			} else
 				throw ParseError("expected '=', comma or ']'", op.pos);
 
 			// parse compatible version
@@ -628,11 +629,12 @@ BPackageInfo::Parser::_ParseResolvableExprList(
 			|| op.type == TOKEN_OPERATOR_EQUAL
 			|| op.type == TOKEN_OPERATOR_NOT_EQUAL
 			|| op.type == TOKEN_OPERATOR_GREATER_EQUAL
-			|| op.type == TOKEN_OPERATOR_GREATER)
+			|| op.type == TOKEN_OPERATOR_GREATER) {
 				parser._ParseVersionValue(&version, true);
-		else if (op.type == TOKEN_COMMA || op.type == TOKEN_CLOSE_BRACKET)
+		} else if (op.type == TOKEN_ITEM_SEPARATOR
+			|| op.type == TOKEN_CLOSE_BRACE) {
 				parser._RewindTo(op);
-		else {
+		} else {
 			throw ParseError(
 				"expected '<', '<=', '==', '!=', '>=', '>', comma or ']'",
 				op.pos);
@@ -660,15 +662,12 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 	const char* const* names = BPackageInfo::kElementNames;
 
 	while (Token t = _NextToken()) {
+		if (t.type == TOKEN_ITEM_SEPARATOR)
+			continue;
+
 		if (t.type != TOKEN_WORD)
 			throw ParseError("expected word (a variable name)", t.pos);
 
-		Token opAssign = _NextToken();
-		if (opAssign.type != TOKEN_OPERATOR_ASSIGN) {
-			throw ParseError("expected assignment operator ('=')",
-				opAssign.pos);
-		}
-
 		if (t.text.ICompare(names[B_PACKAGE_INFO_NAME]) == 0) {
 			if (seen[B_PACKAGE_INFO_NAME]) {
 				BString error = BString(names[B_PACKAGE_INFO_NAME])

From 1feaa8ab7e7ea62930d1e74ea7dfad3c32576fc4 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 27 Jun 2011 19:12:58 +0200
Subject: [PATCH 0149/1170] Adjust to changed .PackageInfo format

---
 src/data/package_infos/haiku           | 30 +++++++++++++++-----------
 src/data/package_infos/haiku-devel     | 27 ++++++++++++-----------
 src/data/package_infos/haiku-userguide | 26 +++++++++++-----------
 src/data/package_infos/haiku-welcome   | 26 +++++++++++-----------
 src/data/package_infos/makefile-engine | 26 +++++++++++-----------
 5 files changed, 70 insertions(+), 65 deletions(-)

diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku
index 4f005d57dc..0398f10f66 100644
--- a/src/data/package_infos/haiku
+++ b/src/data/package_infos/haiku
@@ -1,19 +1,23 @@
-name = Haiku
-version = R1-alpha3_pm-1
-architecture = x86_gcc2
-summary = "The Haiku base system"
-description = "The Haiku base system includes all system core software, like
+name 			Haiku
+version			R1-alpha3_pm-1
+architecture	x86_gcc2
+summary			"The Haiku base system"
+
+description		"The Haiku base system includes all system core software, like
 boot loader, kernel, the system libraries, servers, and applications."
 
-packager = "Ingo Weinhold "
-vendor = "Haiku Project"
+packager		"Ingo Weinhold "
+vendor			"Haiku Project"
 
-copyrights = "2001-2011 Haiku, Inc. et al"
-licenses = [ "MIT" , "GNU LGPL v2.1" ]
+copyrights		"2001-2011 Haiku, Inc. et al"
+licenses {
+	MIT
+	"GNU LGPL v2.1"
+}
 
-provides = [
+provides {
 	haiku=R1-alpha3_pm-1 compat>=R1-alpha1
-]
+}
 
-requires = [
-]
+requires {
+}
diff --git a/src/data/package_infos/haiku-devel b/src/data/package_infos/haiku-devel
index 653533d649..de21f9a864 100644
--- a/src/data/package_infos/haiku-devel
+++ b/src/data/package_infos/haiku-devel
@@ -1,21 +1,22 @@
-name = haiku-devel
-version = R1-alpha3_pm-1
-architecture = x86_gcc2
-summary = "The Haiku base system development files"
-description = "The package contains all files associated with the base system
+name			haiku-devel
+version			R1-alpha3_pm-1
+architecture	x86_gcc2
+summary			"The Haiku base system development files"
+
+description		"The package contains all files associated with the base system
 needed for development, like static libraries, glue code, library symlinks,
 header files, etc."
 
-packager = "The Haiku build system"
-vendor = "Haiku Project"
+packager		"The Haiku build system"
+vendor			"Haiku Project"
 
-copyrights = "2001-2011 Haiku, Inc. et al"
-licenses = "MIT"
+copyrights		"2001-2011 Haiku, Inc. et al"
+licenses		"MIT"
 
-provides = [
+provides {
 	haiku-devel=R1-alpha3_pm-1
-]
+}
 
-requires = [
+requires {
 	haiku
-]
+}
diff --git a/src/data/package_infos/haiku-userguide b/src/data/package_infos/haiku-userguide
index 3f4a88ce8e..cfef5a6d25 100644
--- a/src/data/package_infos/haiku-userguide
+++ b/src/data/package_infos/haiku-userguide
@@ -1,18 +1,18 @@
-name = haiku-userguide
-version = R1-alpha3_pm-1
-architecture = any
-summary = "The Haiku user documentation"
-description = "The Haiku user documentation."
+name			haiku-userguide
+version			R1-alpha3_pm-1
+architecture	any
+summary			"The Haiku user documentation"
+description		"The Haiku user documentation."
 
-packager = "The Haiku build system"
-vendor = "Haiku Project"
+packager		"The Haiku build system"
+vendor			"Haiku Project"
 
-copyrights = "2001-2011 Haiku, Inc. et al"
-licenses = "MIT"
+copyrights		"2001-2011 Haiku, Inc. et al"
+licenses		MIT
 
-provides = [
+provides {
 	haiku-userguide=R1-alpha3_pm-1
-]
+}
 
-requires = [
-]
+requires {
+}
diff --git a/src/data/package_infos/haiku-welcome b/src/data/package_infos/haiku-welcome
index c85397e1b1..b5c349e233 100644
--- a/src/data/package_infos/haiku-welcome
+++ b/src/data/package_infos/haiku-welcome
@@ -1,18 +1,18 @@
-name = haiku-welcome
-version = R1-alpha3_pm-1
-architecture = any
-summary = "The Haiku welcome documentation"
-description = "The Haiku welcome documentation for new users."
+name			haiku-welcome
+version			R1-alpha3_pm-1
+architecture	any
+summary			"The Haiku welcome documentation"
+description		"The Haiku welcome documentation for new users."
 
-packager = "The Haiku build system"
-vendor = "Haiku Project"
+packager		"The Haiku build system"
+vendor			"Haiku Project"
 
-copyrights = "2001-2011 Haiku, Inc. et al"
-licenses = "MIT"
+copyrights		"2001-2011 Haiku, Inc. et al"
+licenses		"MIT"
 
-provides = [
+provides {
 	haiku-welcome=R1-alpha3_pm-1
-]
+}
 
-requires = [
-]
+requires {
+}
diff --git a/src/data/package_infos/makefile-engine b/src/data/package_infos/makefile-engine
index 0ab5b4834f..31387409a1 100644
--- a/src/data/package_infos/makefile-engine
+++ b/src/data/package_infos/makefile-engine
@@ -1,19 +1,19 @@
-name = makefile-engine
-version = R1-alpha3_pm-1
-architecture = any
-summary = "The makefile engine"
-description = "A simple generic makefile engine and makefile template."
+name			makefile-engine
+version			R1-alpha3_pm-1
+architecture	any
+summary			"The makefile engine"
+description 	"A simple generic makefile engine and makefile template."
 
-packager = "The Haiku build system"
-vendor = "Be Inc., Haiku Project"
+packager		"The Haiku build system"
+vendor			"Be Inc., Haiku Project"
 
-copyrights = "? Be Inc. 2001-2011 Haiku, Inc."
-licenses = "MIT"
+copyrights		"? Be Inc. 2001-2011 Haiku, Inc."
+licenses		MIT
 
-provides = [
+provides {
 	makefile-engine=R1-alpha3_pm-1
-]
+}
 
-requires = [
+requires {
 	cmd:make
-]
+}

From 941ec459132d16fe7a373841a054aa78063dbcd9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 28 Jun 2011 01:04:26 +0200
Subject: [PATCH 0150/1170] Don't include architecture in package links names

This reverts commit a491e591c86cec4b2ce52df86f7b0d32545b4169.
---
 .../file_systems/packagefs/PackageLinkDirectory.cpp | 13 -------------
 1 file changed, 13 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
index 8b88e14eea..86fab0f19b 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
@@ -56,30 +56,17 @@ PackageLinkDirectory::Init(Directory* parent, Package* package)
 			// + 1 for the '-'
 	}
 
-	const char* architecture = package->ArchitectureName();
-	if (architecture != NULL) {
-		size += 1 + strlen(architecture);
-			// + 1 for the '-'
-	}
-
 	// allocate the name and compose it
 	char* name = (char*)malloc(size);
 	if (name == NULL)
 		return B_NO_MEMORY;
 
 	memcpy(name, package->Name(), nameLength + 1);
-
 	if (version != NULL) {
 		name[nameLength] = '-';
 		version->ToString(name + nameLength + 1, size - nameLength - 1);
 	}
 
-	if (architecture != NULL) {
-		nameLength += strlen(name + nameLength);
-		name[nameLength] = '-';
-		strlcpy(name + nameLength + 1, architecture, size - nameLength - 1);
-	}
-
 	// init the directory/node
 	status_t error = Init(parent, name, NODE_FLAG_KEEP_NAME);
 	if (error != B_OK)

From 430689a68858ddd6dc4ac36394fd924abd5ed143 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 28 Jun 2011 16:54:56 +0200
Subject: [PATCH 0151/1170] Move hpkgBaseURL definition before its first use

---
 build/jam/OptionalBuildFeatures | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures
index c0af75f3fa..15c141d407 100644
--- a/build/jam/OptionalBuildFeatures
+++ b/build/jam/OptionalBuildFeatures
@@ -18,6 +18,7 @@ if $(HAIKU_GCC_VERSION[1]) >= 4 {
 }
 
 local baseURL = http://haiku-files.org/files/optional-packages ;
+local hpkgBaseURL = http://haiku-files.org/files/hpkg ;
 HAIKU_OPENSSL_URL = $(baseURL)/$(HAIKU_OPENSSL_PACKAGE) ;
 
 if $(HAIKU_BUILD_FEATURE_SSL) {
@@ -143,7 +144,6 @@ if [ IsOptionalHaikuImagePackageAdded CLucene ] {
 }
 
 local baseURL = http://haiku-files.org/files/optional-packages ;
-local hpkgBaseURL = http://haiku-files.org/files/hpkg ;
 HAIKU_CLUCENE_PACKAGE = clucene-0.9.21-x86-gcc4-haiku-2009-08-11.zip ;
 HAIKU_CLUCENE_URL = $(baseURL)/$(HAIKU_CLUCENE_PACKAGE) ;
 

From ee453e8bbccd77988e5c422a4e3d76058bd95fb2 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 28 Jun 2011 17:24:34 +0200
Subject: [PATCH 0152/1170] Add url and sourceURL properties to BPackageInfo

Also extend the parser to accept "url" and "source-url" attributes.
---
 headers/os/package/PackageInfo.h           | 10 +++
 headers/os/package/PackageInfoAttributes.h |  2 +
 src/kits/package/PackageInfo.cpp           | 82 ++++++++++++++++++++++
 3 files changed, 94 insertions(+)

diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h
index b130d175a9..c1bd851acb 100644
--- a/headers/os/package/PackageInfo.h
+++ b/headers/os/package/PackageInfo.h
@@ -65,6 +65,8 @@ public:
 
 			const BObjectList&	CopyrightList() const;
 			const BObjectList&	LicenseList() const;
+			const BObjectList&	URLList() const;
+			const BObjectList&	SourceURLList() const;
 
 			const BObjectList&	ProvidesList() const;
 			const BObjectList&
@@ -97,6 +99,12 @@ public:
 			void				ClearLicenseList();
 			status_t			AddLicense(const BString& license);
 
+			void				ClearURLList();
+			status_t			AddURL(const BString& url);
+
+			void				ClearSourceURLList();
+			status_t			AddSourceURL(const BString& url);
+
 			void				ClearProvidesList();
 			status_t			AddProvides(const BPackageResolvable& provides);
 
@@ -146,6 +154,8 @@ private:
 
 			BObjectList	fCopyrightList;
 			BObjectList	fLicenseList;
+			BObjectList	fURLList;
+			BObjectList	fSourceURLList;
 
 			BObjectList	fProvidesList;
 
diff --git a/headers/os/package/PackageInfoAttributes.h b/headers/os/package/PackageInfoAttributes.h
index 19bb8ff3f1..d03a21695a 100644
--- a/headers/os/package/PackageInfoAttributes.h
+++ b/headers/os/package/PackageInfoAttributes.h
@@ -34,6 +34,8 @@ enum BPackageInfoAttributeID {
 	B_PACKAGE_INFO_REPLACES,	// list of resolvables that this package
 								// will replace (upon update)
 	B_PACKAGE_INFO_FLAGS,
+	B_PACKAGE_INFO_URLS,		// list
+	B_PACKAGE_INFO_SOURCE_URLS,	// list
 	B_PACKAGE_INFO_CHECKSUM,	// sha256-checksum
 	//
 	B_PACKAGE_INFO_ENUM_COUNT,
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 52f2e89f2a..13d6dccfa6 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -773,6 +773,32 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 			for (int i = 0; i < count; ++i)
 				packageInfo->AddLicense(*(licenseList.ItemAt(i)));
 			seen[B_PACKAGE_INFO_LICENSES] = true;
+		} else if (t.text.ICompare(names[B_PACKAGE_INFO_URLS]) == 0) {
+			if (seen[B_PACKAGE_INFO_URLS]) {
+				BString error = BString(names[B_PACKAGE_INFO_URLS])
+					<< " already seen!";
+				throw ParseError(error, t.pos);
+			}
+
+			BObjectList urlList;
+			_ParseStringList(&urlList);
+			int count = urlList.CountItems();
+			for (int i = 0; i < count; ++i)
+				packageInfo->AddURL(*(urlList.ItemAt(i)));
+			seen[B_PACKAGE_INFO_URLS] = true;
+		} else if (t.text.ICompare(names[B_PACKAGE_INFO_SOURCE_URLS]) == 0) {
+			if (seen[B_PACKAGE_INFO_SOURCE_URLS]) {
+				BString error = BString(names[B_PACKAGE_INFO_SOURCE_URLS])
+					<< " already seen!";
+				throw ParseError(error, t.pos);
+			}
+
+			BObjectList urlList;
+			_ParseStringList(&urlList);
+			int count = urlList.CountItems();
+			for (int i = 0; i < count; ++i)
+				packageInfo->AddSourceURL(*(urlList.ItemAt(i)));
+			seen[B_PACKAGE_INFO_SOURCE_URLS] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_PROVIDES]) == 0) {
 			if (seen[B_PACKAGE_INFO_PROVIDES]) {
 				BString error = BString(names[B_PACKAGE_INFO_PROVIDES])
@@ -890,6 +916,8 @@ const char* BPackageInfo::kElementNames[B_PACKAGE_INFO_ENUM_COUNT] = {
 	"freshens",
 	"replaces",
 	"flags",
+	"urls",
+	"source-urls",
 	"checksum",		// not being parsed, computed externally
 };
 
@@ -908,6 +936,8 @@ BPackageInfo::BPackageInfo()
 	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
 	fCopyrightList(5, true),
 	fLicenseList(5, true),
+	fURLList(5, true),
+	fSourceURLList(5, true),
 	fProvidesList(20, true),
 	fRequiresList(20, true),
 	fSupplementsList(20, true),
@@ -1060,6 +1090,20 @@ BPackageInfo::LicenseList() const
 }
 
 
+const BObjectList&
+BPackageInfo::URLList() const
+{
+	return fURLList;
+}
+
+
+const BObjectList&
+BPackageInfo::SourceURLList() const
+{
+	return fSourceURLList;
+}
+
+
 const BObjectList&
 BPackageInfo::ProvidesList() const
 {
@@ -1201,6 +1245,42 @@ BPackageInfo::AddLicense(const BString& license)
 }
 
 
+void
+BPackageInfo::ClearURLList()
+{
+	fURLList.MakeEmpty();
+}
+
+
+status_t
+BPackageInfo::AddURL(const BString& url)
+{
+	BString* newURL = new (std::nothrow) BString(url);
+	if (newURL == NULL)
+		return B_NO_MEMORY;
+
+	return fURLList.AddItem(newURL) ? B_OK : B_NO_MEMORY;
+}
+
+
+void
+BPackageInfo::ClearSourceURLList()
+{
+	fSourceURLList.MakeEmpty();
+}
+
+
+status_t
+BPackageInfo::AddSourceURL(const BString& url)
+{
+	BString* newURL = new (std::nothrow) BString(url);
+	if (newURL == NULL)
+		return B_NO_MEMORY;
+
+	return fSourceURLList.AddItem(newURL) ? B_OK : B_NO_MEMORY;
+}
+
+
 void
 BPackageInfo::ClearProvidesList()
 {
@@ -1328,6 +1408,8 @@ BPackageInfo::Clear()
 	fVersion.Clear();
 	fCopyrightList.MakeEmpty();
 	fLicenseList.MakeEmpty();
+	fURLList.MakeEmpty();
+	fSourceURLList.MakeEmpty();
 	fRequiresList.MakeEmpty();
 	fProvidesList.MakeEmpty();
 	fSupplementsList.MakeEmpty();

From 8b684dd3630305ea03495f39e3a1bf62a94ba6d6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 28 Jun 2011 17:25:18 +0200
Subject: [PATCH 0153/1170] Add URL/source URL hpkg package attributes

---
 headers/os/package/hpkg/HPKGDefs.h              | 2 ++
 src/kits/package/hpkg/PackageContentHandler.cpp | 4 +++-
 2 files changed, 5 insertions(+), 1 deletion(-)

diff --git a/headers/os/package/hpkg/HPKGDefs.h b/headers/os/package/hpkg/HPKGDefs.h
index 2ea360e044..f50d0bdf23 100644
--- a/headers/os/package/hpkg/HPKGDefs.h
+++ b/headers/os/package/hpkg/HPKGDefs.h
@@ -112,6 +112,8 @@ enum BHPKGAttributeID {
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_CHECKSUM			= 39,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_PRE_RELEASE	= 40,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_COMPATIBLE	= 41,
+	B_HPKG_ATTRIBUTE_ID_PACKAGE_URL					= 42,
+	B_HPKG_ATTRIBUTE_ID_PACKAGE_SOURCE_URL			= 43,
 	//
 	B_HPKG_ATTRIBUTE_ID_ENUM_COUNT,
 };
diff --git a/src/kits/package/hpkg/PackageContentHandler.cpp b/src/kits/package/hpkg/PackageContentHandler.cpp
index 8abfc1d996..61878e172a 100644
--- a/src/kits/package/hpkg/PackageContentHandler.cpp
+++ b/src/kits/package/hpkg/PackageContentHandler.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
  * Distributed under the terms of the MIT License.
  */
 
@@ -58,6 +58,8 @@ static const char* kAttributeNames[B_HPKG_ATTRIBUTE_ID_ENUM_COUNT + 1] = {
 	"package:checksum",
 	"package:version.prerelease",
 	"package:provides.compatible",
+	"package:url",
+	"package:source_url",
 	NULL
 };
 

From 122597e0ba4eaa94aea0b1197e1f42d659a5f3ea Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 28 Jun 2011 17:44:13 +0200
Subject: [PATCH 0154/1170] Simplify BPackageInfo::Parser::_Parse()

This also fixes the memory leak due to the previously used on-stack
BObjectLists not having been defined owning the elements.
---
 src/kits/package/PackageInfo.cpp | 60 ++++++--------------------------
 1 file changed, 10 insertions(+), 50 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 13d6dccfa6..ecb4e6b78a 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -754,11 +754,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				throw ParseError(error, t.pos);
 			}
 
-			BObjectList copyrightList;
-			_ParseStringList(©rightList);
-			int count = copyrightList.CountItems();
-			for (int i = 0; i < count; ++i)
-				packageInfo->AddCopyright(*(copyrightList.ItemAt(i)));
+			_ParseStringList(&packageInfo->fCopyrightList);
 			seen[B_PACKAGE_INFO_COPYRIGHTS] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_LICENSES]) == 0) {
 			if (seen[B_PACKAGE_INFO_LICENSES]) {
@@ -767,11 +763,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				throw ParseError(error, t.pos);
 			}
 
-			BObjectList licenseList;
-			_ParseStringList(&licenseList);
-			int count = licenseList.CountItems();
-			for (int i = 0; i < count; ++i)
-				packageInfo->AddLicense(*(licenseList.ItemAt(i)));
+			_ParseStringList(&packageInfo->fLicenseList);
 			seen[B_PACKAGE_INFO_LICENSES] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_URLS]) == 0) {
 			if (seen[B_PACKAGE_INFO_URLS]) {
@@ -780,11 +772,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				throw ParseError(error, t.pos);
 			}
 
-			BObjectList urlList;
-			_ParseStringList(&urlList);
-			int count = urlList.CountItems();
-			for (int i = 0; i < count; ++i)
-				packageInfo->AddURL(*(urlList.ItemAt(i)));
+			_ParseStringList(&packageInfo->fURLList);
 			seen[B_PACKAGE_INFO_URLS] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_SOURCE_URLS]) == 0) {
 			if (seen[B_PACKAGE_INFO_SOURCE_URLS]) {
@@ -793,11 +781,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				throw ParseError(error, t.pos);
 			}
 
-			BObjectList urlList;
-			_ParseStringList(&urlList);
-			int count = urlList.CountItems();
-			for (int i = 0; i < count; ++i)
-				packageInfo->AddSourceURL(*(urlList.ItemAt(i)));
+			_ParseStringList(&packageInfo->fSourceURLList);
 			seen[B_PACKAGE_INFO_SOURCE_URLS] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_PROVIDES]) == 0) {
 			if (seen[B_PACKAGE_INFO_PROVIDES]) {
@@ -806,11 +790,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				throw ParseError(error, t.pos);
 			}
 
-			BObjectList providesList;
-			_ParseResolvableList(&providesList);
-			int count = providesList.CountItems();
-			for (int i = 0; i < count; ++i)
-				packageInfo->AddProvides(*(providesList.ItemAt(i)));
+			_ParseResolvableList(&packageInfo->fProvidesList);
 			seen[B_PACKAGE_INFO_PROVIDES] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_REQUIRES]) == 0) {
 			if (seen[B_PACKAGE_INFO_REQUIRES]) {
@@ -819,11 +799,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				throw ParseError(error, t.pos);
 			}
 
-			BObjectList requiresList;
-			_ParseResolvableExprList(&requiresList);
-			int count = requiresList.CountItems();
-			for (int i = 0; i < count; ++i)
-				packageInfo->AddRequires(*(requiresList.ItemAt(i)));
+			_ParseResolvableExprList(&packageInfo->fRequiresList);
 			seen[B_PACKAGE_INFO_REQUIRES] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_SUPPLEMENTS]) == 0) {
 			if (seen[B_PACKAGE_INFO_SUPPLEMENTS]) {
@@ -832,11 +808,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				throw ParseError(error, t.pos);
 			}
 
-			BObjectList supplementsList;
-			_ParseResolvableExprList(&supplementsList);
-			int count = supplementsList.CountItems();
-			for (int i = 0; i < count; ++i)
-				packageInfo->AddSupplements(*(supplementsList.ItemAt(i)));
+			_ParseResolvableExprList(&packageInfo->fSupplementsList);
 			seen[B_PACKAGE_INFO_SUPPLEMENTS] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_CONFLICTS]) == 0) {
 			if (seen[B_PACKAGE_INFO_CONFLICTS]) {
@@ -845,11 +817,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				throw ParseError(error, t.pos);
 			}
 
-			BObjectList conflictsList;
-			_ParseResolvableExprList(&conflictsList);
-			int count = conflictsList.CountItems();
-			for (int i = 0; i < count; ++i)
-				packageInfo->AddConflicts(*(conflictsList.ItemAt(i)));
+			_ParseResolvableExprList(&packageInfo->fConflictsList);
 			seen[B_PACKAGE_INFO_CONFLICTS] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_FRESHENS]) == 0) {
 			if (seen[B_PACKAGE_INFO_FRESHENS]) {
@@ -858,11 +826,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				throw ParseError(error, t.pos);
 			}
 
-			BObjectList freshensList;
-			_ParseResolvableExprList(&freshensList);
-			int count = freshensList.CountItems();
-			for (int i = 0; i < count; ++i)
-				packageInfo->AddFreshens(*(freshensList.ItemAt(i)));
+			_ParseResolvableExprList(&packageInfo->fFreshensList);
 			seen[B_PACKAGE_INFO_FRESHENS] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_REPLACES]) == 0) {
 			if (seen[B_PACKAGE_INFO_REPLACES]) {
@@ -871,11 +835,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				throw ParseError(error, t.pos);
 			}
 
-			BObjectList replacesList;
-			_ParseStringList(&replacesList, false);
-			int count = replacesList.CountItems();
-			for (int i = 0; i < count; ++i)
-				packageInfo->AddReplaces(*(replacesList.ItemAt(i)));
+			_ParseStringList(&packageInfo->fReplacesList, false);
 			seen[B_PACKAGE_INFO_REPLACES] = true;
 		} else if (t.text.ICompare(names[B_PACKAGE_INFO_FLAGS]) == 0) {
 			if (seen[B_PACKAGE_INFO_FLAGS]) {

From d4701a292100473ababbd936b01c5dc3de2e135d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 28 Jun 2011 18:01:14 +0200
Subject: [PATCH 0155/1170] Simplify BPackageInfo::Parser::_Parse() further

* Match the attribute in a loop, use an attribute ID switch, do the
  "seen" checks without the switch.
* Explicitly handle the case when encountering an unknown attribute.
---
 src/kits/package/PackageInfo.cpp | 278 +++++++++++--------------------
 1 file changed, 101 insertions(+), 177 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index ecb4e6b78a..dd7dad04f1 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -668,185 +668,109 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 		if (t.type != TOKEN_WORD)
 			throw ParseError("expected word (a variable name)", t.pos);
 
-		if (t.text.ICompare(names[B_PACKAGE_INFO_NAME]) == 0) {
-			if (seen[B_PACKAGE_INFO_NAME]) {
-				BString error = BString(names[B_PACKAGE_INFO_NAME])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
+		BPackageInfoAttributeID attribute = B_PACKAGE_INFO_ENUM_COUNT;
+		for (int i = 0; i < B_PACKAGE_INFO_ENUM_COUNT; i++) {
+			if (t.text.ICompare(names[i]) == 0) {
+				attribute = (BPackageInfoAttributeID)i;
+				break;
 			}
-
-			BString name;
-			_ParseStringValue(&name);
-			packageInfo->SetName(name);
-			seen[B_PACKAGE_INFO_NAME] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_SUMMARY]) == 0) {
-			if (seen[B_PACKAGE_INFO_SUMMARY]) {
-				BString error = BString(names[B_PACKAGE_INFO_SUMMARY])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			BString summary;
-			_ParseStringValue(&summary);
-			if (summary.FindFirst('\n') >= 0)
-				throw ParseError("the summary contains linebreaks", t.pos);
-			packageInfo->SetSummary(summary);
-			seen[B_PACKAGE_INFO_SUMMARY] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_DESCRIPTION]) == 0) {
-			if (seen[B_PACKAGE_INFO_DESCRIPTION]) {
-				BString error = BString(names[B_PACKAGE_INFO_DESCRIPTION])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			BString description;
-			_ParseStringValue(&description);
-			packageInfo->SetDescription(description);
-			seen[B_PACKAGE_INFO_DESCRIPTION] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_VENDOR]) == 0) {
-			if (seen[B_PACKAGE_INFO_VENDOR]) {
-				BString error = BString(names[B_PACKAGE_INFO_VENDOR])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			BString vendor;
-			_ParseStringValue(&vendor);
-			packageInfo->SetVendor(vendor);
-			seen[B_PACKAGE_INFO_VENDOR] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_PACKAGER]) == 0) {
-			if (seen[B_PACKAGE_INFO_PACKAGER]) {
-				BString error = BString(names[B_PACKAGE_INFO_PACKAGER])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			BString packager;
-			_ParseStringValue(&packager);
-			packageInfo->SetPackager(packager);
-			seen[B_PACKAGE_INFO_PACKAGER] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_ARCHITECTURE]) == 0) {
-			if (seen[B_PACKAGE_INFO_ARCHITECTURE]) {
-				BString error = BString(names[B_PACKAGE_INFO_ARCHITECTURE])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			BPackageArchitecture architecture;
-			_ParseArchitectureValue(&architecture);
-			packageInfo->SetArchitecture(architecture);
-			seen[B_PACKAGE_INFO_ARCHITECTURE] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_VERSION]) == 0) {
-			if (seen[B_PACKAGE_INFO_VERSION]) {
-				BString error = BString(names[B_PACKAGE_INFO_VERSION])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			BPackageVersion version;
-			_ParseVersionValue(&version, false);
-			packageInfo->SetVersion(version);
-			seen[B_PACKAGE_INFO_VERSION] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_COPYRIGHTS]) == 0) {
-			if (seen[B_PACKAGE_INFO_COPYRIGHTS]) {
-				BString error = BString(names[B_PACKAGE_INFO_COPYRIGHTS])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			_ParseStringList(&packageInfo->fCopyrightList);
-			seen[B_PACKAGE_INFO_COPYRIGHTS] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_LICENSES]) == 0) {
-			if (seen[B_PACKAGE_INFO_LICENSES]) {
-				BString error = BString(names[B_PACKAGE_INFO_LICENSES])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			_ParseStringList(&packageInfo->fLicenseList);
-			seen[B_PACKAGE_INFO_LICENSES] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_URLS]) == 0) {
-			if (seen[B_PACKAGE_INFO_URLS]) {
-				BString error = BString(names[B_PACKAGE_INFO_URLS])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			_ParseStringList(&packageInfo->fURLList);
-			seen[B_PACKAGE_INFO_URLS] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_SOURCE_URLS]) == 0) {
-			if (seen[B_PACKAGE_INFO_SOURCE_URLS]) {
-				BString error = BString(names[B_PACKAGE_INFO_SOURCE_URLS])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			_ParseStringList(&packageInfo->fSourceURLList);
-			seen[B_PACKAGE_INFO_SOURCE_URLS] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_PROVIDES]) == 0) {
-			if (seen[B_PACKAGE_INFO_PROVIDES]) {
-				BString error = BString(names[B_PACKAGE_INFO_PROVIDES])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			_ParseResolvableList(&packageInfo->fProvidesList);
-			seen[B_PACKAGE_INFO_PROVIDES] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_REQUIRES]) == 0) {
-			if (seen[B_PACKAGE_INFO_REQUIRES]) {
-				BString error = BString(names[B_PACKAGE_INFO_REQUIRES])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			_ParseResolvableExprList(&packageInfo->fRequiresList);
-			seen[B_PACKAGE_INFO_REQUIRES] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_SUPPLEMENTS]) == 0) {
-			if (seen[B_PACKAGE_INFO_SUPPLEMENTS]) {
-				BString error = BString(names[B_PACKAGE_INFO_SUPPLEMENTS])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			_ParseResolvableExprList(&packageInfo->fSupplementsList);
-			seen[B_PACKAGE_INFO_SUPPLEMENTS] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_CONFLICTS]) == 0) {
-			if (seen[B_PACKAGE_INFO_CONFLICTS]) {
-				BString error = BString(names[B_PACKAGE_INFO_CONFLICTS])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			_ParseResolvableExprList(&packageInfo->fConflictsList);
-			seen[B_PACKAGE_INFO_CONFLICTS] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_FRESHENS]) == 0) {
-			if (seen[B_PACKAGE_INFO_FRESHENS]) {
-				BString error = BString(names[B_PACKAGE_INFO_FRESHENS])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			_ParseResolvableExprList(&packageInfo->fFreshensList);
-			seen[B_PACKAGE_INFO_FRESHENS] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_REPLACES]) == 0) {
-			if (seen[B_PACKAGE_INFO_REPLACES]) {
-				BString error = BString(names[B_PACKAGE_INFO_REPLACES])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			_ParseStringList(&packageInfo->fReplacesList, false);
-			seen[B_PACKAGE_INFO_REPLACES] = true;
-		} else if (t.text.ICompare(names[B_PACKAGE_INFO_FLAGS]) == 0) {
-			if (seen[B_PACKAGE_INFO_FLAGS]) {
-				BString error = BString(names[B_PACKAGE_INFO_FLAGS])
-					<< " already seen!";
-				throw ParseError(error, t.pos);
-			}
-
-			packageInfo->SetFlags(_ParseFlags());
-			seen[B_PACKAGE_INFO_FLAGS] = true;
 		}
+
+		if (attribute == B_PACKAGE_INFO_ENUM_COUNT) {
+			BString error = BString("unknown attribute \"") << t.text << '"';
+			throw ParseError(error, t.pos);
+		}
+
+		if (seen[attribute]) {
+			BString error = BString(names[attribute]) << " already seen!";
+			throw ParseError(error, t.pos);
+		}
+
+		switch (attribute) {
+			case B_PACKAGE_INFO_NAME:
+				_ParseStringValue(&packageInfo->fName);
+				break;
+
+			case B_PACKAGE_INFO_SUMMARY:
+			{
+				BString summary;
+				_ParseStringValue(&summary);
+				if (summary.FindFirst('\n') >= 0)
+					throw ParseError("the summary contains linebreaks", t.pos);
+				packageInfo->SetSummary(summary);
+				break;
+			}
+
+			case B_PACKAGE_INFO_DESCRIPTION:
+				_ParseStringValue(&packageInfo->fDescription);
+				break;
+
+			case B_PACKAGE_INFO_VENDOR:
+				_ParseStringValue(&packageInfo->fVendor);
+				break;
+
+			case B_PACKAGE_INFO_PACKAGER:
+				_ParseStringValue(&packageInfo->fPackager);
+				break;
+
+			case B_PACKAGE_INFO_ARCHITECTURE:
+				_ParseArchitectureValue(&packageInfo->fArchitecture);
+				break;
+
+			case B_PACKAGE_INFO_VERSION:
+				_ParseVersionValue(&packageInfo->fVersion, false);
+				break;
+
+			case B_PACKAGE_INFO_COPYRIGHTS:
+				_ParseStringList(&packageInfo->fCopyrightList);
+				break;
+
+			case B_PACKAGE_INFO_LICENSES:
+				_ParseStringList(&packageInfo->fLicenseList);
+				break;
+
+			case B_PACKAGE_INFO_URLS:
+				_ParseStringList(&packageInfo->fURLList);
+				break;
+
+			case B_PACKAGE_INFO_SOURCE_URLS:
+				_ParseStringList(&packageInfo->fSourceURLList);
+				break;
+
+			case B_PACKAGE_INFO_PROVIDES:
+				_ParseResolvableList(&packageInfo->fProvidesList);
+				break;
+
+			case B_PACKAGE_INFO_REQUIRES:
+				_ParseResolvableExprList(&packageInfo->fRequiresList);
+				break;
+
+			case B_PACKAGE_INFO_SUPPLEMENTS:
+				_ParseResolvableExprList(&packageInfo->fSupplementsList);
+				break;
+
+			case B_PACKAGE_INFO_CONFLICTS:
+				_ParseResolvableExprList(&packageInfo->fConflictsList);
+				break;
+
+			case B_PACKAGE_INFO_FRESHENS:
+				_ParseResolvableExprList(&packageInfo->fFreshensList);
+				break;
+
+			case B_PACKAGE_INFO_REPLACES:
+				_ParseStringList(&packageInfo->fReplacesList, false);
+				break;
+
+			case B_PACKAGE_INFO_FLAGS:
+				packageInfo->SetFlags(_ParseFlags());
+				break;
+
+			default:
+				// can never get here
+				break;
+		}
+
+		seen[attribute] = true;
 	}
 
 	// everything up to and including 'provides' is mandatory

From 28268808d8e956d3536ed04b2ce44a8c07a9be63 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 28 Jun 2011 18:15:36 +0200
Subject: [PATCH 0156/1170] Change source URL package info attribute name

Use "-" instead of "_".
---
 src/kits/package/hpkg/PackageContentHandler.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/kits/package/hpkg/PackageContentHandler.cpp b/src/kits/package/hpkg/PackageContentHandler.cpp
index 61878e172a..9d344e715c 100644
--- a/src/kits/package/hpkg/PackageContentHandler.cpp
+++ b/src/kits/package/hpkg/PackageContentHandler.cpp
@@ -59,7 +59,7 @@ static const char* kAttributeNames[B_HPKG_ATTRIBUTE_ID_ENUM_COUNT + 1] = {
 	"package:version.prerelease",
 	"package:provides.compatible",
 	"package:url",
-	"package:source_url",
+	"package:source-url",
 	NULL
 };
 

From 116852fecb4dc982b2f3581a9f65ff290ae79e3f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 28 Jun 2011 18:16:18 +0200
Subject: [PATCH 0157/1170] Support package info [source] URL attributes

---
 src/bin/package/command_list.cpp         |  8 ++++++++
 src/bin/package_repo/command_list.cpp    | 10 ++++++++++
 src/kits/package/hpkg/ReaderImplBase.cpp |  8 ++++++++
 src/kits/package/hpkg/WriterImplBase.cpp | 22 ++++++++++++++++++++++
 4 files changed, 48 insertions(+)

diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp
index 82a5ee53ef..efcf33685e 100644
--- a/src/bin/package/command_list.cpp
+++ b/src/bin/package/command_list.cpp
@@ -164,6 +164,14 @@ struct PackageContentListHandler : BPackageContentHandler {
 				printf("\tlicense: %s\n", value.string);
 				break;
 
+			case B_PACKAGE_INFO_URLS:
+				printf("\tURL: %s\n", value.string);
+				break;
+
+			case B_PACKAGE_INFO_SOURCE_URLS:
+				printf("\tsource URL: %s\n", value.string);
+				break;
+
 			case B_PACKAGE_INFO_PROVIDES:
 				printf("\tprovides: %s", value.resolvable.name);
 				if (value.resolvable.haveVersion) {
diff --git a/src/bin/package_repo/command_list.cpp b/src/bin/package_repo/command_list.cpp
index ad290d2065..c1ff03b683 100644
--- a/src/bin/package_repo/command_list.cpp
+++ b/src/bin/package_repo/command_list.cpp
@@ -115,6 +115,16 @@ struct RepositoryContentListHandler : BRepositoryContentHandler {
 					printf("\tlicense: %s\n", value.string);
 				break;
 
+			case B_PACKAGE_INFO_URLS:
+				if (fVerbose)
+					printf("\tURL: %s\n", value.string);
+				break;
+
+			case B_PACKAGE_INFO_SOURCE_URLS:
+				if (fVerbose)
+					printf("\tsource URL: %s\n", value.string);
+				break;
+
 			case B_PACKAGE_INFO_PROVIDES:
 				if (!fVerbose)
 					break;
diff --git a/src/kits/package/hpkg/ReaderImplBase.cpp b/src/kits/package/hpkg/ReaderImplBase.cpp
index ab3f7b461a..44706b9bf7 100644
--- a/src/kits/package/hpkg/ReaderImplBase.cpp
+++ b/src/kits/package/hpkg/ReaderImplBase.cpp
@@ -376,6 +376,14 @@ ReaderImplBase::PackageAttributeHandler::HandleAttribute(
 				value.string);
 			break;
 
+		case B_HPKG_ATTRIBUTE_ID_PACKAGE_URL:
+			fPackageInfoValue.SetTo(B_PACKAGE_INFO_URLS, value.string);
+			break;
+
+		case B_HPKG_ATTRIBUTE_ID_PACKAGE_SOURCE_URL:
+			fPackageInfoValue.SetTo(B_PACKAGE_INFO_SOURCE_URLS, value.string);
+			break;
+
 		case B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES:
 			fPackageInfoValue.resolvable.name = value.string;
 			fPackageInfoValue.attributeID = B_PACKAGE_INFO_PROVIDES;
diff --git a/src/kits/package/hpkg/WriterImplBase.cpp b/src/kits/package/hpkg/WriterImplBase.cpp
index f90f05ee57..d2b43f3025 100644
--- a/src/kits/package/hpkg/WriterImplBase.cpp
+++ b/src/kits/package/hpkg/WriterImplBase.cpp
@@ -431,6 +431,28 @@ WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList,
 		attributeList.Add(license);
 	}
 
+	// URL list
+	const BObjectList& urlList = packageInfo.URLList();
+	for (int i = 0; i < urlList.CountItems(); ++i) {
+		PackageAttribute* url = new PackageAttribute(
+			B_HPKG_ATTRIBUTE_ID_PACKAGE_URL, B_HPKG_ATTRIBUTE_TYPE_STRING,
+			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
+		url->string = fPackageStringCache.Get(urlList.ItemAt(i)->String());
+		attributeList.Add(url);
+	}
+
+	// source URL list
+	const BObjectList& sourceURLList = packageInfo.SourceURLList();
+	for (int i = 0; i < sourceURLList.CountItems(); ++i) {
+		PackageAttribute* url = new PackageAttribute(
+			B_HPKG_ATTRIBUTE_ID_PACKAGE_SOURCE_URL,
+			B_HPKG_ATTRIBUTE_TYPE_STRING,
+			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
+		url->string = fPackageStringCache.Get(
+			sourceURLList.ItemAt(i)->String());
+		attributeList.Add(url);
+	}
+
 	// provides list
 	const BObjectList& providesList
 		= packageInfo.ProvidesList();

From 1bcc0f6e4a895e130db7cedabc178edfe78d777e Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 28 Jun 2011 20:57:30 +0200
Subject: [PATCH 0158/1170] .OPD -> .PackageInfo conversion tool

---
 src/tools/Jamfile                             |   1 +
 src/tools/opd_to_package_info/Jamfile         |   9 +
 .../opd_to_package_info.cpp                   | 377 ++++++++++++++++++
 3 files changed, 387 insertions(+)
 create mode 100644 src/tools/opd_to_package_info/Jamfile
 create mode 100644 src/tools/opd_to_package_info/opd_to_package_info.cpp

diff --git a/src/tools/Jamfile b/src/tools/Jamfile
index 566e373242..dbb92b27e8 100644
--- a/src/tools/Jamfile
+++ b/src/tools/Jamfile
@@ -135,6 +135,7 @@ SubInclude HAIKU_TOP src tools hack_coff ;
 SubInclude HAIKU_TOP src tools keymap ;
 SubInclude HAIKU_TOP src tools locale ;
 SubInclude HAIKU_TOP src tools makebootable ;
+SubInclude HAIKU_TOP src tools opd_to_package_info ;
 SubInclude HAIKU_TOP src tools package ;
 SubInclude HAIKU_TOP src tools rc ;
 SubInclude HAIKU_TOP src tools remote_disk_server ;
diff --git a/src/tools/opd_to_package_info/Jamfile b/src/tools/opd_to_package_info/Jamfile
new file mode 100644
index 0000000000..11c38b2a5a
--- /dev/null
+++ b/src/tools/opd_to_package_info/Jamfile
@@ -0,0 +1,9 @@
+SubDir HAIKU_TOP src tools opd_to_package_info ;
+
+USES_BE_API on opd_to_package_info = true ;
+
+BuildPlatformMain opd_to_package_info :
+	opd_to_package_info.cpp
+	:
+	$(HOST_LIBBE) $(HOST_LIBSTDC++) $(HOST_LIBSUPC++)
+;
diff --git a/src/tools/opd_to_package_info/opd_to_package_info.cpp b/src/tools/opd_to_package_info/opd_to_package_info.cpp
new file mode 100644
index 0000000000..104a284718
--- /dev/null
+++ b/src/tools/opd_to_package_info/opd_to_package_info.cpp
@@ -0,0 +1,377 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+
+enum {
+	FLAG_MANDATORY_FIELD	= 0x01,
+	FLAG_LIST_ATTRIBUTE		= 0x02,
+	FLAG_DONT_QUOTE			= 0x04,
+};
+
+
+extern const char* __progname;
+const char* kCommandName = __progname;
+
+
+static const char* kUsage =
+	"Usage: %s [  ]  "
+		"[  ]\n"
+	"Converts an .OptionalPackageDescription to a .PackageInfo. If "
+		"\n"
+	"is not specified, the output is printed to stdout.\n"
+	"Note that the generated .PackageInfo will not be complete. For several\n"
+	"fields an empty string will be used, unless specified via an option.\n"
+	"The \"provides\" and \"requires\" lists will always be empty, though\n"
+	"\n"
+	"Options:\n"
+	"  -a         - Use the given architecture string. Default is to "
+		"guess from the file name.\n"
+	"  -d  - Use the given descripton string. Default is to use\n"
+	"                     the summary.\n"
+	"  -h, --help       - Print this usage info.\n"
+	"  -p     - Use the given packager string. Default is an empty "
+		"string.\n"
+	"  -s      - Use the given summary string. Default is an empty "
+		"string.\n"
+	"  -v      - Use the given version string. Overrides the version\n"
+	"                     from the input file.\n"
+	"  -V       - Use the given vendor string. Default is an empty "
+		"string.\n"
+;
+
+
+static void
+print_usage_and_exit(bool error)
+{
+    fprintf(error ? stderr : stdout, kUsage, kCommandName);
+    exit(error ? 1 : 0);
+}
+
+
+static const char*
+guess_architecture(const char* name)
+{
+	if (strstr(name, "x86") != NULL) {
+		if (strstr(name, "gcc4") != NULL)
+			return "x86";
+
+		return "x86_gcc2";
+	}
+
+	return NULL;
+}
+
+
+struct OuputWriter {
+	OuputWriter(FILE* output, const BMessage& package)
+		:
+		fOutput(output),
+		fPackage(package)
+	{
+	}
+
+	void WriteAttribute(const char* attributeName, const char* fieldName,
+		const char* defaultValue, uint32 flags)
+	{
+		if (fieldName != NULL) {
+			int32 count;
+			type_code type;
+			if (fPackage.GetInfo(fieldName, &type, &count) != B_OK) {
+				if ((flags & FLAG_MANDATORY_FIELD) != 0) {
+					fprintf(stderr, "Error: Missing mandatory field \"%s\" in "
+						"input file.\n", fieldName);
+					exit(1);
+				}
+				count = 0;
+			}
+
+			if (count > 0) {
+				if (count == 1) {
+					const char* value;
+					fPackage.FindString(fieldName, &value);
+					_WriteSingleElementAttribute(attributeName, value, flags);
+				} else {
+					fprintf(fOutput, "\n%s {\n", attributeName);
+
+					for (int32 i = 0; i < count; i++) {
+						fprintf(fOutput, "\t");
+						const char* value;
+						fPackage.FindString(fieldName, i, &value);
+						_WriteValue(value, flags);
+						fputc('\n', fOutput);
+					}
+
+					fputs("}\n", fOutput);
+				}
+
+				return;
+			}
+		}
+
+		// write the default value
+		if (defaultValue != NULL)
+			_WriteSingleElementAttribute(attributeName, defaultValue, flags);
+	}
+
+private:
+	void _WriteSingleElementAttribute(const char* attributeName,
+		const char* value, uint32 flags)
+	{
+		fputs(attributeName, fOutput);
+
+		int32 indentation = 16 - (int32)strlen(attributeName);
+		if (indentation > 0)
+			indentation = (indentation + 3) / 4;
+		else
+			indentation = 1;
+
+		for (int32 i = 0; i < indentation; i++)
+			fputc('\t', fOutput);
+
+		_WriteValue(value, flags);
+		fputc('\n',  fOutput);
+	}
+
+	void _WriteValue(const char* value, uint32 flags)
+	{
+		BString escapedValue(value);
+
+		if ((flags & FLAG_DONT_QUOTE) != 0) {
+			escapedValue.CharacterEscape("\\\"' \t", '\\');
+			fputs(escapedValue.String(), fOutput);
+		} else {
+			escapedValue.CharacterEscape("\\\"", '\\');
+			fprintf(fOutput, "\"%s\"", escapedValue.String());
+		}
+	}
+
+private:
+	FILE*			fOutput;
+	const BMessage&	fPackage;
+};
+
+
+int
+main(int argc, const char* const* argv)
+{
+	const char* architecture = NULL;
+	const char* version = NULL;
+	const char* summary = "";
+	const char* description = "";
+	const char* packager = "";
+	const char* vendor = "";
+
+	while (true) {
+		static const struct option kLongOptions[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ 0, 0, 0, 0 }
+		};
+
+		opterr = 0; // don't print errors
+		int c = getopt_long(argc, (char**)argv, "+ha:d:p:s:v:V:", kLongOptions,
+			NULL);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'a':
+				architecture = optarg;
+				break;
+
+			case 'd':
+				description = optarg;
+				break;
+
+			case 'h':
+				print_usage_and_exit(false);
+				break;
+
+			case 'p':
+				packager = optarg;
+				break;
+
+			case 's':
+				summary = optarg;
+				break;
+
+			case 'v':
+				version = optarg;
+				break;
+
+			case 'V':
+				vendor = optarg;
+				break;
+
+			default:
+				print_usage_and_exit(true);
+				break;
+		}
+	}
+
+	// One or two argument should remain -- the input file and optionally the
+	// output file.
+	if (optind + 1 != argc && optind + 2 != argc)
+		print_usage_and_exit(true);
+
+	const char* opdName = argv[optind++];
+	const char* packageInfoName = optind < argc ? argv[optind++] : NULL;
+
+	// guess architecture from the input file name, if not given
+	if (architecture == NULL) {
+		const char* fileName = strrchr(opdName, '/');
+		if (fileName == NULL)
+			fileName = opdName;
+		else
+			fileName++;
+
+		// Try to guess from the file name.
+		architecture = guess_architecture(fileName);
+
+		// If we've got nothing yet, try to guess from the file name.
+		if (architecture == NULL && fileName != opdName)
+			architecture = guess_architecture(opdName);
+
+		// fallback is "any"
+		if (architecture == NULL)
+			architecture = "any";
+	}
+
+	// open the input
+	FILE* input = fopen(opdName, "r");
+	if (input == NULL) {
+		fprintf(stderr, "Failed to open input file \"%s\": %s\n", opdName,
+			strerror(errno));
+		exit(1);
+	}
+
+	// open the output
+	FILE* output = packageInfoName != NULL
+		? fopen(packageInfoName, "w+") : stdout;
+	if (output == NULL) {
+		fprintf(stderr, "Failed to open output file \"%s\": %s\n",
+			packageInfoName, strerror(errno));
+		exit(1);
+	}
+
+	// read and parse the input file
+	BMessage package;
+	BString fieldName;
+	BString fieldValue;
+	char lineBuffer[LINE_MAX];
+	bool seenPackageAttribute = false;
+
+	while (char* line = fgets(lineBuffer, sizeof(lineBuffer), input)) {
+		// chop off line break
+		size_t lineLen = strlen(line);
+		if (lineLen > 0 && line[lineLen - 1] == '\n')
+			line[--lineLen] = '\0';
+
+		// flush previous field, if a new field begins, otherwise append
+		if (lineLen == 0 || !isspace(line[0])) {
+			// new field -- flush the previous one
+			if (fieldName.Length() > 0) {
+				fieldValue.Trim();
+				package.AddString(fieldName.String(), fieldValue);
+				fieldName = "";
+			}
+		} else if (fieldName.Length() > 0) {
+			// append to current field
+			fieldValue += line;
+			continue;
+		} else {
+			// bogus line -- ignore
+			continue;
+		}
+
+		if (lineLen == 0)
+			continue;
+
+		// parse new field
+		char* colon = strchr(line, ':');
+		if (colon == NULL) {
+			// bogus line -- ignore
+			continue;
+		}
+
+		fieldName.SetTo(line, colon - line);
+		fieldName.Trim();
+		if (fieldName.Length() == 0) {
+			// invalid field name
+			continue;
+		}
+
+		fieldValue = colon + 1;
+
+		if (fieldName == "Package") {
+			if (seenPackageAttribute) {
+				fprintf(stderr, "Duplicate \"Package\" attribute!\n");
+				exit(1);
+			}
+
+			seenPackageAttribute = true;
+		}
+	}
+
+	// write the output
+	OuputWriter writer(output, package);
+
+	// name
+	writer.WriteAttribute("name", "Package", NULL,
+		FLAG_MANDATORY_FIELD | FLAG_DONT_QUOTE);
+
+	// version
+	writer.WriteAttribute("version", "Version", version, FLAG_DONT_QUOTE);
+
+	// architecture
+	fprintf(output, "architecture\t%s\n", architecture);
+
+	// summary
+	fprintf(output, "summary\t\t\t\"%s\"\n", summary);
+
+	// description
+	if (description != NULL)
+		fprintf(output, "description\t\t\"%s\"\n", description);
+	else
+		fprintf(output, "description\t\t\"%s\"\n", summary);
+
+	// packager
+	fprintf(output, "packager\t\t\"%s\"\n", packager);
+
+	// vendor
+	fprintf(output, "vendor\t\t\t\"%s\"\n", vendor);
+
+	// copyrights
+	writer.WriteAttribute("copyrights", "Copyright", NULL,
+		FLAG_MANDATORY_FIELD | FLAG_LIST_ATTRIBUTE);
+
+	// licenses
+	writer.WriteAttribute("licenses", "License", NULL, FLAG_LIST_ATTRIBUTE);
+
+	// empty provides
+	fprintf(output, "\nprovides {\n}\n");
+
+	// empty requires
+	fprintf(output, "\nrequires {\n}\n");
+
+	// URLs
+	writer.WriteAttribute("urls", "URL", NULL, FLAG_LIST_ATTRIBUTE);
+
+	// source URLs
+	writer.WriteAttribute("source-urls", "SourceURL", NULL,
+		FLAG_LIST_ATTRIBUTE);
+
+	return 0;
+}

From 1ef35574eb72074ae996c537d7ff26743c6844da Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 00:04:54 +0200
Subject: [PATCH 0159/1170] package extract: Delay setting node permissions

In HandleEntry() create the file/directory with sufficient permissions
for the user and set the archived permissions in HandleEntryDone(). This
makes sure child attributes and entries can be created.
---
 src/bin/package/command_extract.cpp | 25 ++++++++++++++++++++++---
 1 file changed, 22 insertions(+), 3 deletions(-)

diff --git a/src/bin/package/command_extract.cpp b/src/bin/package/command_extract.cpp
index 7c8b19c517..d3269c883f 100644
--- a/src/bin/package/command_extract.cpp
+++ b/src/bin/package/command_extract.cpp
@@ -116,7 +116,10 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		if (S_ISREG(entry->Mode())) {
 			// create the file
 			fd = openat(parentFD, entry->Name(), O_RDWR | O_CREAT | O_EXCL,
-				entry->Mode() & ALLPERMS);
+				S_IRUSR | S_IWUSR);
+				// Note: We use read+write user permissions now -- so write
+				// operations (e.g. attributes) won't fail, but set them to the
+				// desired ones in HandleEntryDone().
 			if (fd < 0) {
 				fprintf(stderr, "Error: Failed to create file \"%s\": %s\n",
 					entry->Name(), strerror(errno));
@@ -148,8 +151,10 @@ struct PackageContentExtractHandler : BPackageContentHandler {
  		} else if (S_ISDIR(entry->Mode())) {
 			// create the directory, if necessary
 			if (!entryExists
-				&& mkdirat(parentFD, entry->Name(), entry->Mode() & ALLPERMS)
-					!= 0) {
+				&& mkdirat(parentFD, entry->Name(), S_IRWXU) != 0) {
+				// Note: We use read+write+exec user permissions now -- so write
+				// operations (e.g. attributes) won't fail, but set them to the
+				// desired ones in HandleEntryDone().
 				fprintf(stderr, "Error: Failed to create directory \"%s\": "
 					"%s\n", entry->Name(), strerror(errno));
 				return errno;
@@ -216,6 +221,20 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 
 	virtual status_t HandleEntryDone(BPackageEntry* entry)
 	{
+		// set the node permissions for non-symlinks
+		if (!S_ISLNK(entry->Mode())) {
+			// get parent FD
+			int parentFD = AT_FDCWD;
+			if (entry->Parent() != NULL)
+				parentFD = ((Token*)entry->Parent()->UserToken())->fd;
+
+			if (fchmodat(parentFD, entry->Name(), entry->Mode() & ALLPERMS,
+					/*AT_SYMLINK_NOFOLLOW*/0) != 0) {
+				fprintf(stderr, "Warning: Failed to set permissions of file "
+					"\"%s\": %s\n", entry->Name(), strerror(errno));
+			}
+		}
+
 		if (Token* token = (Token*)entry->UserToken()) {
 			delete token;
 			entry->SetUserToken(NULL);

From df18eb8718898fb7e41b9e08e213a5ea36ee137f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 00:05:19 +0200
Subject: [PATCH 0160/1170] Fix gcc 2 build by making Parser a friend

---
 headers/os/package/PackageInfo.h | 1 +
 1 file changed, 1 insertion(+)

diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h
index c1bd851acb..124a9fb3f1 100644
--- a/headers/os/package/PackageInfo.h
+++ b/headers/os/package/PackageInfo.h
@@ -138,6 +138,7 @@ public:
 
 private:
 			class Parser;
+			friend class Parser;
 
 private:
 			BString				fName;

From 64b8c37680d22e49337f52a51bff26bfdc5f1811 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 18:36:06 +0200
Subject: [PATCH 0161/1170] Move post install files to system package

---
 build/jam/HaikuImage        | 9 +--------
 build/jam/HaikuPackages     | 8 ++++++++
 data/system/boot/Bootscript | 5 +++--
 3 files changed, 12 insertions(+), 10 deletions(-)

diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage
index 32d3a04edb..57df1c2d63 100644
--- a/build/jam/HaikuImage
+++ b/build/jam/HaikuImage
@@ -307,16 +307,9 @@ SEARCH on $(networkSettingsFiles)
 	= [ FDirName $(HAIKU_TOP) data settings network ] ;
 AddFilesToHaikuImage common settings network : $(networkSettingsFiles) ;
 
-# post install scripts and fresh install indicator file
-local postInstallFiles = add_catalog_entry_attributes.sh
-	default_deskbar_items.sh mime_update.sh ;
-postInstallFiles = $(postInstallFiles:G=post-install) ;
-SEARCH on $(postInstallFiles)
-	= [ FDirName $(HAIKU_TOP) data common boot post_install ] ;
+# fresh install indicator file for the post install scripts
 SEARCH on fresh_install
 	= [ FDirName $(HAIKU_TOP) data common settings ] ;
-AddFilesToHaikuImage common boot post_install
-	: $(postInstallFiles) ;
 AddFilesToHaikuImage common settings : fresh_install ;
 
 # boot loader
diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages
index bc0cd80b3b..4df7c27625 100644
--- a/build/jam/HaikuPackages
+++ b/build/jam/HaikuPackages
@@ -154,6 +154,14 @@ local bootScripts = Bootscript Bootscript.cd SetupEnvironment Netscript
 SEARCH on $(bootScripts) = [ FDirName $(HAIKU_TOP) data system boot ] ;
 AddFilesToPackage boot : $(bootScripts) ;
 
+# post install scripts
+local postInstallFiles = add_catalog_entry_attributes.sh
+	default_deskbar_items.sh mime_update.sh ;
+postInstallFiles = $(postInstallFiles:G=post-install) ;
+SEARCH on $(postInstallFiles)
+	= [ FDirName $(HAIKU_TOP) data common boot post_install ] ;
+AddFilesToPackage boot post_install : $(postInstallFiles) ;
+
 # artwork and sounds
 local logoArtwork =
 	$(HAIKU_INCLUDE_TRADEMARKS)"HAIKU logo - white on blue - big.png"
diff --git a/data/system/boot/Bootscript b/data/system/boot/Bootscript
index e37bc59ab5..e6faaa76fa 100644
--- a/data/system/boot/Bootscript
+++ b/data/system/boot/Bootscript
@@ -178,14 +178,15 @@ if [ "$SAFEMODE" != "yes" ]; then
 fi
 
 # Check for fresh install and run post install scripts.
-postInstallDir=/boot/common/boot/post_install
+postInstallDir=boot/post_install
 freshInstallIndicator=/boot/common/settings/fresh_install
 if [ -e $freshInstallIndicator ]; then
 	# wait a moment for things to calm down a bit
 	sleep 3
 
 	# execute scripts
-	for f in $postInstallDir/*.sh; do
+	for f in /boot/system/$postInstallDir/*.sh /boot/common/$postInstallDir/*.sh
+	do
 		if [ -f $f ]; then
 			echo "Running post install script $f ..." > /dev/dprintf
 			$f

From d3deb18a2d468668e73595b3f2516abdeb4beeb8 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 18:36:17 +0200
Subject: [PATCH 0162/1170] Repackage default optional packages as hpkg files

---
 build/jam/OptionalBuildFeatures |  17 ++-
 build/jam/OptionalPackages      | 208 ++++++++++++++++++--------------
 2 files changed, 125 insertions(+), 100 deletions(-)

diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures
index 15c141d407..8b838e5e37 100644
--- a/build/jam/OptionalBuildFeatures
+++ b/build/jam/OptionalBuildFeatures
@@ -14,12 +14,12 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSL ] {
 if $(HAIKU_GCC_VERSION[1]) >= 4 {
 	HAIKU_OPENSSL_PACKAGE = openssl-1.0.0d-r1a3-x86-gcc4-2011-05-20.zip ;
 } else {
-	HAIKU_OPENSSL_PACKAGE = openssl-1.0.0d-r1a3-x86-gcc2-2011-05-17.zip ;
+	HAIKU_OPENSSL_PACKAGE = openssl-1.0.0d-1-x86_gcc2.hpkg ;
 }
 
 local baseURL = http://haiku-files.org/files/optional-packages ;
 local hpkgBaseURL = http://haiku-files.org/files/hpkg ;
-HAIKU_OPENSSL_URL = $(baseURL)/$(HAIKU_OPENSSL_PACKAGE) ;
+HAIKU_OPENSSL_URL = $(hpkgBaseURL)/$(HAIKU_OPENSSL_PACKAGE) ;
 
 if $(HAIKU_BUILD_FEATURE_SSL) {
 	if $(TARGET_ARCH) != x86 {
@@ -36,20 +36,19 @@ if $(HAIKU_BUILD_FEATURE_SSL) {
 
 		# extract headers and libraries
 		HAIKU_OPENSSL_HEADERS_DEPENDENCY = [ ExtractArchive $(HAIKU_OPENSSL_DIR)
-			: common/include/ : $(zipFile) : extracted-openssl
+			: include/ : $(zipFile) : extracted-openssl
 		] ;
 
 		HAIKU_OPENSSL_LIBS = [ ExtractArchive $(HAIKU_OPENSSL_DIR)
 			:
-			common/lib/libcrypto.so
-			common/lib/libssl.so
+			lib/libcrypto.so
+			lib/libssl.so
 			: $(zipFile)
 			: extracted-openssl
 		] ;
 
 		HAIKU_OPENSSL_ENABLED = 1 ;
-		HAIKU_OPENSSL_HEADERS
-			= [ FDirName $(HAIKU_OPENSSL_DIR) common include ] ;
+		HAIKU_OPENSSL_HEADERS = [ FDirName $(HAIKU_OPENSSL_DIR) include ] ;
 	}
 }
 
@@ -61,7 +60,7 @@ HAIKU_ICU_GCC_2_PACKAGE = icu-4.4.1-r1a3-x86-gcc2-2011-05-29.hpkg ;
 HAIKU_ICU_GCC_4_PACKAGE = icu-4.4.1-r1a3-x86-gcc4-2011-05-29.zip ;
 	# TODO: Make hpkg!
 HAIKU_ICU_PPC_PACKAGE = icu-4.4.1-ppc-2010-08-17.zip ;
-HAIKU_ICU_DEVEL_PACKAGE = icu-devel-4.4.1-2010-07-26.zip ;
+HAIKU_ICU_DEVEL_PACKAGE = icu-devel-4.4.1-1-any.hpkg ;
 
 if $(TARGET_ARCH) = ppc {
 	local icu_package = $(HAIKU_ICU_PPC_PACKAGE) ;
@@ -122,7 +121,7 @@ if $(TARGET_ARCH) = ppc {
 
 # zip file and output directory
 HAIKU_ICU_DEVEL_ZIP_FILE = [ DownloadFile $(HAIKU_ICU_DEVEL_PACKAGE)
-		: $(baseURL)/$(HAIKU_ICU_DEVEL_PACKAGE) ] ;
+		: $(hpkgBaseURL)/$(HAIKU_ICU_DEVEL_PACKAGE) ] ;
 HAIKU_ICU_DEVEL_DIR = [ FDirName $(HAIKU_OPTIONAL_BUILD_PACKAGES_DIR)
 	$(HAIKU_ICU_DEVEL_PACKAGE:B) ] ;
 
diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 11f396e54c..3410c0c7ca 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -112,9 +112,9 @@ if [ IsOptionalHaikuImagePackageAdded APR ] {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			apr-1.4.2-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/apr-1.4.2-r1a3-x86-gcc2-2011-05-17.zip
-			: : true ;
+			apr-1.4.2-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/apr-1.4.2-1-x86_gcc2.hpkg
+			: common packages ;
 	}
 }
 
@@ -130,9 +130,9 @@ if [ IsOptionalHaikuImagePackageAdded APR-util ] {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			apr-util-1.3.10-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/apr-util-1.3.10-r1a3-x86-gcc2-2011-05-17.zip
-			: : true ;
+			apr-util-1.3.10-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/apr-util-1.3.10-1-x86_gcc2.hpkg
+			: common packages ;
 	}
 }
 
@@ -255,8 +255,9 @@ if [ IsOptionalHaikuImagePackageAdded BePDF ] {
 		Echo "No optional package BePDF available for gcc4" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			bepdf-1.1.1b4-r1a3-x86-gcc2-2011-05-30.zip
-			: $(baseURL)/bepdf-1.1.1b4-r1a3-x86-gcc2-2011-05-30.zip ;
+			bepdf-1.1.1b4-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/bepdf-1.1.1b4-1-x86_gcc2.hpkg
+			: common packages ;
 		AddSymlinkToHaikuImage home config be Applications
 			: /boot/apps/BePDF/BePDF ;
 	}
@@ -341,9 +342,9 @@ if [ IsOptionalHaikuImagePackageAdded Bzip ] {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			bzip2-1.0.6-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/bzip2-1.0.6-r1a3-x86-gcc2-2011-05-17.zip
-			: : true ;
+			bzip2-1.0.6-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/bzip2-1.0.6-1-x86_gcc2.hpkg
+			: common packages ;
 	}
 }
 
@@ -374,8 +375,9 @@ if [ IsOptionalHaikuImagePackageAdded CDRecord ] {
 			: $(baseURL)/cdrtools-3.01a01-r1a3-x86-gcc4-2011-05-23.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			cdrtools-3.01a01-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/cdrtools-3.01a01-r1a3-x86-gcc2-2011-05-17.zip ;
+			cdrtools-3.00-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/cdrtools-3.00-1-x86_gcc2.hpkg
+			: common packages ;
 	}
 }
 
@@ -443,8 +445,9 @@ if [ IsOptionalHaikuImagePackageAdded Curl ] {
 		InstallOptionalHaikuImagePackage curl-7.21.7-x86-gcc4-2011-06-23.zip
 			: $(baseURL)/curl-7.21.7-x86-gcc4-2011-06-23.zip ;
 	} else {
-		InstallOptionalHaikuImagePackage curl-7.21.7-x86-gcc2-2011-06-23.zip
-			: $(baseURL)/curl-7.21.7-x86-gcc2-2011-06-23.zip ;
+		InstallOptionalHaikuImagePackage curl-7.21.6-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/curl-7.21.6-1-x86_gcc2.hpkg
+			: common packages ;
 	}
 }
 
@@ -461,9 +464,9 @@ if [ IsOptionalHaikuImagePackageAdded CVS ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				cvs-1.12.13.1-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/cvs-1.12.13.1-r1a3-x86-gcc2-2011-05-18.zip
-				: : true ;
+				cvs-1.12.13.1-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/curl-7.21.6-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -491,21 +494,21 @@ if [ IsOptionalHaikuImagePackageAdded Development ] && $(TARGET_ARCH) = x86 {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			autoconf-2.68-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/autoconf-2.68-r1a3-x86-gcc2-2011-05-17.zip
-			: : true ;
+			autoconf-2.68-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/autoconf-2.68-1-x86_gcc2.hpkg
+			: common packages ;
 		InstallOptionalHaikuImagePackage
-			automake-1.11.1-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/automake-1.11.1-r1a3-x86-gcc2-2011-05-17.zip
-			: : true ;
+			automake-1.11.1-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/automake-1.11.1-1-x86_gcc2.hpkg
+			: common packages ;
 		InstallOptionalHaikuImagePackage
-			libtool-2.4-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/libtool-2.4-r1a3-x86-gcc2-2011-05-17.zip
-			: : true ;
+			libtool-2.4-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/libtool-2.4-1-x86_gcc2.hpkg
+			: common packages ;
 		InstallOptionalHaikuImagePackage
-			texinfo-4.13a-r1a3-x86-gcc2-2011-05-18.zip
-			: $(baseURL)/texinfo-4.13a-r1a3-x86-gcc2-2011-05-18.zip
-			: : true ;
+			texinfo-4.13a-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/texinfo-4.13a-1-x86_gcc2.hpkg
+			: common packages ;
 	}
 }
 
@@ -553,22 +556,28 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 	} else {
 		InstallOptionalHaikuImagePackage
 			bison-2.4.3-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/bison-2.4.3-r1a3-x86-gcc2-2011-05-17.zip ;
+			: $(hpkgBaseURL)/bison-2.4.3-1-x86_gcc2.hpkg
+			: common packages ;
 		InstallOptionalHaikuImagePackage
-			m4-1.4.16-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/m4-1.4.16-r1a3-x86-gcc2-2011-05-17.zip ;
+			m4-1.4.16-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/m4-1.4.16-1-x86_gcc2.hpkg
+			: common packages ;
 		InstallOptionalHaikuImagePackage
-			flex-2.5.35-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/flex-2.5.35-r1a3-x86-gcc2-2011-05-17.zip ;
+			flex-2.5.35-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/flex-2.5.35-1-x86_gcc2.hpkg
+			: common packages ;
 		InstallOptionalHaikuImagePackage
-			jam-2.5-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/jam-2.5-r1a3-x86-gcc2-2011-05-17.zip ;
+			jam-2.5-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/jam-2.5-1-x86_gcc2.hpkg
+			: common packages ;
 		InstallOptionalHaikuImagePackage
-			mkdepend-1.7-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/mkdepend-1.7-r1a3-x86-gcc2-2011-05-17.zip ;
+			mkdepend-1.7-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/mkdepend-1.7-1-x86_gcc2.hpkg
+			: common packages ;
 		InstallOptionalHaikuImagePackage
-			make-3.82-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/make-3.82-r1a3-x86-gcc2-2011-05-17.zip ;
+			make-3.82-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/make-3.82-1-x86_gcc2.hpkg
+			: common packages ;
 	}
 }
 
@@ -639,9 +648,9 @@ if [ IsOptionalHaikuImagePackageAdded Expat ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				expat-2.0.1-r1a3-x86-gcc2-2011-05-20.zip
-				: $(baseURL)/expat-2.0.1-r1a3-x86-gcc2-2011-05-20.zip
-				: : true ;
+				expat-2.0.1-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/expat-2.0.1-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -719,9 +728,9 @@ if [ IsOptionalHaikuImagePackageAdded Git ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				git-1.7.5-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/git-1.7.5-r1a3-x86-gcc2-2011-05-18.zip
-				: : true ;
+				git-1.7.5-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/git-1.7.5-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -790,7 +799,8 @@ if [ IsOptionalHaikuImagePackageAdded ICU ] {
 # ICU-devel
 if [ IsOptionalHaikuImagePackageAdded ICU-devel ] {
 	InstallOptionalHaikuImagePackage $(HAIKU_ICU_DEVEL_PACKAGE)
-		: $(baseURL)/$(HAIKU_ICU_DEVEL_PACKAGE) ;
+		: $(hpkgBaseURL)/$(HAIKU_ICU_DEVEL_PACKAGE)
+		: common packages ;
 
 	local arch = $(TARGET_ARCH) ;
 	local abi = gcc$(HAIKU_GCC_VERSION[1]) ;
@@ -856,8 +866,9 @@ if [ IsOptionalHaikuImagePackageAdded LibIconv ] {
 				: $(baseURL)/libiconv-1.13.1-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				libiconv-1.13.1-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/libiconv-1.13.1-r1a3-x86-gcc2-2011-05-18.zip ;
+				libiconv-1.13.1-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/libiconv-1.13.1-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -903,8 +914,9 @@ if [ IsOptionalHaikuImagePackageAdded LibXML2 ] {
 				: $(baseURL)/libxml2-2.7.8-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				libxml2-2.7.8-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/libxml2-2.7.8-r1a3-x86-gcc2-2011-05-18.zip ;
+				libxml2-2.7.8-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/libxml2-2.7.8-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -996,9 +1008,9 @@ if [ IsOptionalHaikuImagePackageAdded Mercurial ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				mercurial-1.8.3-r1a3-x86-gcc2-2011-05-17.zip
-				: $(baseURL)/mercurial-1.8.3-r1a3-x86-gcc2-2011-05-17.zip
-				: : true ;
+				mercurial-1.8.3-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/mercurial-1.8.3-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -1015,8 +1027,9 @@ if [ IsOptionalHaikuImagePackageAdded Nano ] {
 				: $(baseURL)/nano-2.2.6-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				nano-2.2.6-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/nano-2.2.6-r1a3-x86-gcc2-2011-05-18.zip ;
+				nano-2.2.6-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/nano-2.2.6-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -1033,8 +1046,9 @@ if [ IsOptionalHaikuImagePackageAdded Neon ] {
 				: $(baseURL)/neon-0.29.6-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				neon-0.29.6-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/neon-0.29.6-r1a3-x86-gcc2-2011-05-18.zip ;
+				neon-0.29.6-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/neon-0.29.6-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -1132,8 +1146,9 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSH ] {
 				: $(baseURL)/openssh-5.8p2-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				openssh-5.8p2-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/openssh-5.8p2-r1a3-x86-gcc2-2011-05-18.zip ;
+				openssh-5.8p2-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/openssh-5.8p2-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 
 		AddUserToHaikuImage sshd : 1001 : 100 : /var/empty : /bin/true
@@ -1152,7 +1167,8 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSL ] {
 				: $(HAIKU_OPENSSL_URL) ;
 		} else {
 			InstallOptionalHaikuImagePackage $(HAIKU_OPENSSL_PACKAGE)
-				: $(HAIKU_OPENSSL_URL) ;
+				: $(HAIKU_OPENSSL_URL)
+				: common packages ;
 		}
 	}
 }
@@ -1169,8 +1185,9 @@ if [ IsOptionalHaikuImagePackageAdded P7zip ] {
 				: $(baseURL)/p7zip-9.13-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				p7zip-9.13-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/p7zip-9.13-r1a3-x86-gcc2-2011-05-18.zip ;
+				p7zip-9.13-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/p7zip-9.13-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 		AddExpanderRuleToHaikuImage "application/x-7z-compressed" : .7z
 			: "7za l \\0045s"
@@ -1215,8 +1232,9 @@ if [ IsOptionalHaikuImagePackageAdded PCRE ] {
 				: $(baseURL)/libpcre-8.12-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				libpcre-8.12-r1a3-x86-gcc2-2011-05-17.zip
-				: $(baseURL)/libpcre-8.12-r1a3-x86-gcc2-2011-05-17.zip ;
+				libpcre-8.12-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/libpcre-8.12-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -1233,8 +1251,9 @@ if [ IsOptionalHaikuImagePackageAdded Pe ] {
 				: $(baseURL)/pe-2.4.3-600-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				pe-2.4.3-600-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/pe-2.4.3-600-r1a3-x86-gcc2-2011-05-18.zip ;
+				pe-2.4.3_600-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/pe-2.4.3_600-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 		AddSymlinkToHaikuImage home config be Applications
 			: /boot/apps/Pe/Pe ;
@@ -1256,9 +1275,9 @@ if [ IsOptionalHaikuImagePackageAdded Perl ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				perl-5.10.1-r1a3-x86-gcc2-2011-05-17.zip
-				: $(baseURL)/perl-5.10.1-r1a3-x86-gcc2-2011-05-17.zip
-				: : true ;
+				perl-5.10.1-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/perl-5.10.1-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -1276,9 +1295,9 @@ if [ IsOptionalHaikuImagePackageAdded Python ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				python-2.6.7-x86-gcc2-2011-06-24.zip
-				: $(baseURL)/python-2.6.7-x86-gcc2-2011-06-24.zip
-				: : true ;
+				python-2.6.6-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/python-2.6.6-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -1330,8 +1349,9 @@ if [ IsOptionalHaikuImagePackageAdded Sed ] {
 			: $(baseURL)/sed-4.2.1-r1a3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			sed-4.2.1-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/sed-4.2.1-r1a3-x86-gcc2-2011-05-17.zip ;
+			sed-4.2.1-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/sed-4.2.1-1-x86_gcc2.hpkg
+			: common packages ;
 	}
 }
 
@@ -1347,8 +1367,9 @@ if [ IsOptionalHaikuImagePackageAdded SQLite ] {
 				: $(baseURL)/sqlite-3.7.5-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				sqlite-3.7.5-r1a3-x86-gcc2-2011-05-17.zip
-				: $(baseURL)/sqlite-3.7.5-r1a3-x86-gcc2-2011-05-17.zip ;
+				sqlite3-3.7.5-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/sqlite3-3.7.5-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -1366,9 +1387,9 @@ if [ IsOptionalHaikuImagePackageAdded Subversion ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				subversion-1.6.15-r1a3-x86-gcc2-2011-05-20.zip
-				: $(baseURL)/subversion-1.6.15-r1a3-x86-gcc2-2011-05-20.zip
-				: : true ;
+				subversion-1.6.15-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/subversion-1.6.15-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -1401,8 +1422,9 @@ if [ IsOptionalHaikuImagePackageAdded Tar ] {
 				: $(baseURL)/tar-1.25-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				tar-1.25-r1a3-x86-gcc2-2011-05-20.zip
-				: $(baseURL)/tar-1.25-r1a3-x86-gcc2-2011-05-20.zip ;
+				tar-1.25-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/tar-1.25-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 	}
 }
@@ -1529,8 +1551,9 @@ if [ IsOptionalHaikuImagePackageAdded Vision ] {
 				: $(baseURL)/vision-908-r1a3-x86-gcc4-2011-06-07.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				vision-908-r1a3-x86-gcc2-2011-06-07.zip
-				: $(baseURL)/vision-908-r1a3-x86-gcc2-2011-06-07.zip ;
+				vision-908-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/vision-908-1-x86_gcc2.hpkg
+				: common packages ;
 		}
 		AddSymlinkToHaikuImage home config be Applications
 			: /boot/apps/Vision/Vision ;
@@ -1638,8 +1661,9 @@ if [ IsOptionalHaikuImagePackageAdded WonderBrush ] {
 # WQY-MicroHei
 if [ IsOptionalHaikuImagePackageAdded WQY-MicroHei ] {
 	InstallOptionalHaikuImagePackage
-		wqy-microhei-0.2.0-beta-r1a3-x86-gcc2-2011-05-18.zip
-		: $(baseURL)/wqy-microhei-0.2.0-beta-r1a3-x86-gcc2-2011-05-18.zip ;
+		wqy-microhei-0.2.0-beta-1-x86_gcc2.hpkg
+		: $(hpkgBaseURL)/wqy-microhei-0.2.0-beta-1-x86_gcc2.hpkg
+		: common packages ;
 }
 
 
@@ -1649,8 +1673,9 @@ if [ IsOptionalHaikuImagePackageAdded XZ-Utils ] {
 		Echo "No optional package XZ-Utils available for $(TARGET_ARCH)" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			xz-utils-5.0.1-r1a3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/xz-utils-5.0.1-r1a3-x86-gcc4-2011-05-24.zip ;
+			xz-utils-5.0.1-1-x86.hpkg
+			: $(hpkgBaseURL)/xz-utils-5.0.1-1-x86.hpkg
+			: common packages ;
 		AddExpanderRuleToHaikuImage "application/x-xz" : .tar.xz
 			: "tar -Jtvf \\0045s"
 			: "tar -Jxvf \\0045s"
@@ -1677,7 +1702,8 @@ if [ IsOptionalHaikuImagePackageAdded Yasm ] {
 			: $(baseURL)/yasm-1.1.0-r1a3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			yasm-1.1.0-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/yasm-1.1.0-r1a3-x86-gcc2-2011-05-17.zip ;
+			yasm-1.1.0-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/yasm-1.1.0-1-x86_gcc2.hpkg
+			: common packages ;
 	}
 }

From 775b8d7afd5380fc018b198df853a39c22885231 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 19:05:28 +0200
Subject: [PATCH 0163/1170] _kern_read_link() ignored the path

---
 src/build/libroot/fs.cpp | 13 ++++++-------
 1 file changed, 6 insertions(+), 7 deletions(-)

diff --git a/src/build/libroot/fs.cpp b/src/build/libroot/fs.cpp
index d1f7e8bfbf..fcf09630b8 100644
--- a/src/build/libroot/fs.cpp
+++ b/src/build/libroot/fs.cpp
@@ -863,15 +863,14 @@ _kern_create_symlink(int fd, const char *path, const char *toPath, int mode)
 status_t
 _kern_read_link(int fd, const char *path, char *buffer, size_t *_bufferSize)
 {
-	// get the descriptor
-	SymlinkDescriptor *descriptor
-		= dynamic_cast(get_descriptor(fd));
-	if (!descriptor)
-		return B_FILE_ERROR;
+	// get the path
+	string realPath;
+	status_t error = get_path(fd, path, realPath);
+	if (error != B_OK)
+		return error;
 
 	// readlink
-	ssize_t bytesRead = readlink(descriptor->path.c_str(), buffer,
-		*_bufferSize);
+	ssize_t bytesRead = readlink(realPath.c_str(), buffer, *_bufferSize);
 	if (bytesRead < 0)
 		return errno;
 

From 18d457f8b22dca3069a9e9b7c9701f4c040093b9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 19:06:47 +0200
Subject: [PATCH 0164/1170] Add helper is_unknown_or_system_descriptor()

---
 src/build/libroot/fs_descriptors.cpp | 14 ++++++++++++++
 src/build/libroot/fs_descriptors.h   |  5 +++++
 2 files changed, 19 insertions(+)

diff --git a/src/build/libroot/fs_descriptors.cpp b/src/build/libroot/fs_descriptors.cpp
index 2bf311dca6..68103e341c 100644
--- a/src/build/libroot/fs_descriptors.cpp
+++ b/src/build/libroot/fs_descriptors.cpp
@@ -1,3 +1,8 @@
+/*
+ * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
 
 #ifdef BUILDING_FS_SHELL
 #	include "compat.h"
@@ -507,4 +512,13 @@ delete_descriptor(int fd)
 	return error;
 }
 
+
+bool
+is_unknown_or_system_descriptor(int fd)
+{
+	Descriptor* descriptor = get_descriptor(fd);
+	return descriptor == NULL || descriptor->IsSystemFD();
+}
+
+
 } // namespace BPrivate
diff --git a/src/build/libroot/fs_descriptors.h b/src/build/libroot/fs_descriptors.h
index 608f6f6fc6..0df18381bb 100644
--- a/src/build/libroot/fs_descriptors.h
+++ b/src/build/libroot/fs_descriptors.h
@@ -1,3 +1,7 @@
+/*
+ * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
 #ifndef FS_DESCRIPTORS_H
 #define FS_DESCRIPTORS_H
 
@@ -118,6 +122,7 @@ struct AttrDirDescriptor : DirectoryDescriptor {
 Descriptor*	get_descriptor(int fd);
 int			add_descriptor(Descriptor *descriptor);
 status_t	delete_descriptor(int fd);
+bool		is_unknown_or_system_descriptor(int fd);
 
 }	// namespace BPrivate
 

From 4dbc2457985f94d2aa46668739f73231b4b2edfb Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 19:17:17 +0200
Subject: [PATCH 0165/1170] Wrap POSIX FD functions in libroot_build

This makes opening symlinks work universally in the build system tools.
Two mechanisms have been implemented, both of which don't always work.
The first is remapping via preprocessor macros. This fails where equally
named methods are used (e.g. STL fstream::open()). The other is using
hidden functions in the new libroot_build_function_remapper.a that is
linked into everything that is linked against libroot_build.so. This one
fails for functions that are defined inline in headers (Linux/glibc does
that). Together they seem to cover our build system needs ATM.
---
 build/jam/BuildSetup                    |   2 +-
 headers/build/BeOSBuildCompatibility.h  |  87 ++++++
 src/build/libroot/Jamfile               |  14 +-
 src/build/libroot/fs.cpp                | 378 +++++++++++++++++++++++-
 src/build/libroot/function_remapper.cpp | 277 +++++++++++++++++
 src/build/libroot/remapped_functions.h  |  62 ++++
 6 files changed, 815 insertions(+), 5 deletions(-)
 create mode 100644 src/build/libroot/function_remapper.cpp
 create mode 100644 src/build/libroot/remapped_functions.h

diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup
index e36f954a56..7a9506c143 100644
--- a/build/jam/BuildSetup
+++ b/build/jam/BuildSetup
@@ -760,7 +760,7 @@ if $(HOST_PLATFORM_BEOS_COMPATIBLE) {
 	HOST_HAIKU_COMPATIBILITY_LIBS = libhaikucompat.a ;
 } else {
 	HOST_LIBSTDC++ = stdc++ ;
-	HOST_LIBROOT = libroot_build.so ;
+	HOST_LIBROOT = libroot_build_function_remapper.a libroot_build.so ;
 	HOST_STATIC_LIBROOT = libroot_build.a ;
 	HOST_LIBBE = libbe_build.so ;
 	if $(HOST_PLATFORM) = cygwin {
diff --git a/headers/build/BeOSBuildCompatibility.h b/headers/build/BeOSBuildCompatibility.h
index 3364aef138..875897ca07 100644
--- a/headers/build/BeOSBuildCompatibility.h
+++ b/headers/build/BeOSBuildCompatibility.h
@@ -32,9 +32,12 @@ typedef unsigned long	haiku_build_addr_t;
 #include 
 
 #include 
+#include 
 #include 
+#include 
 #include 
 #include 
+#include 
 
 #ifdef __cplusplus
 extern "C" {
@@ -91,6 +94,90 @@ extern char* _haiku_build_strerror(int errnum);
 
 #endif	// BUILDING_HAIKU_ERROR_MAPPER
 
+
+// remap file descriptor functions
+int		_haiku_build_fchmod(int fd, mode_t mode);
+int		_haiku_build_fchmodat(int fd, const char* path, mode_t mode, int flag);
+int		_haiku_build_fstat(int fd, struct stat* st);
+int		_haiku_build_fstatat(int fd, const char* path, struct stat* st,
+			int flag);
+int		_haiku_build_mkdirat(int fd, const char* path, mode_t mode);
+int		_haiku_build_mkfifoat(int fd, const char* path, mode_t mode);
+int		_haiku_build_utimensat(int fd, const char* path,
+			const struct timespec times[2], int flag);
+int		_haiku_build_futimens(int fd, const struct timespec times[2]);
+int		_haiku_build_faccessat(int fd, const char* path, int accessMode,
+			int flag);
+int		_haiku_build_fchdir(int fd);
+int		_haiku_build_close(int fd);
+int		_haiku_build_dup(int fd);
+int		_haiku_build_dup2(int fd1, int fd2);
+int		_haiku_build_linkat(int toFD, const char* toPath, int pathFD,
+			const char* path, int flag);
+int		_haiku_build_unlinkat(int fd, const char* path, int flag);
+ssize_t	_haiku_build_readlinkat(int fd, const char* path, char* buffer,
+			size_t bufferSize);
+int		_haiku_build_symlinkat(const char* toPath, int fd,
+			const char* symlinkPath);
+int		_haiku_build_ftruncate(int fd, off_t newSize);
+int		_haiku_build_fchown(int fd, uid_t owner, gid_t group);
+int		_haiku_build_fchownat(int fd, const char* path, uid_t owner,
+			gid_t group, int flag);
+int		_haiku_build_mknodat(int fd, const char* name, mode_t mode, dev_t dev);
+int		_haiku_build_creat(const char* path, mode_t mode);
+#ifndef _HAIKU_BUILD_DONT_REMAP_FD_FUNCTIONS
+int		_haiku_build_open(const char* path, int openMode, ...);
+int		_haiku_build_openat(int fd, const char* path, int openMode, ...);
+int		_haiku_build_fcntl(int fd, int op, ...);
+#else
+int		_haiku_build_open(const char* path, int openMode, mode_t permissions);
+int		_haiku_build_openat(int fd, const char* path, int openMode,
+			mode_t permissions);
+int		_haiku_build_fcntl(int fd, int op, int argument);
+#endif
+int		_haiku_build_renameat(int fromFD, const char* from, int toFD,
+			const char* to);
+
+#ifndef _HAIKU_BUILD_DONT_REMAP_FD_FUNCTIONS
+#	define fchmod(fd, mode)				_haiku_build_fchmod(fd, mode)
+#	define fchmodat(fd, path, mode, flag) \
+		_haiku_build_fchmodat(fd, path, mode, flag)
+#	define fstat(fd, st)				_haiku_build_fstat(fd, st)
+#	define fstatat(fd, path, st, flag)	_haiku_build_fstatat(fd, path, st, flag)
+#	define mkdirat(fd, path, mode)		_haiku_build_mkdirat(fd, path, mode)
+#	define mkfifoat(fd, path, mode)		_haiku_build_mkfifoat(fd, path, mode)
+#	define utimensat(fd, path, times, flag) \
+		_haiku_build_utimensat(fd, path, times, flag)
+#	define futimens(fd, times)			_haiku_build_futimens(fd, times)
+#	define faccessat(fd, path, accessMode, flag) \
+		_haiku_build_faccessat(fd, path, accessMode, flag)
+#	define fchdir(fd)					_haiku_build_fchdir(fd)
+#	define close(fd)					_haiku_build_close(fd)
+#	define dup(fd)						_haiku_build_dup(fd)
+#	define dup2(fd1, fd2)				_haiku_build_dup2(fd1, fd2)
+#	define linkat(toFD, toPath, pathFD, path, flag) \
+		_haiku_build_linkat(toFD, toPath, pathFD, path, flag)
+#	define unlinkat(fd, path, flag)		_haiku_build_unlinkat(fd, path, flag)
+#	define readlinkat(fd, path, buffer, bufferSize) \
+		_haiku_build_readlinkat(fd, path, buffer, bufferSize)
+#	define symlinkat(toPath, fd, symlinkPath) \
+		_haiku_build_symlinkat(toPath, fd, symlinkPath)
+#	define ftruncate(fd, newSize)		_haiku_build_ftruncate(fd, newSize)
+#	define fchown(fd, owner, group)		_haiku_build_fchown(fd, owner, group)
+#	define fchownat(fd, path, owner, group, flag) \
+		_haiku_build_fchownat(fd, path, owner, group, flag)
+#	define mknodat(fd, name, mode, dev) \
+		_haiku_build_mknodat(fd, name, mode, dev)
+#	define creat(path, mode)			_haiku_build_creat(path, mode)
+#	define open(path, openMode...)		_haiku_build_open(path, openMode)
+#	define openat(fd, path, openMode...) \
+		_haiku_build_openat(fd, path, openMode)
+#	define fcntl(fd, op...)				_haiku_build_fcntl(fd, op)
+#	define renameat(fromFD, from, toFD, to) \
+		_haiku_build_renameat(fromFD, from, toFD, to)
+#endif	// _HAIKU_BUILD_DONT_REMAP_FD_FUNCTIONS
+
+
 #ifdef __cplusplus
 } // extern "C"
 #endif
diff --git a/src/build/libroot/Jamfile b/src/build/libroot/Jamfile
index a739eedd42..d704520320 100644
--- a/src/build/libroot/Jamfile
+++ b/src/build/libroot/Jamfile
@@ -14,6 +14,7 @@ UsePrivateBuildHeaders kernel libroot ;
 {
 	local defines = [ FDefines
 		HAIKU_BUILD_ATTRIBUTES_DIR="\\\"$(HAIKU_BUILD_ATTRIBUTES_DIR)\\\""
+		_HAIKU_BUILD_DONT_REMAP_FD_FUNCTIONS=1
 	] ;
 	SubDirCcFlags $(defines) ;
 	SubDirC++Flags $(defines) ;
@@ -79,9 +80,16 @@ BuildPlatformSharedLibrary libroot_build.so :
 	$(HOST_LIBSUPC++) $(HOST_LIBSTDC++)
 ;
 
-BuildPlatformStaticLibrary libroot_build.a :
-	:
-	[ FGristFiles $(librootSources:S=$(SUFOBJ)) ]
+# TODO: This doesn't work with the function remapping.
+#BuildPlatformStaticLibrary libroot_build.a :
+#	:
+#	[ FGristFiles $(librootSources:S=$(SUFOBJ)) ]
+#;
+
+USES_BE_API on [ FGristFiles function_remapper$(SUFOBJ) ] = true ;
+
+BuildPlatformStaticLibraryPIC libroot_build_function_remapper.a :
+	function_remapper.cpp
 ;
 
 SEARCH on [ FGristFiles driver_settings.cpp ]
diff --git a/src/build/libroot/fs.cpp b/src/build/libroot/fs.cpp
index fcf09630b8..afecd425d8 100644
--- a/src/build/libroot/fs.cpp
+++ b/src/build/libroot/fs.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2005-2008, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
  * Distributed under the terms of the MIT License.
  */
 
@@ -16,6 +16,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -26,6 +27,7 @@
 
 #include "fs_descriptors.h"
 #include "NodeRef.h"
+#include "remapped_functions.h"
 
 #if defined(HAIKU_HOST_PLATFORM_FREEBSD)
 #	include "fs_freebsd.h"
@@ -48,6 +50,16 @@ using namespace BPrivate;
 #	define haiku_host_platform_writev	writev
 #endif
 
+#define RETURN_AND_SET_ERRNO(err)			\
+	do {									\
+		__typeof(err) __result = (err);		\
+		if (__result < 0) {					\
+			errno = __result;				\
+			return -1;						\
+		}									\
+		return __result;					\
+	} while (0)
+
 
 static status_t get_path(dev_t device, ino_t node, const char *name,
 	string &path);
@@ -1033,3 +1045,367 @@ writev_pos(int fd, off_t pos, const struct iovec *vec, size_t count)
 
 	return bytesWritten;
 }
+
+
+// #pragma mark -
+
+
+int
+_haiku_build_fchmod(int fd, mode_t mode)
+{
+	return _haiku_build_fchmodat(fd, NULL, mode, AT_SYMLINK_NOFOLLOW);
+}
+
+
+int
+_haiku_build_fchmodat(int fd, const char* path, mode_t mode, int flag)
+{
+	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
+		return fchmodat(fd, path, mode, flag);
+
+	struct stat st;
+	st.st_mode = mode;
+
+	RETURN_AND_SET_ERRNO(_kern_write_stat(fd, path,
+		(flag & AT_SYMLINK_NOFOLLOW) == 0, &st, sizeof(st), B_STAT_MODE));
+}
+
+
+int
+_haiku_build_fstat(int fd, struct stat* st)
+{
+	return _haiku_build_fstatat(fd, NULL, st, AT_SYMLINK_NOFOLLOW);
+}
+
+
+int
+_haiku_build_fstatat(int fd, const char* path, struct stat* st, int flag)
+{
+	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
+		return fstatat(fd, path, st, flag);
+
+	RETURN_AND_SET_ERRNO(_kern_read_stat(fd, path,
+		(flag & AT_SYMLINK_NOFOLLOW) == 0, st, sizeof(*st)));
+}
+
+
+int
+_haiku_build_mkdirat(int fd, const char* path, mode_t mode)
+{
+	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
+		return mkdirat(fd, path, mode);
+
+	RETURN_AND_SET_ERRNO(_kern_create_dir(fd, path, mode));
+}
+
+
+int
+_haiku_build_mkfifoat(int fd, const char* path, mode_t mode)
+{
+	return mkfifoat(fd, path, mode);
+
+	// TODO: Handle non-system FDs.
+}
+
+
+int
+_haiku_build_utimensat(int fd, const char* path, const struct timespec times[2],
+	int flag)
+{
+	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
+		return utimensat(fd, path, times, flag);
+
+	struct stat stat;
+	status_t status;
+	uint32 mask = 0;
+
+	// Init the stat time fields to the current time, if at least one time is
+	// supposed to be set to it.
+	if (times == NULL || times[0].tv_nsec == UTIME_NOW
+		|| times[1].tv_nsec == UTIME_NOW) {
+		timeval now;
+		gettimeofday(&now, NULL);
+		stat.st_atim.tv_sec = stat.st_mtim.tv_sec = now.tv_sec;
+		stat.st_atim.tv_nsec = stat.st_mtim.tv_nsec = now.tv_usec * 1000;
+	}
+
+	if (times != NULL) {
+		// access time
+		if (times[0].tv_nsec != UTIME_OMIT) {
+			mask |= B_STAT_ACCESS_TIME;
+
+			if (times[0].tv_nsec != UTIME_NOW) {
+				if (times[0].tv_nsec < 0 || times[0].tv_nsec > 999999999)
+					RETURN_AND_SET_ERRNO(EINVAL);
+			}
+
+			stat.st_atim = times[0];
+		}
+
+		// modified time
+		if (times[1].tv_nsec != UTIME_OMIT) {
+			mask |= B_STAT_MODIFICATION_TIME;
+
+			if (times[1].tv_nsec != UTIME_NOW) {
+				if (times[1].tv_nsec < 0 || times[1].tv_nsec > 999999999)
+					RETURN_AND_SET_ERRNO(EINVAL);
+			}
+
+			stat.st_mtim = times[1];
+		}
+	} else
+		mask |= B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME;
+
+	// set the times -- as per spec we even need to do this, if both have
+	// UTIME_OMIT set
+	status = _kern_write_stat(fd, path, (flag & AT_SYMLINK_NOFOLLOW) == 0,
+		&stat, sizeof(struct stat), mask);
+
+	RETURN_AND_SET_ERRNO(status);
+}
+
+
+int
+_haiku_build_futimens(int fd, const struct timespec times[2])
+{
+	return _haiku_build_utimensat(fd, NULL, times, AT_SYMLINK_NOFOLLOW);
+}
+
+
+int
+_haiku_build_faccessat(int fd, const char* path, int accessMode, int flag)
+{
+	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
+		return faccessat(fd, path, accessMode, flag);
+
+	// stat the file
+	struct stat st;
+	status_t error = _kern_read_stat(fd, path, false, &st, sizeof(st));
+	if (error != B_OK)
+		RETURN_AND_SET_ERRNO(error);
+
+	// get the current user
+	uid_t uid = (flag & AT_EACCESS) != 0 ? geteuid() : getuid();
+
+	int fileMode = 0;
+
+	if (uid == 0) {
+		// user is root
+		// root has always read/write permission, but at least one of the
+		// X bits must be set for execute permission
+		fileMode = R_OK | W_OK;
+		if ((st.st_mode & (S_IXUSR | S_IXGRP | S_IXOTH)) != 0)
+			fileMode |= X_OK;
+	} else if (st.st_uid == uid) {
+		// user is node owner
+		if ((st.st_mode & S_IRUSR) != 0)
+			fileMode |= R_OK;
+		if ((st.st_mode & S_IWUSR) != 0)
+			fileMode |= W_OK;
+		if ((st.st_mode & S_IXUSR) != 0)
+			fileMode |= X_OK;
+	} else if (st.st_gid == ((flag & AT_EACCESS) != 0 ? getegid() : getgid())) {
+		// user is in owning group
+		if ((st.st_mode & S_IRGRP) != 0)
+			fileMode |= R_OK;
+		if ((st.st_mode & S_IWGRP) != 0)
+			fileMode |= W_OK;
+		if ((st.st_mode & S_IXGRP) != 0)
+			fileMode |= X_OK;
+	} else {
+		// user is one of the others
+		if ((st.st_mode & S_IROTH) != 0)
+			fileMode |= R_OK;
+		if ((st.st_mode & S_IWOTH) != 0)
+			fileMode |= W_OK;
+		if ((st.st_mode & S_IXOTH) != 0)
+			fileMode |= X_OK;
+	}
+
+	if ((accessMode & ~fileMode) != 0)
+		RETURN_AND_SET_ERRNO(EACCES);
+
+	return 0;
+}
+
+
+int
+_haiku_build_fchdir(int fd)
+{
+	if (is_unknown_or_system_descriptor(fd))
+		return fchdir(fd);
+
+	RETURN_AND_SET_ERRNO(B_FILE_ERROR);
+}
+
+
+int
+_haiku_build_close(int fd)
+{
+	if (get_descriptor(fd) == NULL)
+		return close(fd);
+
+	RETURN_AND_SET_ERRNO(_kern_close(fd));
+}
+
+
+int
+_haiku_build_dup(int fd)
+{
+	if (get_descriptor(fd) == NULL)
+		return close(fd);
+
+	RETURN_AND_SET_ERRNO(_kern_dup(fd));
+}
+
+
+int
+_haiku_build_dup2(int fd1, int fd2)
+{
+	if (is_unknown_or_system_descriptor(fd1))
+		return dup2(fd1, fd2);
+
+	// TODO: Handle non-system FDs.
+	RETURN_AND_SET_ERRNO(B_NOT_SUPPORTED);
+}
+
+
+int
+_haiku_build_linkat(int toFD, const char* toPath, int pathFD, const char* path,
+	int flag)
+{
+	return linkat(toFD, toPath, pathFD, path, flag);
+
+	// TODO: Handle non-system FDs.
+}
+
+
+int
+_haiku_build_unlinkat(int fd, const char* path, int flag)
+{
+	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
+		return unlinkat(fd, path, flag);
+
+	RETURN_AND_SET_ERRNO(_kern_unlink(fd, path));
+}
+
+
+ssize_t
+_haiku_build_readlinkat(int fd, const char* path, char* buffer,
+	size_t bufferSize)
+{
+	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
+		return readlinkat(fd, path, buffer, bufferSize);
+
+	status_t error = _kern_read_link(fd, path, buffer, &bufferSize);
+	if (error != B_OK)
+		RETURN_AND_SET_ERRNO(error);
+
+	return bufferSize;
+}
+
+
+int
+_haiku_build_symlinkat(const char* toPath, int fd, const char* symlinkPath)
+{
+	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
+		return symlinkat(toPath, fd, symlinkPath);
+
+	RETURN_AND_SET_ERRNO(_kern_create_symlink(fd, symlinkPath, toPath,
+		S_IRWXU | S_IRWXG | S_IRWXO));
+}
+
+
+int
+_haiku_build_ftruncate(int fd, off_t newSize)
+{
+	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
+		return ftruncate(fd, newSize);
+
+	struct stat st;
+	st.st_size = newSize;
+
+	RETURN_AND_SET_ERRNO(_kern_write_stat(fd, NULL, false, &st, sizeof(st),
+		B_STAT_SIZE));
+}
+
+
+int
+_haiku_build_fchown(int fd, uid_t owner, gid_t group)
+{
+	return _haiku_build_fchownat(fd, NULL, owner, group, AT_SYMLINK_NOFOLLOW);
+}
+
+
+int
+_haiku_build_fchownat(int fd, const char* path, uid_t owner, gid_t group,
+	int flag)
+{
+	if (fd >= 0 && fd != AT_FDCWD && get_descriptor(fd) == NULL)
+		return fchownat(fd, path, owner, group, flag);
+
+	struct stat st;
+	st.st_uid = owner;
+	st.st_gid = group;
+
+	RETURN_AND_SET_ERRNO(_kern_write_stat(fd, path,
+		(flag & AT_SYMLINK_NOFOLLOW) == 0, &st, sizeof(st),
+		B_STAT_UID | B_STAT_GID));
+}
+
+
+int
+_haiku_build_mknodat(int fd, const char* name, mode_t mode, dev_t dev)
+{
+	return mknodat(fd, name, mode, dev);
+
+	// TODO: Handle non-system FDs.
+}
+
+
+int
+_haiku_build_creat(const char* path, mode_t mode)
+{
+	return _haiku_build_open(path, O_WRONLY | O_CREAT | O_TRUNC, mode);
+}
+
+
+int
+_haiku_build_open(const char* path, int openMode, mode_t permissions)
+{
+	return _haiku_build_openat(AT_FDCWD, path, openMode, permissions);
+}
+
+
+int
+_haiku_build_openat(int fd, const char* path, int openMode, mode_t permissions)
+{
+	// adapt the permissions as required by POSIX
+	mode_t mask = umask(0);
+	umask(mask);
+	permissions &= ~mask;
+
+	RETURN_AND_SET_ERRNO(_kern_open(fd, path, openMode, permissions));
+}
+
+
+int
+_haiku_build_fcntl(int fd, int op, int argument)
+{
+	if (is_unknown_or_system_descriptor(fd))
+		return fcntl(fd, op, argument);
+
+	RETURN_AND_SET_ERRNO(B_NOT_SUPPORTED);
+}
+
+
+int
+_haiku_build_renameat(int fromFD, const char* from, int toFD, const char* to)
+{
+	if ((fromFD >= 0 && fromFD != AT_FDCWD && get_descriptor(fromFD) == NULL)
+		|| (toFD >= 0 && toFD != AT_FDCWD && get_descriptor(toFD) == NULL)) {
+		return renameat(fromFD, from, toFD, to);
+	}
+
+	RETURN_AND_SET_ERRNO(_kern_rename(fromFD, from, toFD, to));
+}
diff --git a/src/build/libroot/function_remapper.cpp b/src/build/libroot/function_remapper.cpp
new file mode 100644
index 0000000000..35121f3e2c
--- /dev/null
+++ b/src/build/libroot/function_remapper.cpp
@@ -0,0 +1,277 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include 
+
+#include "remapped_functions.h"
+
+
+#if __GNUC__ >= 4
+#	define HIDDEN_FUNCTION(function)	do {} while (0)
+#	define HIDDEN_FUNCTION_ATTRIBUTE	__attribute__((visibility("hidden")))
+#else
+#	define HIDDEN_FUNCTION(function)	asm volatile(".hidden " #function)
+#	define HIDDEN_FUNCTION_ATTRIBUTE
+#endif
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+fchmod(int fd, mode_t mode)
+{
+	HIDDEN_FUNCTION(fchmod);
+
+	return _haiku_build_fchmod(fd, mode);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+fchmodat(int fd, const char* path, mode_t mode, int flag)
+{
+	HIDDEN_FUNCTION(fchmodat);
+
+	return _haiku_build_fchmodat(fd, path, mode, flag);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+fstat(int fd, struct stat* st)
+{
+	HIDDEN_FUNCTION(fstat);
+
+	return _haiku_build_fstat(fd, st);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+fstatat(int fd, const char* path, struct stat* st, int flag)
+{
+	HIDDEN_FUNCTION(fstatat);
+
+	return _haiku_build_fstatat(fd, path, st, flag);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+mkdirat(int fd, const char* path, mode_t mode)
+{
+	HIDDEN_FUNCTION(mkdirat);
+
+	return _haiku_build_mkdirat(fd, path, mode);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+mkfifoat(int fd, const char* path, mode_t mode)
+{
+	HIDDEN_FUNCTION(mkfifoat);
+
+	return _haiku_build_mkfifoat(fd, path, mode);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+utimensat(int fd, const char* path, const struct timespec times[2], int flag)
+{
+	HIDDEN_FUNCTION(utimensat);
+
+	return _haiku_build_utimensat(fd, path, times, flag);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+futimens(int fd, const struct timespec times[2])
+{
+	HIDDEN_FUNCTION(futimens);
+
+	return _haiku_build_futimens(fd, times);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+faccessat(int fd, const char* path, int accessMode, int flag)
+{
+	HIDDEN_FUNCTION(faccessat);
+
+	return _haiku_build_faccessat(fd, path, accessMode, flag);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+fchdir(int fd)
+{
+	HIDDEN_FUNCTION(fchdir);
+
+	return _haiku_build_fchdir(fd);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+close(int fd)
+{
+	HIDDEN_FUNCTION(close);
+
+	return _haiku_build_close(fd);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+dup(int fd)
+{
+	HIDDEN_FUNCTION(dup);
+
+	return _haiku_build_dup(fd);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+dup2(int fd1, int fd2)
+{
+	HIDDEN_FUNCTION(dup2);
+
+	return _haiku_build_dup2(fd1, fd2);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+linkat(int toFD, const char* toPath, int pathFD, const char* path, int flag)
+{
+	HIDDEN_FUNCTION(linkat);
+
+	return _haiku_build_linkat(toFD, toPath, pathFD, path, flag);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+unlinkat(int fd, const char* path, int flag)
+{
+	HIDDEN_FUNCTION(unlinkat);
+
+	return _haiku_build_unlinkat(fd, path, flag);
+}
+
+
+extern "C" ssize_t HIDDEN_FUNCTION_ATTRIBUTE
+readlinkat(int fd, const char* path, char* buffer, size_t bufferSize)
+{
+	HIDDEN_FUNCTION(readlinkat);
+
+	return _haiku_build_readlinkat(fd, path, buffer, bufferSize);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+symlinkat(const char* toPath, int fd, const char* symlinkPath)
+{
+	HIDDEN_FUNCTION(symlinkat);
+
+	return _haiku_build_symlinkat(toPath, fd, symlinkPath);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+ftruncate(int fd, off_t newSize)
+{
+	HIDDEN_FUNCTION(ftruncate);
+
+	return _haiku_build_ftruncate(fd, newSize);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+fchown(int fd, uid_t owner, gid_t group)
+{
+	HIDDEN_FUNCTION(fchown);
+
+	return _haiku_build_fchown(fd, owner, group);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+fchownat(int fd, const char* path, uid_t owner, gid_t group, int flag)
+{
+	HIDDEN_FUNCTION(fchownat);
+
+	return _haiku_build_fchownat(fd, path, owner, group, flag);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+mknodat(int fd, const char* name, mode_t mode, dev_t dev)
+{
+	HIDDEN_FUNCTION(mknodat);
+
+	return _haiku_build_mknodat(fd, name, mode, dev);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+creat(const char* path, mode_t mode)
+{
+	HIDDEN_FUNCTION(RESOLVE(creat));
+
+	return _haiku_build_creat(path, mode);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+open(const char* path, int openMode, ...)
+{
+	HIDDEN_FUNCTION(open);
+
+	mode_t permissions = 0;
+	if ((openMode & O_CREAT) != 0) {
+		va_list args;
+		va_start(args, openMode);
+		mode_t mask = umask(0);
+		umask(mask);
+		permissions = va_arg(args, int);
+		va_end(args);
+	}
+
+	return _haiku_build_open(path, openMode, permissions);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+openat(int fd, const char* path, int openMode, ...)
+{
+	HIDDEN_FUNCTION(openat);
+
+	mode_t permissions = 0;
+	if ((openMode & O_CREAT) != 0) {
+		va_list args;
+		va_start(args, openMode);
+		mode_t mask = umask(0);
+		umask(mask);
+		permissions = va_arg(args, int);
+		va_end(args);
+	}
+
+	return _haiku_build_openat(fd, path, openMode, permissions);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+fcntl(int fd, int op, ...)
+{
+	HIDDEN_FUNCTION(fcntl);
+
+	va_list args;
+	va_start(args, op);
+	int argument = va_arg(args, int);
+	va_end(args);
+
+	return _haiku_build_fcntl(fd, op, argument);
+}
+
+
+extern "C" int HIDDEN_FUNCTION_ATTRIBUTE
+renameat(int fromFD, const char* from, int toFD, const char* to)
+{
+	HIDDEN_FUNCTION(renameat);
+
+	return _haiku_build_renameat(fromFD, from, toFD, to);
+}
diff --git a/src/build/libroot/remapped_functions.h b/src/build/libroot/remapped_functions.h
new file mode 100644
index 0000000000..6b940e72e9
--- /dev/null
+++ b/src/build/libroot/remapped_functions.h
@@ -0,0 +1,62 @@
+/*
+ * Copyright 2005-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef REMAPPED_FUNCTIONS_H
+#define REMAPPED_FUNCTIONS_H
+
+
+#include 
+#include 
+#include 
+#include 
+
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+int		_haiku_build_fchmod(int fd, mode_t mode);
+int		_haiku_build_fchmodat(int fd, const char* path, mode_t mode, int flag);
+int		_haiku_build_fstat(int fd, struct stat* st);
+int		_haiku_build_fstatat(int fd, const char* path, struct stat* st,
+			int flag);
+int		_haiku_build_mkdirat(int fd, const char* path, mode_t mode);
+int		_haiku_build_mkfifoat(int fd, const char* path, mode_t mode);
+int		_haiku_build_utimensat(int fd, const char* path,
+			const struct timespec times[2], int flag);
+int		_haiku_build_futimens(int fd, const struct timespec times[2]);
+int		_haiku_build_faccessat(int fd, const char* path, int accessMode,
+			int flag);
+int		_haiku_build_fchdir(int fd);
+int		_haiku_build_close(int fd);
+int		_haiku_build_dup(int fd);
+int		_haiku_build_dup2(int fd1, int fd2);
+int		_haiku_build_linkat(int toFD, const char* toPath, int pathFD,
+			const char* path, int flag);
+int		_haiku_build_unlinkat(int fd, const char* path, int flag);
+ssize_t	_haiku_build_readlinkat(int fd, const char* path, char* buffer,
+			size_t bufferSize);
+int		_haiku_build_symlinkat(const char* toPath, int fd,
+			const char* symlinkPath);
+int		_haiku_build_ftruncate(int fd, off_t newSize);
+int		_haiku_build_fchown(int fd, uid_t owner, gid_t group);
+int		_haiku_build_fchownat(int fd, const char* path, uid_t owner,
+			gid_t group, int flag);
+int		_haiku_build_mknodat(int fd, const char* name, mode_t mode, dev_t dev);
+int		_haiku_build_creat(const char* path, mode_t mode);
+int		_haiku_build_open(const char* path, int openMode, mode_t permissions);
+int		_haiku_build_openat(int fd, const char* path, int openMode,
+			mode_t permissions);
+int		_haiku_build_fcntl(int fd, int op, int argument);
+int		_haiku_build_renameat(int fromFD, const char* from, int toFD,
+			const char* to);
+
+
+#ifdef __cplusplus
+} // extern "C"
+#endif
+
+
+#endif	// REMAPPED_FUNCTIONS_H

From e954868b707861fe2dcc53c053ac5600134eec5c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 19:18:21 +0200
Subject: [PATCH 0166/1170] Disable function remapping via macros

STL fstream::open() is used, so the macros break the build.
---
 src/tools/locale/Jamfile | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/tools/locale/Jamfile b/src/tools/locale/Jamfile
index 37ef8daab7..32fdc0ccef 100644
--- a/src/tools/locale/Jamfile
+++ b/src/tools/locale/Jamfile
@@ -12,6 +12,10 @@ local localetools =
 	collectcatkeys
 ;
 
+# Due to the use of STL fstream open() mapping the function names via macro
+# name doesn't work.
+DEFINES += _HAIKU_BUILD_DONT_REMAP_FD_FUNCTIONS ;
+
 USES_BE_API on $(localetools) = true ;
 
 UseLibraryHeaders icu ;

From bd530a0800c184d4fcc0091fa4c7949697e58b1d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 19:19:03 +0200
Subject: [PATCH 0167/1170] Remove the build platform work-arounds

---
 src/kits/package/hpkg/PackageWriterImpl.cpp | 69 +--------------------
 1 file changed, 1 insertion(+), 68 deletions(-)

diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 86893eca91..dd12e7f90e 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -41,74 +41,7 @@ using BPrivate::FileDescriptorCloser;
 static const char* const kPublicDomainLicenseName = "Public Domain";
 
 
-// We need to remap a few file operations on non-Haiku platforms, so dealing
-// with symlinks works correctly.
-#ifndef __HAIKU__
-
-
-extern "C" int _kern_open(int fd, const char *path, int openMode, int perms);
-extern "C" status_t _kern_close(int fd);
-extern "C" status_t _kern_read_stat(int fd, const char *path, bool traverseLink,
-	struct stat *st, size_t statSize);
-
-
-static int
-build_openat(int dirFD, const char* fileName, int openMode, int permissions)
-{
-	int fd = _kern_open(dirFD, fileName, openMode, permissions);
-	if (fd < 0) {
-		errno = fd;
-		return -1;
-	}
-
-	return fd;
-}
-
-
-static int
-build_fstat(int fd, struct stat* st)
-{
-	status_t error = _kern_read_stat(fd, NULL, false, st, sizeof(struct stat));
-	if (error != B_OK) {
-		errno = error;
-		return -1;
-	}
-
-	return 0;
-}
-
-
-struct BuildFileDescriptorCloser {
-	BuildFileDescriptorCloser(int fd)
-		:
-		fFD(fd)
-	{
-	}
-
-	~BuildFileDescriptorCloser()
-	{
-		if (fFD >= 0)
-			_kern_close(fFD);
-	}
-
-private:
-	int	fFD;
-};
-
-
-#undef openat
-#define openat(dirFD, fileName, openMode) \
-	build_openat(dirFD, fileName, openMode, 0)
-
-#undef fstat
-#define fstat(fd, st)	build_fstat(fd, st)
-
-#undef FileDescriptorCloser
-#define FileDescriptorCloser	BuildFileDescriptorCloser
-
-
-#endif
-
+#include 
 
 namespace BPackageKit {
 

From a6e73cb9e8addfe832c064bfcb68067f1c2fa3eb Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 19:23:45 +0200
Subject: [PATCH 0168/1170] Remove installoptionalpackage

---
 build/jam/HaikuImage            |  12 -
 build/jam/HaikuPackages         |   2 -
 build/jam/ImageRules            |  17 -
 data/bin/installoptionalpackage | 934 --------------------------------
 4 files changed, 965 deletions(-)
 delete mode 100755 data/bin/installoptionalpackage

diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage
index 57df1c2d63..3df7638b4c 100644
--- a/build/jam/HaikuImage
+++ b/build/jam/HaikuImage
@@ -201,18 +201,6 @@ include [ FDirName $(HAIKU_BUILD_RULES_DIR) HaikuPackages ] ;
 AddFilesToHaikuImage system packages : haiku.hpkg ;
 
 
-# TODO: remove!
-# Add the files to be used by installoptionalpackage.
-AddDirectoryToHaikuImage common data optional-packages ;
-local optional-pkg-files = OptionalBuildFeatures OptionalPackageDependencies
-	OptionalPackages OptionalLibPackages ;
-for name in $(optional-pkg-files) {
-	local file = [ FDirName $(HAIKU_TOP) build jam $(name) ] ;
-	AddFilesToHaikuImage common data optional-packages
-		: $(file) ;
-}
-AddInstalledPackagesFileToHaikuImage ;
-
 AddSymlinkToHaikuImage home Desktop : /boot/home : Home ;
 
 # Mailbox folders and symlink
diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages
index 4df7c27625..6205b76d86 100644
--- a/build/jam/HaikuPackages
+++ b/build/jam/HaikuPackages
@@ -130,8 +130,6 @@ AddFilesToPackage demos			: $(SYSTEM_DEMOS) ;
 
 SEARCH on which = [ FDirName $(HAIKU_TOP) data bin ] ;
 AddFilesToPackage bin : which ;
-SEARCH on installoptionalpackage = [ FDirName $(HAIKU_TOP) data bin ] ;
-AddFilesToPackage bin : installoptionalpackage ;
 SEARCH on install-wifi-firmwares.sh = [ FDirName $(HAIKU_TOP) data bin ] ;
 AddFilesToPackage bin : install-wifi-firmwares.sh ;
 
diff --git a/build/jam/ImageRules b/build/jam/ImageRules
index 813517e899..4869ce89b5 100644
--- a/build/jam/ImageRules
+++ b/build/jam/ImageRules
@@ -999,23 +999,6 @@ rule AddExpanderRuleToHaikuImage mimetype : extension : list : extract
 		: $(entry) ;
 }
 
-rule AddInstalledPackagesFileToHaikuImage
-{
-	#AddInstalledPackagesFileToHaikuImage
-	local file = InstalledPackages ;
-
-	Always $(file) ;
-	MakeLocate $(file) : $(HAIKU_COMMON_PLATFORM_OBJECT_DIR) ;
-	BuildHaikuImageInstalledPackagesFile $(file) ;
-	AddFilesToHaikuImage common data optional-packages
-		: $(file) ;
-}
-
-actions BuildHaikuImageInstalledPackagesFile
-{
-	echo -e "$(HAIKU_ADDED_OPTIONAL_PACKAGES)" | tr '\ ' '\n'  > $(1)
-}
-
 rule AddOptionalPackageDescriptionToHaikuImage file : searchPath
 {
 	if $(searchPath) {
diff --git a/data/bin/installoptionalpackage b/data/bin/installoptionalpackage
deleted file mode 100755
index db6e5a6bb3..0000000000
--- a/data/bin/installoptionalpackage
+++ /dev/null
@@ -1,934 +0,0 @@
-#!/bin/bash
-#
-# Copyright (c) 2009-2010 Haiku Inc. All rights reserved.
-# Distributed under the terms of the MIT License.
-#
-# Authors:
-#		Matt Madia, mattmadia@gmail.com
-#
-# Synopsis:
-#	Provides a controlled mechanism for end-users to install certain pre-built
-#	OptionalPackages. The script will determine the host information: the
-#	default GCC, availability of secondary GCC libs, and revision. Using this
-#	information, the user will be limited to the appropriate OptionalPackages
-#	that were available for that specific revision.
-#
-DISCLAIMER="\
-Disclaimer:\n\
-  This is a temporary solution for installing OptionalPackages.\n\
-  In time, there will be an official package manager.\n\
-  See these URL's for information on the in-development package manager.\n\
-    http://dev.haiku-os.org/wiki/PackageManagerIdeas\n\
-    http://dev.haiku-os.org/wiki/PackageFormat\n\
-	"
-
-USAGE="\
-Usage: ./installoptionalpackage [ [ ...]]\n\
-  or   ./installoptionalpackage [-a|-s  [ ...]]\n\
-  or   ./installoptionalpackage [-f|-h|-l]\n\
-\n\
-Options:\n\
--a     Add one or more packages and all dependencies\n\
--s     Show the final list of packages that would be installed\n\
--f     Remove cached data and list installable packages\n\
--h     Print this help.\n\
--l     List installable packages\n\
-	"
-
-declare -A availablePackages
-declare availablePackagesKeys=""
-declare wantsToInstall=""
-declare alreadyInstalled=""
-# Some Packages cannot be installed,
-# as they require either the source code or compiled binaries
-declare packageIgnoreList="Bluetooth Development DevelopmentMin \
-DevelopmentBase MandatoryPackages UserlandFS Welcome WifiFirmwareScriptData \
-ICU-devel ICU "
-
-
-function CreateInstallerScript()
-{
-	# This function will create a secondary script, containing all of the
-	# information needed to install the optional package and its dependencies
-
-#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-	cat << EOF > ${tmpDir}/install-optpkg.sh
-#!/bin/bash
-
-tmpDir=${tmpDir}
-HAIKU_GCC_VERSION[1]=${HAIKU_GCC_VERSION[1]}
-isHybridBuild=${isHybridBuild}
-TARGET_ARCH=${TARGET_ARCH}
-HAIKU_IMAGE_HOST_NAME=`uname -n`
-#TODO: possibly add a CLI option to execute InstallSourceArchive
-HAIKU_INCLUDE_SOURCES=0
-$urlLine
-$sslPkgLine
-$sslUrlLine
-declare -a functionArgs
-expanderRulesFile=`finddir B_COMMON_DATA_DIRECTORY`/expander.rules
-if [ -f \${expanderRulesFile} ] ; then
-	expanderRulesFileExists=1
-fi
-
-
-function ParseFunctionArguments()
-{
-	# ParseFunctionArguments 
-	# Parse arguments for Jam wrapper functions into an array.
-	IN="\$@"
- 	OIFS=\$IFS
- 	IFS=":"
-
- 	local count=0
-	functionArgs=( )
-	for x in \$IN
-	do
-		functionArgs[\${count}]="\${x}"
-		((count++))
-	done
- 	IFS=\$OIFS
-}
-
-
-function TrimLeadingSpace()
-{
-	# TrimLeadingSpace 
-	eval local text='\$'"\$1"
-	local _outvar="\$1"
-
- 	local length=\${#text}
- 	((length--))
- 	if [ "\${text:0:1}" == ' ' ] ; then
- 		text=\${text#' '}
- 	fi
-
-	eval \$_outvar="'\$text'"
-}
-
-
-function TrimEndingSpace()
-{
-	# TrimEndingSpace 
-	eval local text='\$'"\$1"
-	local _outvar="\$1"
-
- 	local length=\${#text}
- 	((length--))
- 	if [ "\${text:\$length}" == ' ' ] ; then
- 		text=\${text%' '}
- 	fi
-
-	eval \$_outvar="'\$text'"
-}
-
-
-function Exit()
-{
-	# Exit 
-	# Wrapper for Jam rule
-	echo "\$@"
-	exit 1
-}
-
-
-function InstallOptionalHaikuImagePackage()
-{
-	# InstallOptionalHaikuImagePackage package : url : dirTokens : isCDPackage
-
-	# Wrapper for Jam rule
-	echo "Installing \$1 ..."
-	cd \$tmpDir
-
-	archiveFile=\`echo \$3 | sed -s "s/http.*\///"\`
-	if ! [ -f \$archiveFile ] ; then
-		echo "Downloading \$3 ..."
-		# TODO : add some error handling for downloads
-		local attempt=1
-		while [ \`wget -nv \$3 ; echo \$? \` -ne 0 ]; do
-			if [ \$attempt -eq 5 ]; then
-				break
-			fi
-			(( attempt++ ))
-			echo "Download attempt #\$attempt failed. Retrying ..."
-			if [ -e \$archiveFile ]; then
-				rm \$archiveFile
-			fi
-		done
-		if [ \$attempt -ge 5 ]; then
-			if [ -e \$archiveFile ]; then
-				rm \$archiveFile
-			fi
-			Exit "Max download retries exceeded. Halting installation."
-		fi
-	fi
-
-	local dirTokens='/boot'
-	local count=4
-	local i=0
-	for possibleToken in "\$@" ; do
-		if [ \$i -lt \$count ] ; then
-			((i++))
-		else
-			((i++))
-			if [ "\$possibleToken" != ':' ] ; then
-				dirTokens=\${dirTokens}/\$possibleToken
-			else
-				break
-			fi
-		fi
-	done
-	echo "Extracting \$archiveFile ..."
-	extractDir="\${dirTokens}"
-
-	local errorMessage="
-...Failed while extracting \$archiveFile
-You may need to manually clean up the partially extracted files.
-	"
-	case "\$archiveFile" in
-		*.zip)
-			unzip -q -o -d "\$extractDir" "\$archiveFile" \
-			|| Exit "\$errorMessage"
-			;;
-		*.tgz|*.tar.gz)
-			tar -C "\$extractDir" -xf "\$archiveFile" \
-			|| Exit "\$errorMessage"
-			;;
-		*)
-			echo "Unhandled archive extension in InstallOptionalHaikuImagePackage()"
-			exit 1
-			;;
-	esac
-
-	if [ -f '/boot/.OptionalPackageDescription' ] ; then
-		rm '/boot/.OptionalPackageDescription'
-	fi
-	rm "\$archiveFile"
-}
-
-
-function InstallSourceArchive()
-{
-	if [ \$HAIKU_INCLUDE_SOURCES -gt 0 ]; then
-		echo "InstallSourceArchive is not implemented."
-	fi
-}
-
-
-function AddSymlinkToHaikuImage()
-{
-	# AddSymlinkToHaikuImage  :  [ :  ]
-	# Wrapper for Jam rule
- 	ParseFunctionArguments "\$@"
-
- 	local dirTokens="/boot/\${functionArgs[0]}"
- 	TrimLeadingSpace dirTokens
-	TrimEndingSpace dirTokens
- 	dirTokens=\${dirTokens//' '/\/}
-
- 	local linkTarget="\${functionArgs[1]}"
- 	TrimLeadingSpace linkTarget
-	TrimEndingSpace linkTarget
-
- 	local linkName="\${functionArgs[2]}"
- 	TrimLeadingSpace linkName
-	TrimEndingSpace linkName
-
-	mkdir -p "\${dirTokens}"
-
-	if [ "\${linkName}" == '' ] ; then
-		ln -sf "\${linkTarget}" -t "\${dirTokens}"
-	else
-		ln -sf "\${linkTarget}" "\${dirTokens}/\${linkName}"
-	fi
-}
-
-
-function AddUserToHaikuImage()
-{
-	# AddUserToHaikuImage user : uid : gid : home : shell : realName
-	# Wrapper for Jam rule
-	ParseFunctionArguments "\$@"
-
-	local user=\${functionArgs[0]}
- 	local uid=\${functionArgs[1]}
- 	local gid=\${functionArgs[2]}
- 	local home=\${functionArgs[3]}
- 	local shell=\${functionArgs[4]}
- 	local realName=\${functionArgs[5]}
-
- 	passwdLine="\${user}:x:\${uid}:\${gid}:\${realName}:\${home}:\${shell}"
- 	passwdLine=\${passwdLine//' :'/':'}
- 	passwdLine=\${passwdLine//': '/':'}
-
- 	local length=\${#passwdLine}
- 	((length--))
- 	if [ "\${passwdLine:\$length}" == ' ' ] ; then
- 		passwdLine=\${passwdLine%' '}
- 	fi
-
- 	passwdFile="\`finddir B_COMMON_ETC_DIRECTORY\`/passwd"
- 	touch \${passwdFile}
-
- 	local userExists=1
- 	while read line ; do
-		if [ "\${passwdLine}" == "\${line}" ] ; then
-			userExists=0
-		fi
-	done < \${passwdFile}
-
-	if [ \$userExists -ge 1 ] ; then
-		echo "\${passwdLine}" >> \${passwdFile}
-	fi
-}
-
-
-function AddExpanderRuleToHaikuImage()
-{
-	# AddExpanderRuleToHaikuImage  :  :  : 
-	# Wrapper for Jam rule
-	ParseFunctionArguments "\$@"
-
-	local mimetype=\${functionArgs[0]}
-	local extension=\${functionArgs[1]}
-	local list=\${functionArgs[2]}
-	local extract=\${functionArgs[3]}
-
-	# clean up the variables
-	TrimLeadingSpace mimetype
-	TrimEndingSpace mimetype
-	TrimLeadingSpace extension
-	TrimEndingSpace extension
-	TrimLeadingSpace list
-	TrimEndingSpace list
-	TrimLeadingSpace extract
-	TrimEndingSpace extract
-	local rule_raw="\${mimetype}\\t\${extension}\\t\${list}\\t\${extract}"
-
-	# reset this at every invocation
-	ruleFound=
-
-	if [ \${expanderRulesFileExists} ] ; then
-		# Check if a rule for the mimetype & extension exists.
-		while read line ; do
-			existing_rule=`echo \$line | awk '{ print \$1\$2 }'`
-			if [ "\${mimetype}\${extension}" == "\${existing_rule}" ] ; then
-				ruleFound=1
-				break
-			fi
-		done < "\${expanderRulesFile}"
-	fi
-	if ! [ \${expanderRulesFileExists} ] || ! [ \${ruleFound} ] ; then
-		# Either expander.rules does not exist or a rule for mimetype &
-		# extension does not exist. Output the new rule directly to it.
-		echo -e \${rule_raw} >> \${expanderRulesFile}
-	fi
-}
-
-
-EOF
-#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
-	cat ${tmpDir}/optpkg.stage2 >> ${tmpDir}/install-optpkg.sh
-	rm ${tmpDir}/optpkg.stage2
-}
-
-
-function ContainsSubstring()
-{
-	# ContainsSubstring  
-	local string="$1"
-	local substring="$2"
-	local newString=${string/${substring}/''}
-	if [ ${#string} -eq `expr ${#newString} + ${#substring}` ] ; then
-		return 0
-	fi
-	return 1
-}
-
-
-function ErrorExit()
-{
-	echo $1
-	exit 1
-}
-
-
-function Init()
-{
-
-	# Set up some directory paths
-	baseDir=`finddir B_COMMON_DATA_DIRECTORY`/optional-packages
-	tmpDir=`finddir B_COMMON_TEMP_DIRECTORY`
-	libDir=`finddir B_SYSTEM_LIB_DIRECTORY`
-
-	installedPackagesFile="${baseDir}/InstalledPackages"
-
-	# Make sure these files are empty.
-	echo "" > ${tmpDir}/optpkg.jam
-	echo "" > ${tmpDir}/optpkg.stage1
-
-	if ! [ -d ${baseDir} ] ; then
-		mkdir -p ${baseDir}
-	fi
-
-	DetectSystemConfiguration
-	DownloadAllBuildFiles
-	ReadInstalledPackagesIntoMemory
-	ReadPackageNamesIntoMemory
-}
-
-
-function DownloadAllBuildFiles()
-{
-	# DownloadAllBuildFiles
-	# Retreive the necessary jam files from svn.
-	local buildFiles="OptionalPackages OptionalPackageDependencies \
-		OptionalBuildFeatures OptionalLibPackages"
-	for file in ${buildFiles} ; do
-		GetBuildFile ${file}
-	done
-
-}
-
-
-function GetBuildFile()
-{
-	# GetBuildFile 
-	# Downloads files from Haiku's svn
-	local buildfile="$1"
-	if ! [ -f ${baseDir}/${buildfile} ] ; then
-		echo "Fetching ${buildfile} ..."
-		cd ${baseDir}
-		local baseURL=http://dev.haiku-os.org/export/
-		local revision=`uname -v | awk '{print $1}' | sed -e 's/r//'`
-		local url="${baseURL}${revision}/haiku/trunk/build/jam/${buildfile}"
-		wget -q ${url} || ErrorExit "...failed to download $buildfile"
-	fi
-}
-
-
-function DetectSystemConfiguration()
-{
-
-	# Determine which GCC we're running
-	if [ -f "$libDir"/libsupc++.so ] ; then
-		HAIKU_GCC_VERSION[1]=4
-	else
-		HAIKU_GCC_VERSION[1]=2
-	fi
-
-	# Test for hybrid
-	if [ -d "$libDir"/gcc4 -a -d "$libDir"/gcc2 ]; then
-		echo "Sorry, but your build appears to be broken ..."
-		echo "Both gcc2 and gcc4 subdirs exist."
-		exit 1
-	elif [ -d "$libDir"/gcc4 -o -d "$libDir"/gcc2 ]; then
-		isHybridBuild=1
-	else
-		isHybridBuild=""
-	fi
-
-	# Determine the Architecture.
-	if [ `uname -m` == "BePC" ] ; then
-		TARGET_ARCH='x86'
-	else
-		echo "Sorry, x86 only for now."
-		exit 1
-	fi
-}
-
-
-function ReadInstalledPackagesIntoMemory()
-{
-	while read line ; do
-		alreadyInstalled="${alreadyInstalled} $line"
-		packageIgnoreList=${packageIgnoreList/"${line} "/' '}
-	done < ${installedPackagesFile}
-}
-
-
-function ReadPackageNamesIntoMemory()
-{
-	local file="${baseDir}/OptionalPackageNames"
-	if ! [ -f ${file} ] ; then
-		GeneratePackageNames
-	fi
-
-	# read list into associative array
-	while read line ; do
-		local pkg=`echo ${line} | awk '{print $1}'`
-		local pkgDeps=${line/"${pkg} :"/}
-		availablePackages[${pkg}]="${pkgDeps}"
-		availablePackagesKeys="${availablePackagesKeys} ${pkg}"
-	done < ${file}
-}
-
-
-function GeneratePackageNames()
-{
-	# GeneratePackageNames
-	# Creates a file containing available package names
-	# Each line shows a pakage and all of its recrusive dependencies
-	# " :   ..."
-	echo "Generating a list of Package Names ..."
-
-	local file="${baseDir}/OptionalPackageNames"
-	if [ -e "${file}" ]; then
-		rm "${file}"
-	fi
-
-	local regExp='/^if\ \[\ IsOptionalHaikuImagePackageAdded/p'
-	sed -n -e "$regExp" ${baseDir}/OptionalPackages > ${file}.temp
-	sed -n -e "$regExp" ${baseDir}/OptionalLibPackages >> ${file}.temp
-	while read line ; do
-		# in each non-filtered line, the 4th word is the optional package
-		local pkg=`echo ${line} | awk '{print $4}'`
-
-		nonRepeatingDeps=""
-		GetPackageDependencies "$pkg"
-		local lowerCasePkg=`echo ${pkg} | tr '[A-Z]' '[a-z]'`
-		if ! ContainsSubstring "${alreadyInstalled} " "${pkg} " ; then
-			if IsPackageAndDepsOkToInstall ${pkg} ; then
-				echo "${lowerCasePkg} : ${pkg} ${nonRepeatingDeps}"  >> ${file}
-			fi
-		fi
-
-	done < ${file}.temp
-	rm ${file}.temp
-}
-
-
-function GetPackageDependencies()
-{
-	# GetPackageDependencies 
-
-	# parse OptionalPackageDependencies for the single line that defines
-	# this optional package's dependencies.
-	local regExp="^OptionalPackageDependencies\ ${1}\ \:"
-	local inputFile="${baseDir}/OptionalPackageDependencies"
-
-	# print that single line
-	sed -n -e "/${regExp}\ /p" ${inputFile} > ${tmpDir}/optpkg.temp
-
-	# strip out "OptionalPackageDependencies PackageName :"
-	# this leaves " .... ;"
-	tempDeps=`sed -e "s/${regExp}\ //" ${tmpDir}/optpkg.temp`
-
-	for foo in ${tempDeps%' ;'} ; do
-		# Prevent duplicate entries of the same dependency package.
-		if ! ContainsSubstring "${nonRepeatingDeps} " "${foo} " ; then
-			nonRepeatingDeps="$foo $nonRepeatingDeps "
-			nonRepeatingDeps="${nonRepeatingDeps//  / }"
-		fi
-	done
-
-	# Recursively get the dependencies of these dependencies.
-	for dep in ${tempDeps%' ;'} ; do
-		GetPackageDependencies "$dep"
-	done
-
-}
-
-
-function IsPackageAndDepsOkToInstall()
-{
-	# IsPackageAndDepsOkToInstall 
-	if ContainsSubstring "${packageIgnoreList}" "${1}"; then
-		#echo "...warning: ${1} cannot be installed"
-		return 1
-	fi
-	for foo in ${nonRepeatingDeps} ; do
-		if ContainsSubstring "${packageIgnoreList}" "${foo}"; then
-			#echo "...warning: ${1} cannot be installed because of ${foo}"
-			return 1
-		fi
-	done
-	return 0
-}
-
-
-function BuildListOfRequestedPackages()
-{
-	if [ "$1" = '-a' ] || [ "$1" = '-s' ]; then
-		shift
-	fi
-	while [ $# -gt 0 ]; do
-		local lowerCase=`echo $1 | tr '[A-Z]' '[a-z]'`
-		wantsToInstall="${wantsToInstall} $lowerCase"
-		shift
-	done
-}
-
-
-function AddPackages()
-{
-	# AddPackages
-
-	# If one or more packages can be installed, do it.
-	if BuildFinalListOfPackagesToInstall ; then
-
-		for package in ${packagesToInstall} ; do
-			# output the "if [ IsOptionalHaikuImagePackageAdded..." code block
-			local regExp="if\ \[\ IsOptionalHaikuImagePackageAdded\ ${package}\ "
-			for inputFile in OptionalPackages OptionalLibPackages ; do
-				sed -n "/^$regExp/,/^\}/p" "${baseDir}/${inputFile}" >> ${tmpDir}/optpkg.jam
-			done
-		done
-
-		ConvertJamToBash "${tmpDir}/optpkg.jam"
-		rm "${tmpDir}/optpkg.jam"
-		CreateInstallerScript
-		sh ${tmpDir}/install-optpkg.sh
-		exitcode=$?
-		if [ $exitcode -gt 0 ]; then
-			ErrorExit "... something went wrong when installing packages."
-		fi
-		rm ${tmpDir}/install-optpkg.sh
-
-		# update files to account for the newly installed packages
-		alreadyInstalled="${alreadyInstalled} ${packagesToInstall} "
-		RecordInstalledPackages
-		GeneratePackageNames
-		echo "... done."
-	fi
-}
-
-
-function BuildFinalListOfPackagesToInstall()
-{
-	# BuildFinalListOfPackagesToInstall
-
-	packagesToInstall=""
-	proceedWithInstallation=false
-
-	for desiredPackage in ${wantsToInstall}; do
-		if IsPackageNameValid $desiredPackage  ; then
-			for item in ${availablePackages[${desiredPackage}]} ; do
-				if ! ContainsSubstring "${packagesToInstall}" "${item}" ; then
-					packagesToInstall="${packagesToInstall} ${item}"
-				fi
-			done
-			proceedWithInstallation=true
-		fi
-	done
-	# pad the variable
-	packagesToInstall="${packagesToInstall} "
-	# remove entries that are already installed
-	for skip in ${alreadyInstalled}; do
-		packagesToInstall=${packagesToInstall/"${skip} "/}
-	done
-	# strip double spaces
-	packagesToInstall=${packagesToInstall/"  "/" "}
-
-	if ! [ ${#packagesToInstall} -gt 1 ]; then
-		echo "... no packages need to be installed."
-		echo ""
-		echo "If you wish to re-install a package, run these two commands"
-		echo "    rm ${baseDir}/OptionalPackageNames"
-		echo "    open $installedPackagesFile"
-		echo "and delete the line containing the package name(s)."
-		echo ""
-		proceedWithInstallation=false
-	fi
-	if ! $proceedWithInstallation ; then
-		echo 'Not proceeding with installation.'
-		return 1
-	fi
-	echo "To be installed: ${packagesToInstall}"
-	return 0
-}
-
-
-function IsPackageNameValid()
-{
-	# IsPackageNameValid 
-	for name in ${availablePackagesKeys} ; do
-		if [ "$1" == "$name" ] ; then
-			return 0
-		fi
-	done
-	return 1
-}
-
-
-function RecordInstalledPackages()
-{
-	echo -e ${alreadyInstalled} | tr '\ ' '\n' | sort > ${installedPackagesFile}
-}
-
-
-function ConvertJamToBash()
-{
-	# ConvertJamToBash 
-	# The main Jam-to-Bash conversion function.
-	local inputFile=$1
-	declare -a generatedBash
-	countGenBashLine=0
-
-	# Parse out some variable declarations
-
-	# TODO : add these following variables to the CreateInstallerScript
-	# TODO : parse HAIKU_ICU_GCC_2_PACKAGE
-	#local regExp='/^HAIKU_ICU_GCC_2_PACKAGE/p'
-	#icuGcc2PkgLine=`sed -n -e "$regExp" ${baseDir}/OptionalBuildFeatures`
-	#ConvertVariableDeclarationLines "$regExp" 'icuGcc2PkgLine'
-
-	# TODO : parse HAIKU_ICU_GCC_4_PACKAGE
-	#local regExp='/^HAIKU_ICU_GCC_4_PACKAGE/p'
-	#icuGcc4PkgLine=`sed -n -e "$regExp" ${baseDir}/OptionalBuildFeatures`
-	#ConvertVariableDeclarationLines "$regExp" 'icuGcc4PkgLine'
-
-	# TODO : parse HAIKU_ICU_DEVEL_PACKAGE
-	#local regExp='/^HAIKU_ICU_DEVEL_PACKAGE/p'
-	#icuDevelPkgLine=`sed -n -e "$regExp" ${baseDir}/OptionalBuildFeatures`
-	#ConvertVariableDeclarationLines "$regExp" 'icuDevelPkgLine'
-
-	local regExp='/^HAIKU_OPENSSL_PACKAGE/p'
-	sslPkgLine=`sed -n -e "$regExp" ${baseDir}/OptionalBuildFeatures`
-	ConvertVariableDeclarationLines "$regExp" 'sslPkgLine'
-
-	local regExp='/^HAIKU_OPENSSL_URL/p'
-	sslUrlLine=`sed -n -e "$regExp" ${baseDir}/OptionalBuildFeatures`
-	ConvertVariableDeclarationLines "$regExp" 'sslUrlLine'
-
-	local regExp='/^local\ baseURL/p'
-	urlLine=`sed -n -e "$regExp" ${baseDir}/OptionalPackages`
-	urlLine=${urlLine/local\ /''}
-	ConvertVariableDeclarationLines "$regExp" 'urlLine'
-
-	# Convert the easy bits.
-	while read line ; do
-		line=${line/'Echo'/'echo'}
-
-		# TODO: add support for converting for loops.
-		# 		will need to introduce curly brace counting
-		ConvertIfStatements "$line"
-		ConvertVariables "$line"
-		#ReplaceComparators "$line"
-
-		line=${line/"IsOptionalHaikuImagePackageAdded"/'"SomeText" !='}
-		generatedBash[$countGenBashLine]=${line}
-		((countGenBashLine++))
-	done < ${tmpDir}/optpkg.jam
-
-	# output stage 1 generated code
-	local i=0
-	while [ $i -lt $countGenBashLine ] ; do
-		echo ${generatedBash[$i]} >> ${tmpDir}/optpkg.stage1
-		((i++))
-	done
-
-	# This converts multi-line jam statements into a single line.
-	# --- Start awk ---
-	awk '
-		/InstallOptionalHaikuImagePackage/,/\;/{
-			isRule=1;
-			if($0~/\;/) ORS="\n";
-			else ORS=" "; print
-		}
-		/AddSymlinkToHaikuImage/,/\;/{
-			isRule=1;
-			if($0~/\;/) ORS="\n";
-			else ORS=" "; print
-		}
-		/AddUserToHaikuImage/,/\;/{
-			isRule=1;
-			if($0~/\;/) ORS="\n";
-			else ORS=" "; print
-		}
-		/AddExpanderRuleToHaikuImage/,/\;/{
-			isRule=1;
-			if($0~/\;/) ORS="\n";
-			else ORS=" "; print
-		}
-		/Exit/,/\;/{
-			isRule=1;
-			if($0~/\;/) ORS="\n";
-			else ORS=" "; print
-		}
-		{
-			if($1!='InstallOptionalHaikuImagePackage' && isRule!=1 && $1!="\;")
-		 	print $0
-		}
-		{ isRule=0; }
-		' ${tmpDir}/optpkg.stage1 > ${tmpDir}/optpkg.stage2 2>/dev/null
-	# --- End awk ---
-	rm ${tmpDir}/optpkg.stage1
-}
-
-
-function ConvertVariableDeclarationLines()
-{
-	# ConvertVariableDeclarationLines  
-	# One of the Jam-to-Bash conversion functions.
-	# Jam lines that define variables need to be parsed differently.
-	eval local input='$'"$2"
-	local regex="$1"
-	local _outvar="$2"
-
-	input=${input/\ =\ /=}
-	input=${input/\;/''}
-	input=${input//\(/'{'}
-	input=${input//\)/'}'}
-
-	eval $_outvar="'$input'"
-}
-
-
-function ConvertIfStatements()
-{
-	# ConvertIfStatements 
-	# One of the Jam-to-Bash conversion functions.
-	line=${line//'} else {'/'else '}
-	line=${line//'} else if '/'elif '}
-	if ContainsSubstring "$line" "if " ; then
-		if ! ContainsSubstring "$line" "if [" ; then
-			line=${line/'if '/'if [ '}
-		fi
-
-		if ContainsSubstring "$line" '] {' ; then
-			line=${line/'{'/' ; then'}
-		elif ContainsSubstring "$line" '{' ; then
-			line=${line/'{'/' ] ; then'}
-		fi
-
-		for compound in '&&' '||' ; do
-			if ContainsSubstring "$line" "$compound" ; then
-				line=${line/"$compound"/"] $compound ["}
-			fi
-		done
-		ReplaceComparators "$line"
-	fi
-	# Assume all remaining closing braces are part of if statements
-	line=${line/'}'/'fi'}
-}
-
-
-function ConvertVariables()
-{
-	# ConvertVariables
-	# One of the Jam-to-Bash conversion functions.
-
-	# NOTE: jam's variables are normally '$(VARIABLE)'. \n
-	# 		The issue is with '(' and ')', so let's replace them globally.
-	if ContainsSubstring "$line" '$(' ; then
-		line=${line//'('/'{'}
-		line=${line//')'/'}'}
-	fi
-}
-
-
-function ReplaceComparators()
-{
-	# ReplaceComparators 
-	# One of the Jam-to-Bash conversion functions.
-
-	# Preserve string comparators for TARGET_ARCH.
-	if ! ContainsSubstring "$line" 'TARGET_ARCH' ; then
-		line=${line//'>='/'-ge'}
-		line=${line//'<='/'-le'}
-		line=${line//'>'/'-gt'}
-		line=${line//'<'/'-lt'}
-		line=${line//'!='/'-ne'}
-		line=${line//'='/'-eq'}
-	fi
-}
-
-
-function DisplayUsage()
-{
-	echo -e "$DISCLAIMER"
-	echo -e "$USAGE"
-}
-
-
-function RemoveCachedFiles()
-{
-	# RemoveCachedFiles
-	echo "Removing cached files ..."
-	if [ -e ${baseDir}/OptionalPackageNames ]; then
-		rm ${baseDir}/OptionalPackageNames
-	fi
-
-	# Unset variables, which prevents duplicate entries.
-	declare -A availablePackages
-	declare availablePackagesKeys=""
-
-	# Reinitialize
-	Init
-}
-
-
-function ListPackages()
-{
-	# ListPackages
-	echo ""
-	echo "Optional Packages that have been installed:"
-	echo ${alreadyInstalled}
-
-	echo ""
-	echo ""
-	echo "Installable Optional Packages:"
-
-	# single line:
-	echo ${availablePackagesKeys}
-
-	# one per line:
-	#for package in ${availablePackagesKeys} ; do
-	#	echo ${package}
-	#done
-}
-
-
-# If no arguments were passed to the script, display its usage and exit.
-if [ "$#" -lt 1 ] ; then
-	DisplayUsage
-	exit 0
-else
-	Init
-fi
-
-# Support `installoptionalpackage   ...`
-if [ "$1" != '-f' ] && [ "$1" != '-l' ] && [ "$1" != '-h' ] \
-	&& [ "$1" != '-s' ]; then
-	BuildListOfRequestedPackages $@
-	AddPackages
-	exit 0
-fi
-
-# Parse the arguments given to the script.
-while getopts "as:fhl" opt; do
-	case $opt in
-		a)
-			BuildListOfRequestedPackages $@
-			AddPackages
-			exit 0
-			;;
-		f)
-			RemoveCachedFiles
-			ListPackages
-			exit 0
-			;;
-		h)
-			DisplayUsage
-			exit 0
-			;;
-		l)
-			ListPackages
-			exit 0
-			;;
-		s)
-			BuildListOfRequestedPackages $@
-			BuildFinalListOfPackagesToInstall
-			exit 0
-			;;
-		\?)
-			echo "Invalid option: -$OPTARG" >&2
-			exit 1
-			;;
-		:)
-			echo "Option -$OPTARG requires an argument." >&2
-			exit 1
-			;;
-	esac
-done

From 075913f32d78b62c8b9ea13c7834515ae83fa482 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 20:28:07 +0200
Subject: [PATCH 0169/1170] Move gutenprint data files to system

---
 build/jam/HaikuImage                  | 5 -----
 build/jam/HaikuPackages               | 5 +++++
 src/libs/print/libgutenprint/config.h | 8 ++++----
 3 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage
index 3df7638b4c..bf38df590d 100644
--- a/build/jam/HaikuImage
+++ b/build/jam/HaikuImage
@@ -339,11 +339,6 @@ AddDirectoryToHaikuImage home config settings printers Preview
 AddDirectoryToHaikuImage home config settings printers "Save as PDF"
 	: home-config-settings-printers-save-as-pdf.rdef ;
 
-# Gutenprint data files
-CopyDirectoryToHaikuImage common data
-	: [ FDirName $(HAIKU_TOP) src libs print libgutenprint src xml ]
-	: gutenprint : -x .svn -x *.c -x Makefile.am -x Makefile.in ;
-
 # dvb channel settings
 CopyDirectoryToHaikuImage home config settings Media
 	: [ FDirName $(HAIKU_TOP) data settings media dvb ]
diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages
index 6205b76d86..e043cfff58 100644
--- a/build/jam/HaikuPackages
+++ b/build/jam/HaikuPackages
@@ -160,6 +160,11 @@ SEARCH on $(postInstallFiles)
 	= [ FDirName $(HAIKU_TOP) data common boot post_install ] ;
 AddFilesToPackage boot post_install : $(postInstallFiles) ;
 
+# Gutenprint data files
+CopyDirectoryToPackage data
+	: [ FDirName $(HAIKU_TOP) src libs print libgutenprint src xml ]
+	: gutenprint : -x .svn -x *.c -x Makefile.am -x Makefile.in ;
+
 # artwork and sounds
 local logoArtwork =
 	$(HAIKU_INCLUDE_TRADEMARKS)"HAIKU logo - white on blue - big.png"
diff --git a/src/libs/print/libgutenprint/config.h b/src/libs/print/libgutenprint/config.h
index 3c59527c90..9bc3e99cfd 100644
--- a/src/libs/print/libgutenprint/config.h
+++ b/src/libs/print/libgutenprint/config.h
@@ -3,10 +3,10 @@
 
 /* CUPS data directory. */
 /* Not used in Haiku */
-#define CUPS_DATADIR "/boot/common/data/cups"
+#define CUPS_DATADIR "/system/data/cups"
 
 /* Not used in Haiku */
-#define CUPS_MODELDIR "/boot/common/data/model/gutenprint/5.2/"
+#define CUPS_MODELDIR "/system/data/model/gutenprint/5.2/"
 
 /* */
 /* Not used in Haiku */
@@ -153,7 +153,7 @@
 #define PACKAGE_DATA_DIR "/system/data/gutenprint"
 
 /* */
-#define PACKAGE_LIB_DIR "/boot/common/lib/gutenprint"
+#define PACKAGE_LIB_DIR "/system/lib/gutenprint"
 
 /* */
 #define PACKAGE_LOCALE_DIR "/NOT_USED/locale"
@@ -171,7 +171,7 @@
 #define PACKAGE_VERSION "5.2.7"
 
 /* */
-#define PKGMODULEDIR "/boot/common/lib/gutenprint/5.2/modules"
+#define PKGMODULEDIR "/system/lib/gutenprint/5.2/modules"
 
 /* */
 #define PKGXMLDATADIR "/system/data/gutenprint"

From 78c665f2c3ba57d4e7758d99f8a8123aed64a81e Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 20:42:48 +0200
Subject: [PATCH 0170/1170] lpe symlink is in the pe package now

---
 build/jam/OptionalPackages | 2 --
 1 file changed, 2 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 3410c0c7ca..35206d208c 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -1257,8 +1257,6 @@ if [ IsOptionalHaikuImagePackageAdded Pe ] {
 		}
 		AddSymlinkToHaikuImage home config be Applications
 			: /boot/apps/Pe/Pe ;
-		AddSymlinkToHaikuImage common bin
-			: /boot/apps/Pe/lpe ;
 	}
 }
 

From 80399d67d31da6137f876a5edabc198c1d30f885 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 20:59:07 +0200
Subject: [PATCH 0171/1170] Don't create empty non-writable common directories

---
 build/jam/HaikuImage | 3 ---
 1 file changed, 3 deletions(-)

diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage
index bf38df590d..4393b38964 100644
--- a/build/jam/HaikuImage
+++ b/build/jam/HaikuImage
@@ -309,10 +309,7 @@ AddFilesToHaikuImage home config add-ons decorators :
 	MacDecorator WinDecorator ClassicBe SATDecorator ;
 
 # create directories that will remain empty
-AddDirectoryToHaikuImage common bin ;
 AddDirectoryToHaikuImage common cache tmp ;
-AddDirectoryToHaikuImage common develop headers ;
-AddDirectoryToHaikuImage common lib ;
 AddDirectoryToHaikuImage common non-packaged ;
 AddDirectoryToHaikuImage common var empty ;
 AddDirectoryToHaikuImage common var log ;

From b0533d66a71485d56a53b8af672974617e3e4684 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 20:59:22 +0200
Subject: [PATCH 0172/1170] Add missing "cache" shine-through directory

---
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index a1b300fc7e..53c4e4f33e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -57,7 +57,7 @@ const char* const kSystemShineThroughDirectories[] = {
 	"packages", NULL
 };
 const char* const kCommonShineThroughDirectories[] = {
-	"non-packaged", "packages", "settings", "var", NULL
+	"cache", "non-packaged", "packages", "settings", "var", NULL
 };
 const char* const* kHomeShineThroughDirectories
 	= kCommonShineThroughDirectories;

From 57af7489207c9c9cd504ecdf221b1f59caee170e Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 21:00:22 +0200
Subject: [PATCH 0173/1170] Also mount "common" packagefs on boot

---
 src/system/kernel/fs/vfs_boot.cpp | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

diff --git a/src/system/kernel/fs/vfs_boot.cpp b/src/system/kernel/fs/vfs_boot.cpp
index 6f233c4981..cd1e681327 100644
--- a/src/system/kernel/fs/vfs_boot.cpp
+++ b/src/system/kernel/fs/vfs_boot.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2007-2010, Ingo Weinhold, bonefish@cs.tu-berlin.de.
+ * Copyright 2007-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
  * Copyright 2002-2010, Axel Dörfler, axeld@pinc-software.de.
  * Distributed under the terms of the MIT License.
  *
@@ -520,6 +520,15 @@ vfs_mount_boot_file_system(kernel_args* args)
 			panic("Failed to mount system packagefs: %s",
 				strerror(systemPackageMount));
 		}
+
+		dev_t commonPackageMount = _kern_mount("/boot/common",
+			NULL, kPackageFSName, 0,
+			"packages /boot/common/packages; type common",
+			0 /* unused argument length */);
+		if (commonPackageMount < 0) {
+			dprintf("Failed to mount common packagefs: %s",
+				strerror(commonPackageMount));
+		}
 	}
 
 	// Do post-boot-volume module initialization. The module code wants to know

From 00043b5320954b88725e2379e7e590add246a304 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 21:07:03 +0200
Subject: [PATCH 0174/1170] Use InstallOptionalHaikuImagePackage for gcc too

---
 build/jam/OptionalPackages | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 35206d208c..fcf997d43e 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -518,8 +518,9 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 		&& $(TARGET_ARCH) = x86 {
 	# gcc and binutils
 	if $(HAIKU_GCC_VERSION[1]) = 2 {
-		InstallCommonPackage gcc-2.95.3_110304-1.hpkg
-			: $(hpkgBaseURL)/gcc-2.95.3_110304-1.hpkg ;
+		InstallOptionalHaikuImagePackage gcc-2.95.3_110304-1.hpkg
+			: $(hpkgBaseURL)/gcc-2.95.3_110304-1.hpkg
+			: common packages ;
 
 		# TODO: remove this when we have a mechanism to switch gcc via PATH
 		AddSymlinkToHaikuImage common settings develop tools

From dfa6888fb2b5ed76fbb533486b2d3828809523a2 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 21:07:22 +0200
Subject: [PATCH 0175/1170] Remove InstallCommonPackage rule

---
 build/jam/ImageRules | 9 ---------
 1 file changed, 9 deletions(-)

diff --git a/build/jam/ImageRules b/build/jam/ImageRules
index 4869ce89b5..48fb107f73 100644
--- a/build/jam/ImageRules
+++ b/build/jam/ImageRules
@@ -886,15 +886,6 @@ rule InstallSourceArchive file : url
 	}
 }
 
-rule InstallCommonPackage package : url
-{
-	# download archive file
-	local archiveFile = [ DownloadFile $(package) : $(url) ] ;
-
-	# copy onto image
-	ExtractArchiveToHaikuImage common packages : $(archiveFile) ;
-}
-
 rule InstallOptionalHaikuImagePackage package : url : dirTokens : isCDPackage
 {
 	# download archive file

From fd0e9e33d0ff6487625877af16dfd6a076762fc7 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 22:39:03 +0200
Subject: [PATCH 0176/1170] Fix bison hpkg package name

---
 build/jam/OptionalPackages | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index fcf997d43e..60eac94043 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -556,7 +556,7 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 			: $(baseURL)/make-3.82-r1a3-x86-gcc4-2011-05-23.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			bison-2.4.3-r1a3-x86-gcc2-2011-05-17.zip
+			bison-2.4.3-1-x86_gcc2.hpkg
 			: $(hpkgBaseURL)/bison-2.4.3-1-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage

From 4cf5f9293fa9bd941c1cf1072042b90d11e4f5d3 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 30 Jun 2011 21:33:43 +0200
Subject: [PATCH 0177/1170] Cleanup

---
 headers/os/package/hpkg/PackageWriter.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/headers/os/package/hpkg/PackageWriter.h b/headers/os/package/hpkg/PackageWriter.h
index 7cc6095f05..f64087bec0 100644
--- a/headers/os/package/hpkg/PackageWriter.h
+++ b/headers/os/package/hpkg/PackageWriter.h
@@ -42,7 +42,6 @@ public:
 
 
 class BPackageWriter {
-public:
 public:
 								BPackageWriter(
 									BPackageWriterListener* listener);

From 5b486787aac2318368f6cd3eb624eebb28e9ed94 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 1 Jul 2011 01:36:46 +0200
Subject: [PATCH 0178/1170] Improve FileDescriptorCloser

* Add SetTo()/Unset() methods and no-argument constructor.
* Detach() returns the FD now.
---
 headers/private/shared/AutoDeleter.h | 26 +++++++++++++++++++++++---
 1 file changed, 23 insertions(+), 3 deletions(-)

diff --git a/headers/private/shared/AutoDeleter.h b/headers/private/shared/AutoDeleter.h
index 339ba43a62..aa2f041431 100644
--- a/headers/private/shared/AutoDeleter.h
+++ b/headers/private/shared/AutoDeleter.h
@@ -224,6 +224,12 @@ struct MethodDeleter
 // FileDescriptorCloser
 
 struct FileDescriptorCloser {
+	inline FileDescriptorCloser()
+		:
+		fDescriptor(-1)
+	{
+	}
+
 	inline FileDescriptorCloser(int descriptor)
 		:
 		fDescriptor(descriptor)
@@ -232,13 +238,27 @@ struct FileDescriptorCloser {
 
 	inline ~FileDescriptorCloser()
 	{
-		if (fDescriptor >= 0)
-			close(fDescriptor);
+		SetTo(-1);
 	}
 
-	inline void Detach()
+	inline void SetTo(int descriptor)
 	{
+		if (fDescriptor >= 0)
+			close(fDescriptor);
+
+		fDescriptor = descriptor;
+	}
+
+	inline void Unset()
+	{
+		SetTo(-1);
+	}
+
+	inline int Detach()
+	{
+		int descriptor = fDescriptor;
 		fDescriptor = -1;
+		return descriptor;
 	}
 
 private:

From bfbb410d1a0c26a5c39fbaeb10bfbd69ccf0cb1a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 1 Jul 2011 01:37:48 +0200
Subject: [PATCH 0179/1170] BPackageInfo::ReadFromConfigFile() BFile& version

---
 headers/os/package/PackageInfo.h |  4 ++++
 src/kits/package/PackageInfo.cpp | 13 +++++++++++--
 2 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h
index 124a9fb3f1..6109a2efa5 100644
--- a/headers/os/package/PackageInfo.h
+++ b/headers/os/package/PackageInfo.h
@@ -18,6 +18,7 @@
 
 
 class BEntry;
+class BFile;
 
 
 namespace BPackageKit {
@@ -44,6 +45,9 @@ public:
 			status_t			ReadFromConfigFile(
 									const BEntry& packageInfoEntry,
 									ParseErrorListener* listener = NULL);
+			status_t			ReadFromConfigFile(
+									BFile& packageInfoFile,
+									ParseErrorListener* listener = NULL);
 			status_t			ReadFromConfigString(
 									const BString& packageInfoString,
 									ParseErrorListener* listener = NULL);
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index dd7dad04f1..ee3376e7b8 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -849,8 +849,17 @@ BPackageInfo::ReadFromConfigFile(const BEntry& packageInfoEntry,
 	if ((result = file.InitCheck()) != B_OK)
 		return result;
 
+	return ReadFromConfigFile(file, listener);
+}
+
+
+status_t
+BPackageInfo::ReadFromConfigFile(BFile& packageInfoFile,
+	ParseErrorListener* listener)
+{
 	off_t size;
-	if ((result = file.GetSize(&size)) != B_OK)
+	status_t result = packageInfoFile.GetSize(&size);
+	if (result != B_OK)
 		return result;
 
 	BString packageInfoString;
@@ -858,7 +867,7 @@ BPackageInfo::ReadFromConfigFile(const BEntry& packageInfoEntry,
 	if (buffer == NULL)
 		return B_NO_MEMORY;
 
-	if ((result = file.Read(buffer, size)) < size) {
+	if ((result = packageInfoFile.Read(buffer, size)) < size) {
 		packageInfoString.UnlockBuffer(0);
 		return result >= 0 ? B_IO_ERROR : result;
 	}

From 4512e8d5669716c2d0e41f6f117cb86635482ebc Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 1 Jul 2011 01:41:28 +0200
Subject: [PATCH 0180/1170] Add optional FD parameter to AddEntry()

If a FD is specified, instead of using the file with the given the FD is
used. Allows for adding entries without first copying them into the
directory structure.
---
 headers/os/package/hpkg/PackageWriter.h       |   2 +-
 .../private/package/hpkg/PackageWriterImpl.h  |   6 +-
 src/kits/package/hpkg/PackageWriter.cpp       |   4 +-
 src/kits/package/hpkg/PackageWriterImpl.cpp   | 108 ++++++++++++++----
 4 files changed, 89 insertions(+), 31 deletions(-)

diff --git a/headers/os/package/hpkg/PackageWriter.h b/headers/os/package/hpkg/PackageWriter.h
index f64087bec0..7ab04a5d5e 100644
--- a/headers/os/package/hpkg/PackageWriter.h
+++ b/headers/os/package/hpkg/PackageWriter.h
@@ -48,7 +48,7 @@ public:
 								~BPackageWriter();
 
 			status_t			Init(const char* fileName);
-			status_t			AddEntry(const char* fileName);
+			status_t			AddEntry(const char* fileName, int fd = -1);
 			status_t			Finish();
 
 private:
diff --git a/headers/private/package/hpkg/PackageWriterImpl.h b/headers/private/package/hpkg/PackageWriterImpl.h
index ec28e1d77f..e70514457d 100644
--- a/headers/private/package/hpkg/PackageWriterImpl.h
+++ b/headers/private/package/hpkg/PackageWriterImpl.h
@@ -38,7 +38,7 @@ public:
 								~PackageWriterImpl();
 
 			status_t			Init(const char* fileName);
-			status_t			AddEntry(const char* fileName);
+			status_t			AddEntry(const char* fileName, int fd = -1);
 			status_t			Finish();
 
 private:
@@ -52,9 +52,9 @@ private:
 			status_t			_Init(const char* fileName);
 			status_t			_Finish();
 
-			status_t			_RegisterEntry(const char* fileName);
+			status_t			_RegisterEntry(const char* fileName, int fd);
 			Entry*				_RegisterEntry(Entry* parent,
-									const char* name, size_t nameLength,
+									const char* name, size_t nameLength, int fd,
 									bool isImplicit);
 
 			status_t			_CheckLicenses();
diff --git a/src/kits/package/hpkg/PackageWriter.cpp b/src/kits/package/hpkg/PackageWriter.cpp
index 52428c608e..1966b5a84f 100644
--- a/src/kits/package/hpkg/PackageWriter.cpp
+++ b/src/kits/package/hpkg/PackageWriter.cpp
@@ -40,12 +40,12 @@ BPackageWriter::Init(const char* fileName)
 
 
 status_t
-BPackageWriter::AddEntry(const char* fileName)
+BPackageWriter::AddEntry(const char* fileName, int fd)
 {
 	if (fImpl == NULL)
 		return B_NO_INIT;
 
-	return fImpl->AddEntry(fileName);
+	return fImpl->AddEntry(fileName, fd);
 }
 
 
diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index dd12e7f90e..cd9791b354 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -91,10 +91,11 @@ struct PackageWriterImpl::Attribute
 
 
 struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl {
-	Entry(char* name, size_t nameLength, bool isImplicit)
+	Entry(char* name, size_t nameLength, int fd, bool isImplicit)
 		:
 		fName(name),
 		fNameLength(nameLength),
+		fFD(fd),
 		fIsImplicit(isImplicit)
 	{
 	}
@@ -105,7 +106,8 @@ struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl {
 		free(fName);
 	}
 
-	static Entry* Create(const char* name, size_t nameLength, bool isImplicit)
+	static Entry* Create(const char* name, size_t nameLength, int fd,
+		bool isImplicit)
 	{
 		char* clonedName = (char*)malloc(nameLength + 1);
 		if (clonedName == NULL)
@@ -113,7 +115,7 @@ struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl {
 		memcpy(clonedName, name, nameLength);
 		clonedName[nameLength] = '\0';
 
-		Entry* entry = new(std::nothrow) Entry(clonedName, nameLength,
+		Entry* entry = new(std::nothrow) Entry(clonedName, nameLength, fd,
 			isImplicit);
 		if (entry == NULL) {
 			free(clonedName);
@@ -128,6 +130,16 @@ struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl {
 		return fName;
 	}
 
+	int FD() const
+	{
+		return fFD;
+	}
+
+	void SetFD(int fd)
+	{
+		fFD = fd;
+	}
+
 	bool IsImplicit() const
 	{
 		return fIsImplicit;
@@ -174,6 +186,7 @@ struct PackageWriterImpl::Entry : DoublyLinkedListLinkImpl {
 private:
 	char*		fName;
 	size_t		fNameLength;
+	int			fFD;
 	bool		fIsImplicit;
 	EntryList	fChildren;
 };
@@ -253,7 +266,7 @@ PackageWriterImpl::Init(const char* fileName)
 
 
 status_t
-PackageWriterImpl::AddEntry(const char* fileName)
+PackageWriterImpl::AddEntry(const char* fileName, int fd)
 {
 	try {
 		// if it's ".PackageInfo", parse it
@@ -267,15 +280,48 @@ PackageWriterImpl::AddEntry(const char* fileName)
 				}
 				BPackageWriterListener* listener;
 			} errorListener(fListener);
-			BEntry packageInfoEntry(fileName);
-			status_t result = fPackageInfo.ReadFromConfigFile(packageInfoEntry,
-				&errorListener);
-			if (result != B_OK || (result = fPackageInfo.InitCheck()) != B_OK)
-				return result;
+
+			if (fd >= 0) {
+				// a file descriptor is given -- read the config from there
+				// stat the file to get the file size
+				struct stat st;
+				if (fstat(fd, &st) != 0)
+					return errno;
+
+				BString packageInfoString;
+				char* buffer = packageInfoString.LockBuffer(st.st_size);
+				if (buffer == NULL)
+					return B_NO_MEMORY;
+
+				ssize_t result = read_pos(fd, 0, buffer, st.st_size);
+				if (result < 0) {
+					packageInfoString.UnlockBuffer(0);
+					return errno;
+				}
+
+				buffer[st.st_size] = '\0';
+				packageInfoString.UnlockBuffer(st.st_size);
+
+				result = fPackageInfo.ReadFromConfigString(packageInfoString,
+					&errorListener);
+				if (result != B_OK)
+					return result;
+			} else {
+printf("  reading by name...\n");
+				// use the file name
+				BEntry packageInfoEntry(fileName);
+				status_t result = fPackageInfo.ReadFromConfigFile(
+					packageInfoEntry, &errorListener);
+				if (result != B_OK
+					|| (result = fPackageInfo.InitCheck()) != B_OK) {
+					return result;
+				}
+			}
+
 			RegisterPackageInfo(PackageAttributes(), fPackageInfo);
 		}
 
-		return _RegisterEntry(fileName);
+		return _RegisterEntry(fileName, fd);
 	} catch (status_t error) {
 		return error;
 	} catch (std::bad_alloc) {
@@ -325,7 +371,7 @@ PackageWriterImpl::_Init(const char* fileName)
 		throw std::bad_alloc();
 
 	// create entry list
-	fRootEntry = new Entry(NULL, 0, true);
+	fRootEntry = new Entry(NULL, 0, -1, true);
 
 	fRootAttribute = new Attribute();
 
@@ -425,7 +471,7 @@ PackageWriterImpl::_Finish()
 
 
 status_t
-PackageWriterImpl::_RegisterEntry(const char* fileName)
+PackageWriterImpl::_RegisterEntry(const char* fileName, int fd)
 {
 	if (*fileName == '\0') {
 		fListener->PrintError("Invalid empty file name\n");
@@ -438,7 +484,8 @@ PackageWriterImpl::_RegisterEntry(const char* fileName)
 		const char* nextSlash = strchr(fileName, '/');
 		// no slash, just add the file name
 		if (nextSlash == NULL) {
-			entry = _RegisterEntry(entry, fileName, strlen(fileName), false);
+			entry = _RegisterEntry(entry, fileName, strlen(fileName), fd,
+				false);
 			break;
 		}
 
@@ -447,13 +494,15 @@ PackageWriterImpl::_RegisterEntry(const char* fileName)
 		while (*nextComponent == '/')
 			nextComponent++;
 
+		bool lastComponent = *nextComponent != '\0';
+
 		if (nextSlash == fileName) {
 			// the FS root
-			entry = _RegisterEntry(entry, fileName, 1,
-				*nextComponent != '\0');
+			entry = _RegisterEntry(entry, fileName, 1, lastComponent ? fd : -1,
+				lastComponent);
 		} else {
 			entry = _RegisterEntry(entry, fileName, nextSlash - fileName,
-				*nextComponent != '\0');
+				lastComponent ? fd : -1, lastComponent);
 		}
 
 		fileName = nextComponent;
@@ -465,7 +514,7 @@ PackageWriterImpl::_RegisterEntry(const char* fileName)
 
 PackageWriterImpl::Entry*
 PackageWriterImpl::_RegisterEntry(Entry* parent, const char* name,
-	size_t nameLength, bool isImplicit)
+	size_t nameLength, int fd, bool isImplicit)
 {
 	// check the component name -- don't allow "." or ".."
 	if (name[0] == '.'
@@ -483,10 +532,11 @@ PackageWriterImpl::_RegisterEntry(Entry* parent, const char* name,
 		if (entry->IsImplicit() && !isImplicit) {
 			entry->DeleteChildren();
 			entry->SetImplicit(false);
+			entry->SetFD(fd);
 		}
 	} else {
 		// nope -- create it
-		entry = Entry::Create(name, nameLength, isImplicit);
+		entry = Entry::Create(name, nameLength, fd, isImplicit);
 		parent->AddChild(entry);
 	}
 
@@ -626,14 +676,22 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 	}
 
 	// open the node
-	int fd = openat(dirFD, fileName,
-		O_RDONLY | (isImplicitEntry ? 0 : O_NOTRAVERSE));
-	if (fd < 0) {
-		fListener->PrintError("Failed to open entry \"%s\": %s\n", fileName,
-			strerror(errno));
-		throw status_t(errno);
+	int fd;
+	FileDescriptorCloser fdCloser;
+
+	if (entry != NULL && entry->FD() >= 0) {
+		// a file descriptor is already given -- use that
+		fd = entry->FD();
+	} else {
+		fd = openat(dirFD, fileName,
+			O_RDONLY | (isImplicitEntry ? 0 : O_NOTRAVERSE));
+		if (fd < 0) {
+			fListener->PrintError("Failed to open entry \"%s\": %s\n", fileName,
+				strerror(errno));
+			throw status_t(errno);
+		}
+		fdCloser.SetTo(fd);
 	}
-	FileDescriptorCloser fdCloser(fd);
 
 	// stat the node
 	struct stat st;

From 6707be54030e82f4e1a3ad38cdce7d1522f61cb1 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 1 Jul 2011 01:42:23 +0200
Subject: [PATCH 0181/1170] Add create -i option for specifying a package info

---
 src/bin/package/command_create.cpp | 30 +++++++++++++++++++++++++++++-
 src/bin/package/package.cpp        |  7 +++++--
 2 files changed, 34 insertions(+), 3 deletions(-)

diff --git a/src/bin/package/command_create.cpp b/src/bin/package/command_create.cpp
index 66fbb6c28b..5ca624de2c 100644
--- a/src/bin/package/command_create.cpp
+++ b/src/bin/package/command_create.cpp
@@ -100,6 +100,7 @@ int
 command_create(int argc, const char* const* argv)
 {
 	const char* changeToDirectory = NULL;
+	const char* packageInfoFileName = NULL;
 	bool quiet = false;
 	bool verbose = false;
 
@@ -112,7 +113,7 @@ command_create(int argc, const char* const* argv)
 		};
 
 		opterr = 0; // don't print errors
-		int c = getopt_long(argc, (char**)argv, "+C:hqv", sLongOptions, NULL);
+		int c = getopt_long(argc, (char**)argv, "+C:hi:qv", sLongOptions, NULL);
 		if (c == -1)
 			break;
 
@@ -125,6 +126,10 @@ command_create(int argc, const char* const* argv)
 				print_usage_and_exit(false);
 				break;
 
+			case 'i':
+				packageInfoFileName = optarg;
+				break;
+
 			case 'q':
 				quiet = true;
 				break;
@@ -152,6 +157,16 @@ command_create(int argc, const char* const* argv)
 	if (result != B_OK)
 		return 1;
 
+	// If a package info file has been specified explicitly, open it.
+	int packageInfoFD = -1;
+	if (packageInfoFileName != NULL) {
+		packageInfoFD = open(packageInfoFileName, O_RDONLY);
+		if (packageInfoFD < 0) {
+			fprintf(stderr, "Error: Failed to open package info file \"%s\": "
+				"%s\n", packageInfoFileName, strerror(errno));
+		}
+	}
+
 	// change directory, if requested
 	if (changeToDirectory != NULL) {
 		if (chdir(changeToDirectory) != 0) {
@@ -168,16 +183,29 @@ command_create(int argc, const char* const* argv)
 			strerror(errno));
 		return 1;
 	}
+
 	while (dirent* entry = readdir(dir)) {
+		// skip "." and ".."
 		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
 			continue;
 
+		// also skip the .PackageInfo -- we'll add it later
+		if (strcmp(entry->d_name, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0)
+			continue;
+
 		result = packageWriter.AddEntry(entry->d_name);
 		if (result != B_OK)
 			return 1;
 	}
+
 	closedir(dir);
 
+	// add the .PackageInfo
+	result = packageWriter.AddEntry(B_HPKG_PACKAGE_INFO_FILE_NAME,
+		packageInfoFD);
+	if (result != B_OK)
+		return 1;
+
 	// write the package
 	result = packageWriter.Finish();
 	if (result != B_OK)
diff --git a/src/bin/package/package.cpp b/src/bin/package/package.cpp
index 7d192caff1..2d25611762 100644
--- a/src/bin/package/package.cpp
+++ b/src/bin/package/package.cpp
@@ -27,8 +27,11 @@ static const char* kUsage =
 	"    Creates package file  from contents of current directory.\n"
 	"\n"
 	"    -C    - Change to directory  before starting.\n"
-	"    -q         - be quiet (don't show any output except for errors).\n"
-	"    -v         - be verbose (show more info about created package).\n"
+	"    -i   - Use the package info file . It will be added as\n"
+	"                 \".PackageInfo\", overriding a \".PackageInfo\" file,\n"
+	"                 existing.\n"
+	"    -q         - Be quiet (don't show any output except for errors).\n"
+	"    -v         - Be verbose (show more info about created package).\n"
 	"\n"
 	"  dump [  ] \n"
 	"    Dumps the TOC section of package file . For debugging only.\n"

From 32081667b118ca5603e9036ad18ef8161c34386a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 1 Jul 2011 01:42:47 +0200
Subject: [PATCH 0182/1170] Make use of package create -i option

---
 build/scripts/build_haiku_package | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/build/scripts/build_haiku_package b/build/scripts/build_haiku_package
index 2b326d55d8..0e8228dd88 100755
--- a/build/scripts/build_haiku_package
+++ b/build/scripts/build_haiku_package
@@ -61,6 +61,5 @@ done
 
 
 # create the package
-cp "$packageInfoPath" "$contentsDir/.PackageInfo"
 rm -f "$packagePath"
-$package create -C "$contentsDir" "$packagePath"
+$package create -i "$packageInfoPath" -C "$contentsDir" "$packagePath"

From 55191c9ac9883365c93d4e5cdf3e54a4e46d0366 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 1 Jul 2011 01:51:34 +0200
Subject: [PATCH 0183/1170] Remove debug output

---
 src/bin/package/command_extract.cpp | 2 --
 1 file changed, 2 deletions(-)

diff --git a/src/bin/package/command_extract.cpp b/src/bin/package/command_extract.cpp
index d3269c883f..d70c2396c4 100644
--- a/src/bin/package/command_extract.cpp
+++ b/src/bin/package/command_extract.cpp
@@ -366,7 +366,6 @@ command_extract(int argc, const char* const* argv)
 	StandardErrorOutput errorOutput;
 	BPackageReader packageReader(&errorOutput);
 	status_t error = packageReader.Init(packageFileName);
-printf("Init(): %s\n", strerror(error));
 	if (error != B_OK)
 		return 1;
 
@@ -386,7 +385,6 @@ printf("Init(): %s\n", strerror(error));
 		return 1;
 
 	error = packageReader.ParseContent(&handler);
-printf("ParseContent(): %s\n", strerror(error));
 	if (error != B_OK)
 		return 1;
 

From 4f5d405e3468ab70499b2a31542817136fd9dd9a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 1 Jul 2011 02:21:28 +0200
Subject: [PATCH 0184/1170] Add package extract -i option

Allows to specify an alternate location for the .PackageInfo.
---
 src/bin/package/command_extract.cpp | 111 ++++++++++++++++++++--------
 src/bin/package/package.cpp         |   1 +
 2 files changed, 80 insertions(+), 32 deletions(-)

diff --git a/src/bin/package/command_extract.cpp b/src/bin/package/command_extract.cpp
index d70c2396c4..ca58ed089d 100644
--- a/src/bin/package/command_extract.cpp
+++ b/src/bin/package/command_extract.cpp
@@ -43,6 +43,8 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		fPackageFileReader(packageFileFD),
 		fDataBuffer(NULL),
 		fDataBufferSize(0),
+		fBaseDirectory(AT_FDCWD),
+		fInfoFileName(NULL),
 		fErrorOccurred(false)
 	{
 	}
@@ -66,6 +68,16 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		return B_OK;
 	}
 
+	void SetBaseDirectory(int fd)
+	{
+		fBaseDirectory = fd;
+	}
+
+	void SetPackageInfoFile(const char* infoFileName)
+	{
+		fInfoFileName = infoFileName;
+	}
+
 	virtual status_t HandleEntry(BPackageEntry* entry)
 	{
 		// create a token
@@ -74,14 +86,14 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 			return B_NO_MEMORY;
 		ObjectDeleter tokenDeleter(token);
 
-		// get parent FD
-		int parentFD = AT_FDCWD;
-		if (entry->Parent() != NULL)
-			parentFD = ((Token*)entry->Parent()->UserToken())->fd;
+		// get parent FD and the entry name
+		int parentFD;
+		const char* entryName;
+		_GetParentFDAndEntryName(entry, parentFD, entryName);
 
 		// check whether something is in the way
 		struct stat st;
-		bool entryExists = fstatat(parentFD, entry->Name(), &st,
+		bool entryExists = fstatat(parentFD, entryName, &st,
 			AT_SYMLINK_NOFOLLOW) == 0;
 		if (entryExists) {
 			if (S_ISREG(entry->Mode()) || S_ISLNK(entry->Mode())) {
@@ -89,13 +101,13 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 				// remove it, otherwise fail.
 				if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
 					fprintf(stderr, "Error: Can't create entry \"%s\", since "
-						"something is in the way\n", entry->Name());
+						"something is in the way\n", entryName);
 					return B_FILE_EXISTS;
 				}
 
-				if (unlinkat(parentFD, entry->Name(), 0) != 0) {
+				if (unlinkat(parentFD, entryName, 0) != 0) {
 					fprintf(stderr, "Error: Failed to unlink entry \"%s\": %s\n",
-						entry->Name(), strerror(errno));
+						entryName, strerror(errno));
 					return errno;
 				}
 
@@ -105,7 +117,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 				// fail.
 				if (!S_ISDIR(st.st_mode)) {
 					fprintf(stderr, "Error: Can't create directory \"%s\", "
-						"since something is in the way\n", entry->Name());
+						"since something is in the way\n", entryName);
 					return B_FILE_EXISTS;
 				}
 			}
@@ -115,14 +127,14 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		int fd = -1;
 		if (S_ISREG(entry->Mode())) {
 			// create the file
-			fd = openat(parentFD, entry->Name(), O_RDWR | O_CREAT | O_EXCL,
+			fd = openat(parentFD, entryName, O_RDWR | O_CREAT | O_EXCL,
 				S_IRUSR | S_IWUSR);
 				// Note: We use read+write user permissions now -- so write
 				// operations (e.g. attributes) won't fail, but set them to the
 				// desired ones in HandleEntryDone().
 			if (fd < 0) {
 				fprintf(stderr, "Error: Failed to create file \"%s\": %s\n",
-					entry->Name(), strerror(errno));
+					entryName, strerror(errno));
 				return errno;
 			}
 
@@ -142,35 +154,35 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 			// create the symlink
 			const char* symlinkPath = entry->SymlinkPath();
 			if (symlinkat(symlinkPath != NULL ? symlinkPath : "", parentFD,
-					entry->Name()) != 0) {
+					entryName) != 0) {
 				fprintf(stderr, "Error: Failed to create symlink \"%s\": %s\n",
-					entry->Name(), strerror(errno));
+					entryName, strerror(errno));
 				return errno;
 			}
 // TODO: Set symlink permissions?
  		} else if (S_ISDIR(entry->Mode())) {
 			// create the directory, if necessary
 			if (!entryExists
-				&& mkdirat(parentFD, entry->Name(), S_IRWXU) != 0) {
+				&& mkdirat(parentFD, entryName, S_IRWXU) != 0) {
 				// Note: We use read+write+exec user permissions now -- so write
 				// operations (e.g. attributes) won't fail, but set them to the
 				// desired ones in HandleEntryDone().
 				fprintf(stderr, "Error: Failed to create directory \"%s\": "
-					"%s\n", entry->Name(), strerror(errno));
+					"%s\n", entryName, strerror(errno));
 				return errno;
 			}
 		} else {
 			fprintf(stderr, "Error: Invalid file type for entry \"%s\"\n",
-				entry->Name());
+				entryName);
 			return B_BAD_DATA;
 		}
 
 		// If not done yet (symlink, dir), open the node -- we need the FD.
 		if (fd < 0) {
-			fd = openat(parentFD, entry->Name(), O_RDONLY | O_NOTRAVERSE);
+			fd = openat(parentFD, entryName, O_RDONLY | O_NOTRAVERSE);
 			if (fd < 0) {
 				fprintf(stderr, "Error: Failed to open entry \"%s\": %s\n",
-					entry->Name(), strerror(errno));
+					entryName, strerror(errno));
 				return errno;
 			}
 		}
@@ -198,10 +210,14 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		int fd = fs_fopen_attr(entryFD, attribute->Name(), attribute->Type(),
 			O_WRONLY | O_CREAT | O_TRUNC);
 		if (fd < 0) {
-				fprintf(stderr, "Error: Failed to create attribute \"%s\" of "
-					"file \"%s\": %s\n", attribute->Name(), entry->Name(),
-					strerror(errno));
-				return errno;
+			int parentFD;
+			const char* entryName;
+			_GetParentFDAndEntryName(entry, parentFD, entryName);
+
+			fprintf(stderr, "Error: Failed to create attribute \"%s\" of "
+				"file \"%s\": %s\n", attribute->Name(), entryName,
+				strerror(errno));
+			return errno;
 		}
 
 		// write data
@@ -223,15 +239,15 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 	{
 		// set the node permissions for non-symlinks
 		if (!S_ISLNK(entry->Mode())) {
-			// get parent FD
-			int parentFD = AT_FDCWD;
-			if (entry->Parent() != NULL)
-				parentFD = ((Token*)entry->Parent()->UserToken())->fd;
+			// get parent FD and entry name
+			int parentFD;
+			const char* entryName;
+			_GetParentFDAndEntryName(entry, parentFD, entryName);
 
-			if (fchmodat(parentFD, entry->Name(), entry->Mode() & ALLPERMS,
+			if (fchmodat(parentFD, entryName, entry->Mode() & ALLPERMS,
 					/*AT_SYMLINK_NOFOLLOW*/0) != 0) {
 				fprintf(stderr, "Warning: Failed to set permissions of file "
-					"\"%s\": %s\n", entry->Name(), strerror(errno));
+					"\"%s\": %s\n", entryName, strerror(errno));
 			}
 		}
 
@@ -272,6 +288,21 @@ private:
 	};
 
 private:
+	void _GetParentFDAndEntryName(BPackageEntry* entry, int& _parentFD,
+		const char*& _entryName)
+	{
+		_entryName = entry->Name();
+
+		if (fInfoFileName != NULL
+			&& strcmp(_entryName, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) {
+			_parentFD = AT_FDCWD;
+			_entryName = fInfoFileName;
+		} else {
+			_parentFD = entry->Parent() != NULL
+				? ((Token*)entry->Parent()->UserToken())->fd : fBaseDirectory;
+		}
+	}
+
 	status_t _ExtractFileData(BDataReader* dataReader, const BPackageData& data,
 		int fd)
 	{
@@ -321,6 +352,8 @@ private:
 	BFDDataReader			fPackageFileReader;
 	void*					fDataBuffer;
 	size_t					fDataBufferSize;
+	int						fBaseDirectory;
+	const char*				fInfoFileName;
 	bool					fErrorOccurred;
 };
 
@@ -329,6 +362,7 @@ int
 command_extract(int argc, const char* const* argv)
 {
 	const char* changeToDirectory = NULL;
+	const char* packageInfoFileName = NULL;
 
 	while (true) {
 		static struct option sLongOptions[] = {
@@ -337,7 +371,7 @@ command_extract(int argc, const char* const* argv)
 		};
 
 		opterr = 0; // don't print errors
-		int c = getopt_long(argc, (char**)argv, "+C:h", sLongOptions, NULL);
+		int c = getopt_long(argc, (char**)argv, "+C:hi:", sLongOptions, NULL);
 		if (c == -1)
 			break;
 
@@ -350,6 +384,10 @@ command_extract(int argc, const char* const* argv)
 				print_usage_and_exit(false);
 				break;
 
+			case 'i':
+				packageInfoFileName = optarg;
+				break;
+
 			default:
 				print_usage_and_exit(true);
 				break;
@@ -369,17 +407,26 @@ command_extract(int argc, const char* const* argv)
 	if (error != B_OK)
 		return 1;
 
-	// change directory, if requested
+	PackageContentExtractHandler handler(packageReader.PackageFileFD());
+
+	// get the target directory, if requested
 	if (changeToDirectory != NULL) {
-		if (chdir(changeToDirectory) != 0) {
+		int currentDirFD = open(changeToDirectory, O_RDONLY);
+		if (currentDirFD < 0) {
 			fprintf(stderr, "Error: Failed to change the current working "
 				"directory to \"%s\": %s\n", changeToDirectory,
 				strerror(errno));
+			return 1;
 		}
+
+		handler.SetBaseDirectory(currentDirFD);
 	}
 
+	// If a package info file name is given, set it.
+	if (packageInfoFileName != NULL)
+		handler.SetPackageInfoFile(packageInfoFileName);
+
 	// extract
-	PackageContentExtractHandler handler(packageReader.PackageFileFD());
 	error = handler.Init();
 	if (error != B_OK)
 		return 1;
diff --git a/src/bin/package/package.cpp b/src/bin/package/package.cpp
index 2d25611762..4917703428 100644
--- a/src/bin/package/package.cpp
+++ b/src/bin/package/package.cpp
@@ -42,6 +42,7 @@ static const char* kUsage =
 	"    -C    - Change to directory  before extracting the "
 		"contents\n"
 	"                  of the archive.\n"
+	"    -i   - Extract the .PackageInfo file to  instead.\n"
 	"\n"
 	"  list [  ] \n"
 	"    Lists the contents of package file .\n"

From 5845e7916997e8c231a89daf5a5bacdc9f4211d9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 1 Jul 2011 02:39:57 +0200
Subject: [PATCH 0185/1170] Missing include

---
 src/bin/package/command_create.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/bin/package/command_create.cpp b/src/bin/package/command_create.cpp
index 5ca624de2c..7e7af90676 100644
--- a/src/bin/package/command_create.cpp
+++ b/src/bin/package/command_create.cpp
@@ -7,6 +7,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 

From 4796acbc8c8fa3a5325a27722746b999009988d1 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 1 Jul 2011 04:26:23 +0200
Subject: [PATCH 0186/1170] Support for extracting only specified entries

---
 src/bin/package/command_extract.cpp | 326 ++++++++++++++++++++++++++--
 src/bin/package/package.cpp         |   6 +-
 src/tools/package/Jamfile           |   2 +-
 3 files changed, 318 insertions(+), 16 deletions(-)

diff --git a/src/bin/package/command_extract.cpp b/src/bin/package/command_extract.cpp
index ca58ed089d..dbb24dc7eb 100644
--- a/src/bin/package/command_extract.cpp
+++ b/src/bin/package/command_extract.cpp
@@ -18,8 +18,12 @@
 #include 
 
 #include 
+#include 
 
 #include 
+#include 
+
+#include 
 
 #include 
 #include 
@@ -36,6 +40,142 @@ using namespace BPackageKit::BHPKG;
 using BPackageKit::BBlockBufferCacheNoLock;
 
 
+struct Entry {
+	Entry(Entry* parent, char* name, bool implicit)
+		:
+		fParent(parent),
+		fName(name),
+		fImplicit(implicit),
+		fSeen(false)
+	{
+	}
+
+	~Entry()
+	{
+		_DeleteChildren();
+
+		free(fName);
+	}
+
+	status_t Init()
+	{
+		return fChildren.Init();
+	}
+
+	static status_t Create(Entry* parent, const char* name, bool implicit,
+		Entry*& _entry)
+	{
+		char* clonedName = strdup(name);
+		if (clonedName == NULL)
+			return B_NO_MEMORY;
+
+		Entry* entry = new(std::nothrow) Entry(parent, clonedName, implicit);
+		if (entry == NULL) {
+			free(clonedName);
+			return B_NO_MEMORY;
+		}
+
+		status_t error = entry->Init();
+		if (error != B_OK) {
+			delete entry;
+			return error;
+		}
+
+		if (parent != NULL)
+			parent->fChildren.Insert(entry);
+
+		_entry = entry;
+		return B_OK;
+	}
+
+	Entry* Parent() const
+	{
+		return fParent;
+	}
+
+	const char* Name() const
+	{
+		return fName;
+	}
+
+	bool IsImplicit() const
+	{
+		return fImplicit;
+	}
+
+	void SetExplicit()
+	{
+		// remove all children and set this entry non-implicit
+		_DeleteChildren();
+		fImplicit = false;
+	}
+
+	void SetSeen()
+	{
+		fSeen = true;
+	}
+
+	bool Seen() const
+	{
+		return fSeen;
+	}
+
+	Entry* FindChild(const char* name) const
+	{
+		return fChildren.Lookup(name);
+	}
+
+private:
+	struct ChildHashDefinition {
+		typedef const char*		KeyType;
+		typedef	Entry			ValueType;
+
+		size_t HashKey(const char* key) const
+		{
+			return string_hash(key);
+		}
+
+		size_t Hash(const Entry* value) const
+		{
+			return HashKey(value->Name());
+		}
+
+		bool Compare(const char* key, const Entry* value) const
+		{
+			return strcmp(value->Name(), key) == 0;
+		}
+
+		Entry*& GetLink(Entry* value) const
+		{
+			return value->fHashTableNext;
+		}
+	};
+
+	typedef BOpenHashTable ChildTable;
+
+private:
+	void _DeleteChildren()
+	{
+		Entry* child = fChildren.Clear(true);
+		while (child != NULL) {
+			Entry* next = child->fHashTableNext;
+			delete child;
+			child = next;
+		}
+	}
+
+public:
+	Entry*		fHashTableNext;
+
+private:
+	Entry*		fParent;
+	char*		fName;
+	bool		fImplicit;
+	bool		fSeen;
+	ChildTable	fChildren;
+};
+
+
 struct PackageContentExtractHandler : BPackageContentHandler {
 	PackageContentExtractHandler(int packageFileFD)
 		:
@@ -43,6 +183,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		fPackageFileReader(packageFileFD),
 		fDataBuffer(NULL),
 		fDataBufferSize(0),
+		fRootFilterEntry(NULL, NULL, true),
 		fBaseDirectory(AT_FDCWD),
 		fInfoFileName(NULL),
 		fErrorOccurred(false)
@@ -60,6 +201,10 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		if (error != B_OK)
 			return error;
 
+		error = fRootFilterEntry.Init();
+		if (error != B_OK)
+			return error;
+
 		fDataBufferSize = 64 * 1024;
 		fDataBuffer = malloc(fDataBufferSize);
 		if (fDataBuffer == NULL)
@@ -78,6 +223,63 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		fInfoFileName = infoFileName;
 	}
 
+	void SetExtractAll()
+	{
+		fRootFilterEntry.SetExplicit();
+	}
+
+	status_t AddFilterEntry(const char* fileName)
+	{
+		// add all components of the path
+		Entry* entry = &fRootFilterEntry;
+		while (*fileName != 0) {
+			const char* nextSlash = strchr(fileName, '/');
+			// no slash, just add the file name
+			if (nextSlash == NULL) {
+				return _AddFilterEntry(entry, fileName, strlen(fileName),
+					false, entry);
+			}
+
+			// find the start of the next component, skipping slashes
+			const char* nextComponent = nextSlash + 1;
+			while (*nextComponent == '/')
+				nextComponent++;
+
+			status_t error = _AddFilterEntry(entry, fileName,
+				nextSlash - fileName, *nextComponent != '\0', entry);
+			if (error != B_OK)
+				return error;
+
+			fileName = nextComponent;
+		}
+
+		return B_OK;
+	}
+
+	Entry* FindFilterEntry(const char* fileName)
+	{
+		// add all components of the path
+		Entry* entry = &fRootFilterEntry;
+		while (entry != NULL && *fileName != 0) {
+			const char* nextSlash = strchr(fileName, '/');
+			// no slash, just add the file name
+			if (nextSlash == NULL)
+				return entry->FindChild(fileName);
+
+			// find the start of the next component, skipping slashes
+			const char* nextComponent = nextSlash + 1;
+			while (*nextComponent == '/')
+				nextComponent++;
+
+			BString componentName(fileName, nextSlash - fileName);
+			entry = entry->FindChild(componentName);
+
+			fileName = nextComponent;
+		}
+
+		return entry;
+	}
+
 	virtual status_t HandleEntry(BPackageEntry* entry)
 	{
 		// create a token
@@ -86,6 +288,41 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 			return B_NO_MEMORY;
 		ObjectDeleter tokenDeleter(token);
 
+		// check whether this entry shall be ignored or is implicit
+		Entry* parentFilterEntry;
+		bool implicit;
+		if (entry->Parent() != NULL) {
+			Token* parentToken = (Token*)entry->Parent()->UserToken();
+			if (parentToken == NULL) {
+				// parent is ignored, so ignore this entry, too
+				return B_OK;
+			}
+
+			parentFilterEntry = parentToken->filterEntry;
+			implicit = parentToken->implicit;
+		} else {
+			parentFilterEntry = &fRootFilterEntry;
+			implicit = fRootFilterEntry.IsImplicit();
+		}
+
+		Entry* filterEntry = parentFilterEntry != NULL
+			? parentFilterEntry->FindChild(entry->Name()) : NULL;
+
+		if (implicit && filterEntry == NULL) {
+			// parent is implicit and the filter doesn't include this entry
+			// -- ignore it
+			return B_OK;
+		}
+
+		// If the entry is in the filter, get its implicit flag.
+		if (filterEntry != NULL) {
+			implicit = filterEntry->IsImplicit();
+			filterEntry->SetSeen();
+		}
+
+		token->filterEntry = filterEntry;
+		token->implicit = implicit;
+
 		// get parent FD and the entry name
 		int parentFD;
 		const char* entryName;
@@ -126,6 +363,12 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		// create the entry
 		int fd = -1;
 		if (S_ISREG(entry->Mode())) {
+			if (implicit) {
+				fprintf(stderr, "Error: File \"%s\" was specified as a "
+					"path directory component.\n", entryName);
+				return B_BAD_VALUE;
+			}
+
 			// create the file
 			fd = openat(parentFD, entryName, O_RDWR | O_CREAT | O_EXCL,
 				S_IRUSR | S_IWUSR);
@@ -151,6 +394,12 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 			if (error != B_OK)
 				return error;
 		} else if (S_ISLNK(entry->Mode())) {
+			if (implicit) {
+				fprintf(stderr, "Error: Symlink \"%s\" was specified as a "
+					"path directory component.\n", entryName);
+				return B_BAD_VALUE;
+			}
+
 			// create the symlink
 			const char* symlinkPath = entry->SymlinkPath();
 			if (symlinkat(symlinkPath != NULL ? symlinkPath : "", parentFD,
@@ -178,7 +427,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		}
 
 		// If not done yet (symlink, dir), open the node -- we need the FD.
-		if (fd < 0) {
+		if (fd < 0 && (!implicit || S_ISDIR(entry->Mode()))) {
 			fd = openat(parentFD, entryName, O_RDONLY | O_NOTRAVERSE);
 			if (fd < 0) {
 				fprintf(stderr, "Error: Failed to open entry \"%s\": %s\n",
@@ -189,7 +438,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		token->fd = fd;
 
 		// set the file times
-		if (!entryExists) {
+		if (!entryExists && !implicit) {
 			timespec times[2] = {entry->AccessTime(), entry->ModifiedTime()};
 			futimens(fd, times);
 
@@ -204,7 +453,12 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
 		BPackageEntryAttribute* attribute)
 	{
-		int entryFD = ((Token*)entry->UserToken())->fd;
+		// don't write attributes of ignored or implicit entries
+		Token* token = (Token*)entry->UserToken();
+		if (token == NULL || token->implicit)
+			return B_OK;
+
+		int entryFD = token->fd;
 
 		// create the attribute
 		int fd = fs_fopen_attr(entryFD, attribute->Name(), attribute->Type(),
@@ -237,8 +491,10 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 
 	virtual status_t HandleEntryDone(BPackageEntry* entry)
 	{
+		Token* token = (Token*)entry->UserToken();
+
 		// set the node permissions for non-symlinks
-		if (!S_ISLNK(entry->Mode())) {
+		if (token != NULL && !S_ISLNK(entry->Mode())) {
 			// get parent FD and entry name
 			int parentFD;
 			const char* entryName;
@@ -251,7 +507,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 			}
 		}
 
-		if (Token* token = (Token*)entry->UserToken()) {
+		if (token != NULL) {
 			delete token;
 			entry->SetUserToken(NULL);
 		}
@@ -272,11 +528,15 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 
 private:
 	struct Token {
-		int	fd;
+		Entry*	filterEntry;
+		int		fd;
+		bool	implicit;
 
 		Token()
 			:
-			fd(-1)
+			filterEntry(NULL),
+			fd(-1),
+			implicit(true)
 		{
 		}
 
@@ -288,6 +548,16 @@ private:
 	};
 
 private:
+	status_t _AddFilterEntry(Entry* parentEntry, const char* _name,
+		size_t nameLength, bool implicit, Entry*& _entry)
+	{
+		BString name(_name, nameLength);
+		if (name.IsEmpty())
+			return B_NO_MEMORY;
+
+		return Entry::Create(parentEntry, name.String(), implicit, _entry);
+	}
+
 	void _GetParentFDAndEntryName(BPackageEntry* entry, int& _parentFD,
 		const char*& _entryName)
 	{
@@ -352,6 +622,7 @@ private:
 	BFDDataReader			fPackageFileReader;
 	void*					fDataBuffer;
 	size_t					fDataBufferSize;
+	Entry					fRootFilterEntry;
 	int						fBaseDirectory;
 	const char*				fInfoFileName;
 	bool					fErrorOccurred;
@@ -394,8 +665,8 @@ command_extract(int argc, const char* const* argv)
 		}
 	}
 
-	// One argument should remain -- the package file name.
-	if (optind + 1 != argc)
+	// At least one argument should remain -- the package file name.
+	if (optind + 1 > argc)
 		print_usage_and_exit(true);
 
 	const char* packageFileName = argv[optind++];
@@ -408,6 +679,27 @@ command_extract(int argc, const char* const* argv)
 		return 1;
 
 	PackageContentExtractHandler handler(packageReader.PackageFileFD());
+	error = handler.Init();
+	if (error != B_OK)
+		return 1;
+
+	// If entries to extract have been specified explicitly, add those to the
+	// filtered ones.
+	int explicitEntriesIndex = optind;
+	if (optind < argc) {
+		while (optind < argc) {
+			const char* entryName = argv[optind++];
+			if (entryName[0] == '\0' || entryName[0] == '/') {
+				fprintf(stderr, "Error: Invalid entry name: \"%s\".",
+					entryName);
+				return 1;
+			}
+
+			if (handler.AddFilterEntry(entryName) != B_OK)
+				return 1;
+		}
+	} else
+		handler.SetExtractAll();
 
 	// get the target directory, if requested
 	if (changeToDirectory != NULL) {
@@ -427,13 +719,21 @@ command_extract(int argc, const char* const* argv)
 		handler.SetPackageInfoFile(packageInfoFileName);
 
 	// extract
-	error = handler.Init();
-	if (error != B_OK)
-		return 1;
-
 	error = packageReader.ParseContent(&handler);
 	if (error != B_OK)
 		return 1;
 
+	// check whether all explicitly specified entries have been extracted
+	if (explicitEntriesIndex < argc) {
+		for (int i = explicitEntriesIndex; i < argc; i++) {
+			if (Entry* entry = handler.FindFilterEntry(argv[i])) {
+				if (!entry->Seen()) {
+					fprintf(stderr, "Warning: Entry \"%s\" not found.\n",
+						argv[i]);
+				}
+			}
+		}
+	}
+
 	return 0;
 }
diff --git a/src/bin/package/package.cpp b/src/bin/package/package.cpp
index 4917703428..cebeff5fc4 100644
--- a/src/bin/package/package.cpp
+++ b/src/bin/package/package.cpp
@@ -36,8 +36,10 @@ static const char* kUsage =
 	"  dump [  ] \n"
 	"    Dumps the TOC section of package file . For debugging only.\n"
 	"\n"
-	"  extract [  ] \n"
-	"    Extracts the contents of package file .\n"
+	"  extract [  ]  [ ... ]\n"
+	"    Extracts the contents of package file . If  are\n"
+	"    specified, only those entries are extracted (directories "
+		"recursively).\n"
 	"\n"
 	"    -C    - Change to directory  before extracting the "
 		"contents\n"
diff --git a/src/tools/package/Jamfile b/src/tools/package/Jamfile
index 9667f53dc8..92baf1fe33 100644
--- a/src/tools/package/Jamfile
+++ b/src/tools/package/Jamfile
@@ -1,6 +1,6 @@
 SubDir HAIKU_TOP src tools package ;
 
-UsePrivateBuildHeaders shared ;
+UsePrivateBuildHeaders shared kernel ;
 
 SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src bin package ] ;
 

From 52232dbf43ef8347f3b2c18a294f0068ed9453d7 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 1 Jul 2011 04:29:34 +0200
Subject: [PATCH 0187/1170] Print relative paths in error messages

---
 src/bin/package/command_extract.cpp | 42 ++++++++++++++++++++---------
 1 file changed, 29 insertions(+), 13 deletions(-)

diff --git a/src/bin/package/command_extract.cpp b/src/bin/package/command_extract.cpp
index dbb24dc7eb..a4cc3e903d 100644
--- a/src/bin/package/command_extract.cpp
+++ b/src/bin/package/command_extract.cpp
@@ -338,13 +338,14 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 				// remove it, otherwise fail.
 				if (!S_ISREG(st.st_mode) && !S_ISLNK(st.st_mode)) {
 					fprintf(stderr, "Error: Can't create entry \"%s\", since "
-						"something is in the way\n", entryName);
+						"something is in the way\n",
+						_EntryPath(entry).String());
 					return B_FILE_EXISTS;
 				}
 
 				if (unlinkat(parentFD, entryName, 0) != 0) {
 					fprintf(stderr, "Error: Failed to unlink entry \"%s\": %s\n",
-						entryName, strerror(errno));
+						_EntryPath(entry).String(), strerror(errno));
 					return errno;
 				}
 
@@ -354,7 +355,8 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 				// fail.
 				if (!S_ISDIR(st.st_mode)) {
 					fprintf(stderr, "Error: Can't create directory \"%s\", "
-						"since something is in the way\n", entryName);
+						"since something is in the way\n",
+						_EntryPath(entry).String());
 					return B_FILE_EXISTS;
 				}
 			}
@@ -365,7 +367,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		if (S_ISREG(entry->Mode())) {
 			if (implicit) {
 				fprintf(stderr, "Error: File \"%s\" was specified as a "
-					"path directory component.\n", entryName);
+					"path directory component.\n", _EntryPath(entry).String());
 				return B_BAD_VALUE;
 			}
 
@@ -377,7 +379,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 				// desired ones in HandleEntryDone().
 			if (fd < 0) {
 				fprintf(stderr, "Error: Failed to create file \"%s\": %s\n",
-					entryName, strerror(errno));
+					_EntryPath(entry).String(), strerror(errno));
 				return errno;
 			}
 
@@ -396,7 +398,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 		} else if (S_ISLNK(entry->Mode())) {
 			if (implicit) {
 				fprintf(stderr, "Error: Symlink \"%s\" was specified as a "
-					"path directory component.\n", entryName);
+					"path directory component.\n", _EntryPath(entry).String());
 				return B_BAD_VALUE;
 			}
 
@@ -405,7 +407,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 			if (symlinkat(symlinkPath != NULL ? symlinkPath : "", parentFD,
 					entryName) != 0) {
 				fprintf(stderr, "Error: Failed to create symlink \"%s\": %s\n",
-					entryName, strerror(errno));
+					_EntryPath(entry).String(), strerror(errno));
 				return errno;
 			}
 // TODO: Set symlink permissions?
@@ -417,12 +419,12 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 				// operations (e.g. attributes) won't fail, but set them to the
 				// desired ones in HandleEntryDone().
 				fprintf(stderr, "Error: Failed to create directory \"%s\": "
-					"%s\n", entryName, strerror(errno));
+					"%s\n", _EntryPath(entry).String(), strerror(errno));
 				return errno;
 			}
 		} else {
 			fprintf(stderr, "Error: Invalid file type for entry \"%s\"\n",
-				entryName);
+				_EntryPath(entry).String());
 			return B_BAD_DATA;
 		}
 
@@ -431,7 +433,7 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 			fd = openat(parentFD, entryName, O_RDONLY | O_NOTRAVERSE);
 			if (fd < 0) {
 				fprintf(stderr, "Error: Failed to open entry \"%s\": %s\n",
-					entryName, strerror(errno));
+					_EntryPath(entry).String(), strerror(errno));
 				return errno;
 			}
 		}
@@ -469,8 +471,8 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 			_GetParentFDAndEntryName(entry, parentFD, entryName);
 
 			fprintf(stderr, "Error: Failed to create attribute \"%s\" of "
-				"file \"%s\": %s\n", attribute->Name(), entryName,
-				strerror(errno));
+				"file \"%s\": %s\n", attribute->Name(),
+				_EntryPath(entry).String(), strerror(errno));
 			return errno;
 		}
 
@@ -503,7 +505,8 @@ struct PackageContentExtractHandler : BPackageContentHandler {
 			if (fchmodat(parentFD, entryName, entry->Mode() & ALLPERMS,
 					/*AT_SYMLINK_NOFOLLOW*/0) != 0) {
 				fprintf(stderr, "Warning: Failed to set permissions of file "
-					"\"%s\": %s\n", entryName, strerror(errno));
+					"\"%s\": %s\n", _EntryPath(entry).String(),
+					strerror(errno));
 			}
 		}
 
@@ -573,6 +576,19 @@ private:
 		}
 	}
 
+	BString _EntryPath(const BPackageEntry* entry)
+	{
+		BString path;
+
+		if (const BPackageEntry* parent = entry->Parent()) {
+			path = _EntryPath(parent);
+			path << '/';
+		}
+
+		path << entry->Name();
+		return path;
+	}
+
 	status_t _ExtractFileData(BDataReader* dataReader, const BPackageData& data,
 		int fd)
 	{

From 285f4a321ab6fbfc7988f37ef3ef9b64f0aadbc4 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 2 Jul 2011 00:32:35 +0200
Subject: [PATCH 0188/1170] Remove debug output

---
 src/kits/package/hpkg/PackageWriterImpl.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index cd9791b354..9c6ed495f8 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -307,7 +307,6 @@ PackageWriterImpl::AddEntry(const char* fileName, int fd)
 				if (result != B_OK)
 					return result;
 			} else {
-printf("  reading by name...\n");
 				// use the file name
 				BEntry packageInfoEntry(fileName);
 				status_t result = fPackageInfo.ReadFromConfigFile(

From 697b9545b17b6a29237523f6e5aac14a1cab5684 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 2 Jul 2011 02:29:40 +0200
Subject: [PATCH 0189/1170] BLowLevelPackageContentHandler interface extension

HandleAttributeDone(): Add parentToken parameter.
---
 headers/os/package/hpkg/PackageContentHandler.h |  2 +-
 headers/private/package/hpkg/ReaderImplBase.h   |  4 +++-
 src/bin/package/command_dump.cpp                |  2 +-
 src/kits/package/hpkg/ReaderImplBase.cpp        | 12 +++++++-----
 4 files changed, 12 insertions(+), 8 deletions(-)

diff --git a/headers/os/package/hpkg/PackageContentHandler.h b/headers/os/package/hpkg/PackageContentHandler.h
index 1314d92785..2d421155d1 100644
--- a/headers/os/package/hpkg/PackageContentHandler.h
+++ b/headers/os/package/hpkg/PackageContentHandler.h
@@ -32,7 +32,7 @@ public:
 	virtual	status_t			HandleAttributeDone(
 									BHPKGAttributeID attributeID,
 									const BPackageAttributeValue& value,
-									void* token) = 0;
+									void* parentToken, void* token) = 0;
 
 	virtual	void				HandleErrorOccurred() = 0;
 
diff --git a/headers/private/package/hpkg/ReaderImplBase.h b/headers/private/package/hpkg/ReaderImplBase.h
index 5ddc5aa73d..a65a7c80bc 100644
--- a/headers/private/package/hpkg/ReaderImplBase.h
+++ b/headers/private/package/hpkg/ReaderImplBase.h
@@ -145,7 +145,8 @@ protected:
 			struct LowLevelAttributeHandler : AttributeHandler {
 				LowLevelAttributeHandler();
 				LowLevelAttributeHandler(uint8 id,
-					const BPackageAttributeValue& value, void* token);
+					const BPackageAttributeValue& value, void* parentToken,
+					void* token);
 
 				virtual status_t HandleAttribute(
 					AttributeHandlerContext* context, uint8 id,
@@ -153,6 +154,7 @@ protected:
 				virtual status_t Delete(AttributeHandlerContext* context);
 
 			private:
+				void*			fParentToken;
 				void*			fToken;
 				uint8			fID;
 				AttributeValue	fValue;
diff --git a/src/bin/package/command_dump.cpp b/src/bin/package/command_dump.cpp
index 789c32c8ec..c5387c31b6 100644
--- a/src/bin/package/command_dump.cpp
+++ b/src/bin/package/command_dump.cpp
@@ -50,7 +50,7 @@ struct PackageContentDumpHandler : BLowLevelPackageContentHandler {
 	}
 
 	virtual status_t HandleAttributeDone(BHPKGAttributeID attributeID,
-		const BPackageAttributeValue& value, void* token)
+		const BPackageAttributeValue& value, void* parentToken, void* token)
 	{
 		if (fErrorOccurred)
 			return B_OK;
diff --git a/src/kits/package/hpkg/ReaderImplBase.cpp b/src/kits/package/hpkg/ReaderImplBase.cpp
index 44706b9bf7..8da4d32073 100644
--- a/src/kits/package/hpkg/ReaderImplBase.cpp
+++ b/src/kits/package/hpkg/ReaderImplBase.cpp
@@ -463,6 +463,7 @@ ReaderImplBase::PackageAttributeHandler::HandleAttribute(
 
 ReaderImplBase::LowLevelAttributeHandler::LowLevelAttributeHandler()
 	:
+	fParentToken(NULL),
 	fToken(NULL),
 	fID(B_HPKG_ATTRIBUTE_ID_ENUM_COUNT)
 {
@@ -470,8 +471,9 @@ ReaderImplBase::LowLevelAttributeHandler::LowLevelAttributeHandler()
 
 
 ReaderImplBase::LowLevelAttributeHandler::LowLevelAttributeHandler(uint8 id,
-	const BPackageAttributeValue& value, void* token)
+	const BPackageAttributeValue& value, void* parentToken, void* token)
 	:
+	fParentToken(NULL),
 	fToken(token),
 	fID(id),
 	fValue(value)
@@ -494,10 +496,10 @@ ReaderImplBase::LowLevelAttributeHandler::HandleAttribute(
 	// create a subhandler for the attribute, if it has children
 	if (_handler != NULL) {
 		*_handler = new(std::nothrow) LowLevelAttributeHandler(id, value,
-			token);
+			fToken, token);
 		if (*_handler == NULL) {
 			context->lowLevelHandler->HandleAttributeDone((BHPKGAttributeID)id,
-				value, token);
+				value, fToken, token);
 			return B_NO_MEMORY;
 		}
 		return B_OK;
@@ -505,7 +507,7 @@ ReaderImplBase::LowLevelAttributeHandler::HandleAttribute(
 
 	// no children -- just call the done hook
 	return context->lowLevelHandler->HandleAttributeDone((BHPKGAttributeID)id,
-		value, token);
+		value, fToken, token);
 }
 
 
@@ -516,7 +518,7 @@ ReaderImplBase::LowLevelAttributeHandler::Delete(
 	status_t error = B_OK;
 	if (fID != B_HPKG_ATTRIBUTE_ID_ENUM_COUNT) {
 		error = context->lowLevelHandler->HandleAttributeDone(
-			(BHPKGAttributeID)fID, fValue, fToken);
+			(BHPKGAttributeID)fID, fValue, fParentToken, fToken);
 	}
 
 	delete this;

From 82af91fb0ecc92d000d8be513d71353961bffd71 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 2 Jul 2011 04:49:49 +0200
Subject: [PATCH 0190/1170] SubPathAdder: Check for overflows, omit initial /

---
 src/kits/package/hpkg/PackageWriterImpl.cpp | 27 ++++++++++++++-------
 1 file changed, 18 insertions(+), 9 deletions(-)

diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 9c6ed495f8..41439c0050 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -196,17 +196,28 @@ private:
 
 
 struct PackageWriterImpl::SubPathAdder {
-	SubPathAdder(char* pathBuffer, const char* subPath)
-		: fOriginalPathEnd(pathBuffer + strlen(pathBuffer))
+	SubPathAdder(BErrorOutput* errorOutput, char* pathBuffer,
+		const char* subPath)
+		:
+		fOriginalPathEnd(pathBuffer + strlen(pathBuffer))
 	{
-		strcat(pathBuffer, "/");
-		strcat(pathBuffer, subPath);
+		if (fOriginalPathEnd != pathBuffer)
+			strlcat(pathBuffer, "/", B_PATH_NAME_LENGTH);
+
+		if (strlcat(pathBuffer, subPath, B_PATH_NAME_LENGTH)
+				>= B_PATH_NAME_LENGTH) {
+			*fOriginalPathEnd = '\0';
+			errorOutput->PrintError("Path too long: \"%s/%s\"\n", pathBuffer,
+				subPath);
+			throw status_t(B_BUFFER_OVERFLOW);
+		}
 	}
 
 	~SubPathAdder()
 	{
 		*fOriginalPathEnd = '\0';
 	}
+
 private:
 	char* fOriginalPathEnd;
 };
@@ -668,11 +679,9 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 {
 	bool isImplicitEntry = entry != NULL && entry->IsImplicit();
 
-	SubPathAdder pathAdder(pathBuffer, fileName);
-	if (!isImplicitEntry) {
-		fListener->OnEntryAdded(pathBuffer + 1);
-			// pathBuffer + 1 in order to skip leading slash
-	}
+	SubPathAdder pathAdder(fListener, pathBuffer, fileName);
+	if (!isImplicitEntry)
+		fListener->OnEntryAdded(pathBuffer);
 
 	// open the node
 	int fd;

From ffa2b2104bfa68250f1308b0d8f74b9b5ee35d55 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 2 Jul 2011 04:50:51 +0200
Subject: [PATCH 0191/1170] PackageWriterImpl::_AddEntry(): Improve output

Print the relative path instead of only the leaf name.
---
 src/kits/package/hpkg/PackageWriterImpl.cpp | 16 ++++++++--------
 1 file changed, 8 insertions(+), 8 deletions(-)

diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 41439c0050..4c689aa70d 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -694,8 +694,8 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 		fd = openat(dirFD, fileName,
 			O_RDONLY | (isImplicitEntry ? 0 : O_NOTRAVERSE));
 		if (fd < 0) {
-			fListener->PrintError("Failed to open entry \"%s\": %s\n", fileName,
-				strerror(errno));
+			fListener->PrintError("Failed to open entry \"%s\": %s\n",
+				pathBuffer, strerror(errno));
 			throw status_t(errno);
 		}
 		fdCloser.SetTo(fd);
@@ -704,7 +704,7 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 	// stat the node
 	struct stat st;
 	if (fstat(fd, &st) < 0) {
-		fListener->PrintError("Failed to fstat() file \"%s\": %s\n", fileName,
+		fListener->PrintError("Failed to fstat() file \"%s\": %s\n", pathBuffer,
 			strerror(errno));
 		throw status_t(errno);
 	}
@@ -712,7 +712,7 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 	// implicit entries must be directories
 	if (isImplicitEntry && !S_ISDIR(st.st_mode)) {
 		fListener->PrintError("Non-leaf path component \"%s\" is not a "
-			"directory\n", fileName);
+			"directory\n", pathBuffer);
 		throw status_t(B_BAD_VALUE);
 	}
 
@@ -731,7 +731,7 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 	} else {
 		// unsupported node type
 		fListener->PrintError("Unsupported node type, entry: \"%s\"\n",
-			fileName);
+			pathBuffer);
 		throw status_t(B_UNSUPPORTED);
 	}
 
@@ -772,7 +772,7 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 			B_PATH_NAME_LENGTH);
 		if (bytesRead < 0) {
 			fListener->PrintError("Failed to read symlink \"%s\": %s\n",
-				fileName, strerror(errno));
+				pathBuffer, strerror(errno));
 			throw status_t(errno);
 		}
 
@@ -789,7 +789,7 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 			if (fs_stat_attr(fd, entry->d_name, &attrInfo) < 0) {
 				fListener->PrintError(
 					"Failed to stat attribute \"%s\" of file \"%s\": %s\n",
-					entry->d_name, fileName, strerror(errno));
+					entry->d_name, pathBuffer, strerror(errno));
 				throw status_t(errno);
 			}
 
@@ -831,7 +831,7 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 			DIR* dir = fdopendir(clonedFD);
 			if (dir == NULL) {
 				fListener->PrintError(
-					"Failed to open directory \"%s\": %s\n", fileName,
+					"Failed to open directory \"%s\": %s\n", pathBuffer,
 					strerror(errno));
 				close(clonedFD);
 				throw status_t(errno);

From eb601f803e1d79c98d7cb2367e13f70aceafce56 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 2 Jul 2011 18:06:40 +0200
Subject: [PATCH 0192/1170] Move Debugger's Array class to headers/shared

---
 .../util => headers/private/shared}/Array.h   | 73 +++++++++++--------
 src/apps/debugger/arch/x86/ArchitectureX86.h  |  3 +-
 src/apps/debugger/dwarf/CompilationUnit.h     |  4 +-
 src/apps/debugger/model/FileSourceCode.h      |  2 +-
 src/apps/debugger/types/ArrayIndexPath.h      |  3 +-
 .../debugger/types/TargetAddressRangeList.h   |  3 +-
 src/apps/debugger/types/ValueLocation.h       |  2 +-
 src/apps/debugger/util/BitBuffer.h            |  3 +-
 8 files changed, 54 insertions(+), 39 deletions(-)
 rename {src/apps/debugger/util => headers/private/shared}/Array.h (74%)

diff --git a/src/apps/debugger/util/Array.h b/headers/private/shared/Array.h
similarity index 74%
rename from src/apps/debugger/util/Array.h
rename to headers/private/shared/Array.h
index 7b74acbf4d..8b514187cf 100644
--- a/src/apps/debugger/util/Array.h
+++ b/headers/private/shared/Array.h
@@ -1,16 +1,23 @@
 /*
- * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de. All Rights Reserved.
+ * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
  * Distributed under the terms of the MIT License.
  */
-#ifndef ARRAY_H
-#define ARRAY_H
+#ifndef _ARRAY_H
+#define _ARRAY_H
 
 
 #include 
 #include 
 #include 
 
-#include 
+#include 
+
+#if DEBUG
+#	include 
+#endif
+
+
+namespace BPrivate {
 
 
 template
@@ -20,37 +27,37 @@ public:
 								Array(const Array& other);
 								~Array();
 
-	inline	int					Size() const		{ return fSize; }
-	inline	int					Count() const		{ return fSize; }
+	inline	int32				Size() const		{ return fSize; }
+	inline	int32				Count() const		{ return fSize; }
 	inline	bool				IsEmpty() const		{ return fSize == 0; }
 	inline	Element*			Elements() const	{ return fElements; }
 
 	inline	bool				Add(const Element& element);
-	inline	bool				AddUninitialized(int elementCount);
-	inline	bool				Insert(const Element& element, int index);
-	inline	bool				InsertUninitialized(int index, int count);
-	inline	bool				Remove(int index, int count = 1);
+	inline	bool				AddUninitialized(int32 elementCount);
+	inline	bool				Insert(const Element& element, int32 index);
+	inline	bool				InsertUninitialized(int32 index, int32 count);
+	inline	bool				Remove(int32 index, int32 count = 1);
 
 			void				Clear();
 	inline	void				MakeEmpty();
 
-	inline	Element&			ElementAt(int index);
-	inline	const Element&		ElementAt(int index) const;
+	inline	Element&			ElementAt(int32 index);
+	inline	const Element&		ElementAt(int32 index) const;
 
-	inline	Element&			operator[](int index);
-	inline	const Element&		operator[](int index) const;
+	inline	Element&			operator[](int32 index);
+	inline	const Element&		operator[](int32 index) const;
 
 			Array&		operator=(const Array& other);
 
 private:
-	static	const int			kMinCapacity = 8;
+	static	const int32			kMinCapacity = 8;
 
-			bool				_Resize(int index, int delta);
+			bool				_Resize(int32 index, int32 delta);
 
 private:
 			Element*			fElements;
-			int					fSize;
-			int					fCapacity;
+			int32				fSize;
+			int32				fCapacity;
 };
 
 
@@ -97,7 +104,7 @@ Array::Add(const Element& element)
 
 template
 inline bool
-Array::AddUninitialized(int elementCount)
+Array::AddUninitialized(int32 elementCount)
 {
 	return InsertUninitialized(fSize, elementCount);
 }
@@ -105,7 +112,7 @@ Array::AddUninitialized(int elementCount)
 
 template
 bool
-Array::Insert(const Element& element, int index)
+Array::Insert(const Element& element, int32 index)
 {
 	if (index < 0 || index > fSize)
 		index = fSize;
@@ -121,7 +128,7 @@ Array::Insert(const Element& element, int index)
 
 template
 bool
-Array::InsertUninitialized(int index, int count)
+Array::InsertUninitialized(int32 index, int32 count)
 {
 	if (index < 0 || index > fSize || count < 0)
 		return false;
@@ -138,7 +145,7 @@ Array::InsertUninitialized(int index, int count)
 
 template
 bool
-Array::Remove(int index, int count)
+Array::Remove(int32 index, int32 count)
 {
 	if (index < 0 || count < 0 || index + count > fSize) {
 #if DEBUG
@@ -189,7 +196,7 @@ Array::MakeEmpty()
 
 template
 Element&
-Array::ElementAt(int index)
+Array::ElementAt(int32 index)
 {
 	return fElements[index];
 }
@@ -197,7 +204,7 @@ Array::ElementAt(int index)
 
 template
 const Element&
-Array::ElementAt(int index) const
+Array::ElementAt(int32 index) const
 {
 	return fElements[index];
 }
@@ -205,7 +212,7 @@ Array::ElementAt(int index) const
 
 template
 Element&
-Array::operator[](int index)
+Array::operator[](int32 index)
 {
 	return fElements[index];
 }
@@ -213,7 +220,7 @@ Array::operator[](int index)
 
 template
 const Element&
-Array::operator[](int index) const
+Array::operator[](int32 index) const
 {
 	return fElements[index];
 }
@@ -236,11 +243,11 @@ Array::operator=(const Array& other)
 
 template
 bool
-Array::_Resize(int index, int delta)
+Array::_Resize(int32 index, int32 delta)
 {
 	// determine new capacity
-	int newSize = fSize + delta;
-	int newCapacity = kMinCapacity;
+	int32 newSize = fSize + delta;
+	int32 newCapacity = kMinCapacity;
 	while (newCapacity < newSize)
 		newCapacity *= 2;
 
@@ -287,4 +294,10 @@ Array::_Resize(int index, int delta)
 }
 
 
-#endif	// ARRAY_H
+}	// namespace BPrivate
+
+
+using BPrivate::Array;
+
+
+#endif	// _ARRAY_H
diff --git a/src/apps/debugger/arch/x86/ArchitectureX86.h b/src/apps/debugger/arch/x86/ArchitectureX86.h
index 0f5bba0975..d2034edb46 100644
--- a/src/apps/debugger/arch/x86/ArchitectureX86.h
+++ b/src/apps/debugger/arch/x86/ArchitectureX86.h
@@ -6,8 +6,9 @@
 #define ARCHITECTURE_X86_H
 
 
+#include 
+
 #include "Architecture.h"
-#include "Array.h"
 #include "Register.h"
 
 
diff --git a/src/apps/debugger/dwarf/CompilationUnit.h b/src/apps/debugger/dwarf/CompilationUnit.h
index 3fc6ddd2ac..44d7520a29 100644
--- a/src/apps/debugger/dwarf/CompilationUnit.h
+++ b/src/apps/debugger/dwarf/CompilationUnit.h
@@ -6,11 +6,11 @@
 #define COMPILATION_UNIT_H
 
 
+#include 
 #include 
 
-#include 
+#include 
 
-#include "Array.h"
 #include "LineNumberProgram.h"
 #include "Types.h"
 
diff --git a/src/apps/debugger/model/FileSourceCode.h b/src/apps/debugger/model/FileSourceCode.h
index e6a0191fd8..b30415b9d0 100644
--- a/src/apps/debugger/model/FileSourceCode.h
+++ b/src/apps/debugger/model/FileSourceCode.h
@@ -8,8 +8,8 @@
 
 #include 
 
+#include 
 
-#include "Array.h"
 #include "SourceCode.h"
 
 
diff --git a/src/apps/debugger/types/ArrayIndexPath.h b/src/apps/debugger/types/ArrayIndexPath.h
index 834444e3da..b739ef447a 100644
--- a/src/apps/debugger/types/ArrayIndexPath.h
+++ b/src/apps/debugger/types/ArrayIndexPath.h
@@ -6,7 +6,8 @@
 #define ARRAY_INDEX_PATH_H
 
 
-#include "Array.h"
+#include 
+
 #include "Types.h"
 
 
diff --git a/src/apps/debugger/types/TargetAddressRangeList.h b/src/apps/debugger/types/TargetAddressRangeList.h
index 118684b10e..3a7fdb325c 100644
--- a/src/apps/debugger/types/TargetAddressRangeList.h
+++ b/src/apps/debugger/types/TargetAddressRangeList.h
@@ -5,9 +5,10 @@
 #ifndef TARGET_ADDRESS_RANGE_LIST_H
 #define TARGET_ADDRESS_RANGE_LIST_H
 
+
+#include 
 #include 
 
-#include "Array.h"
 #include "TargetAddressRange.h"
 
 
diff --git a/src/apps/debugger/types/ValueLocation.h b/src/apps/debugger/types/ValueLocation.h
index e49164e798..5b598d9cdc 100644
--- a/src/apps/debugger/types/ValueLocation.h
+++ b/src/apps/debugger/types/ValueLocation.h
@@ -6,9 +6,9 @@
 #define VALUE_LOCATION_H
 
 
+#include 
 #include 
 
-#include "Array.h"
 #include "Types.h"
 
 
diff --git a/src/apps/debugger/util/BitBuffer.h b/src/apps/debugger/util/BitBuffer.h
index 6c852c0a9a..51354cbad7 100644
--- a/src/apps/debugger/util/BitBuffer.h
+++ b/src/apps/debugger/util/BitBuffer.h
@@ -8,8 +8,7 @@
 
 #include 
 
-
-#include "Array.h"
+#include 
 
 
 class BitBuffer {

From 5518472255ef10b5b03d30a8d2115cffa3a8dfa6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 03:55:30 +0200
Subject: [PATCH 0193/1170] Declare Array destructor inline

---
 headers/private/shared/Array.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/headers/private/shared/Array.h b/headers/private/shared/Array.h
index 8b514187cf..69f32e4c2f 100644
--- a/headers/private/shared/Array.h
+++ b/headers/private/shared/Array.h
@@ -25,7 +25,7 @@ class Array {
 public:
 	inline						Array();
 								Array(const Array& other);
-								~Array();
+	inline						~Array();
 
 	inline	int32				Size() const		{ return fSize; }
 	inline	int32				Count() const		{ return fSize; }

From 85759ab92f9ad360b2c840d200048e9bb8839f01 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 03:57:51 +0200
Subject: [PATCH 0194/1170] Add RangeArray utility class

Templatized class for managing a set of sorted non-overlapping integer
ranges. Merges and splits ranges as necessary.
---
 headers/private/shared/RangeArray.h | 304 ++++++++++++++++++++++++++++
 1 file changed, 304 insertions(+)
 create mode 100644 headers/private/shared/RangeArray.h

diff --git a/headers/private/shared/RangeArray.h b/headers/private/shared/RangeArray.h
new file mode 100644
index 0000000000..c775d6d46b
--- /dev/null
+++ b/headers/private/shared/RangeArray.h
@@ -0,0 +1,304 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _RANGE_ARRAY_H
+#define _RANGE_ARRAY_H
+
+
+#include 
+
+#include 
+
+
+namespace BPrivate {
+
+
+template
+struct Range {
+	Value	offset;
+	Value	size;
+
+	Range(const Value& offset, const Value& size)
+		:
+		offset(offset),
+		size(size)
+	{
+	}
+
+	Value EndOffset() const
+	{
+		return offset + size;
+	}
+};
+
+
+template
+class RangeArray {
+public:
+			typedef Range RangeType;
+
+public:
+	inline						RangeArray();
+	inline						RangeArray(const RangeArray& other);
+
+	inline	int32				CountRanges() const
+									{ return fRanges.Count(); }
+	inline	bool				IsEmpty() const
+									{ return fRanges.IsEmpty(); }
+	inline	const RangeType*	Ranges() const
+									{ return fRanges.Elements(); }
+
+	inline	bool				AddRange(const RangeType& range);
+			bool				AddRange(const Value& offset,
+									const Value& size);
+	inline	bool				RemoveRange(const RangeType& range);
+			bool				RemoveRange(const Value& offset,
+									const Value& size);
+	inline	bool				RemoveRanges(int32 index, int32 count = 1);
+
+	inline	void				Clear()			{ fRanges.Clear(); }
+	inline	void				MakeEmpty()		{ fRanges.MakeEmpty(); }
+
+	inline	bool				IntersectsWith(const RangeType& range) const;
+			bool				IntersectsWith(const Value& offset,
+									const Value& size) const;
+
+			int32				InsertionIndex(const Value& offset) const;
+
+	inline	const RangeType&	RangeAt(int32 index) const
+									{ return fRanges.ElementAt(index); }
+
+	inline	const RangeType&	operator[](int32 index) const
+									{ return fRanges[index]; }
+
+	inline	RangeArray&	operator=(const RangeArray& other);
+
+private:
+	inline	 RangeType&			_RangeAt(int32 index)
+									{ return fRanges.ElementAt(index); }
+
+private:
+			Array	fRanges;
+};
+
+
+template
+inline
+RangeArray::RangeArray()
+{
+}
+
+
+template
+inline
+RangeArray::RangeArray(const RangeArray& other)
+	:
+	fRanges(other.fRanges)
+{
+}
+
+
+template
+inline bool
+RangeArray::AddRange(const RangeType& range)
+{
+	return AddRange(range.offset, range.size);
+}
+
+
+/*!	Adds the range starting at \a offset with size \a size.
+
+	The range is automatically joined with ranges it adjoins or overlaps with.
+
+	\return \c true, if the range was added successfully, \c false, if a memory
+		allocation failed.
+*/
+template
+bool
+RangeArray::AddRange(const Value& offset, const Value& size)
+{
+	if (size == 0)
+		return true;
+
+	int32 index = InsertionIndex(offset);
+
+	// determine the last range the range intersects with/adjoins
+	Value endOffset = offset + size;
+	int32 endIndex = index;
+		// index after the last affected range
+	int32 count = CountRanges();
+	while (endIndex < count && RangeAt(endIndex).offset <= endOffset)
+		endIndex++;
+
+	// determine whether the range adjoins the previous range
+	if (index > 0 && offset == RangeAt(index - 1).EndOffset())
+		index--;
+
+	if (index == endIndex) {
+		// no joining possible -- just insert the new range
+		return fRanges.Insert(RangeType(offset, size), index);
+	}
+
+	// Joining is possible. We'll adjust the first affected range and remove the
+	// others (if any).
+	RangeType& firstRange = _RangeAt(index);
+	firstRange.offset = std::min(firstRange.offset, offset);
+	firstRange.size = std::max(endOffset, RangeAt(endIndex - 1).EndOffset())
+		- firstRange.offset;;
+
+	if (index + 1 < endIndex)
+		RemoveRanges(index + 1, endIndex - index - 1);
+
+	return true;
+}
+
+
+template
+inline bool
+RangeArray::RemoveRange(const RangeType& range)
+{
+	return RemoveRange(range.offset, range.size);
+}
+
+
+/*!	Removes the range starting at \a offset with size \a size.
+
+	Ranges that are completely covered by the given range are removed. Ranges
+	that partially intersect with it are cut accordingly.
+
+	If a range is split into two ranges by the operation, a memory allocation
+	might be necessary and the method can fail, if the memory allocation fails.
+
+	\return \c true, if the range was removed successfully, \c false, if a
+		memory allocation failed.
+*/
+template
+bool
+RangeArray::RemoveRange(const Value& offset, const Value& size)
+{
+	if (size == 0)
+		return true;
+
+	int32 index = InsertionIndex(offset);
+
+	// determine the last range the range intersects with
+	Value endOffset = offset + size;
+	int32 endIndex = index;
+		// index after the last affected range
+	int32 count = CountRanges();
+	while (endIndex < count && RangeAt(endIndex).offset < endOffset)
+		endIndex++;
+
+	if (index == endIndex) {
+		// the given range doesn't intersect with any exiting range
+		return true;
+	}
+
+	// determine what ranges to remove completely
+	RangeType& firstRange = _RangeAt(index);
+	RangeType& lastRange = _RangeAt(endIndex - 1);
+
+	int32 firstRemoveIndex = firstRange.offset >= offset ? index : index + 1;
+	int32 endRemoveIndex = lastRange.EndOffset() <= endOffset
+		? endIndex : endIndex - 1;
+
+	if (firstRemoveIndex > endRemoveIndex) {
+		// The range lies in the middle of an existing range. We need to split.
+		RangeType newRange(endOffset, firstRange.EndOffset() - endOffset);
+		if (!fRanges.Insert(newRange, index + 1))
+			return false;
+
+		firstRange.size = offset - firstRange.offset;
+		return true;
+	}
+
+	// cut first and last range
+	if (index < firstRemoveIndex)
+		firstRange.size = offset - firstRange.offset;
+
+	if (endOffset > endRemoveIndex) {
+		lastRange.size = lastRange.EndOffset() - endOffset;
+		lastRange.offset = endOffset;
+	}
+
+	// remove ranges
+	if (firstRemoveIndex < endRemoveIndex)
+		RemoveRanges(firstRemoveIndex, endRemoveIndex - firstRemoveIndex);
+
+	return true;
+}
+
+
+template
+inline bool
+RangeArray::RemoveRanges(int32 index, int32 count)
+{
+	return fRanges.Remove(index, count);
+}
+
+
+template
+inline bool
+RangeArray::IntersectsWith(const RangeType& range) const
+{
+	return IntersectsWith(range.offset, range.size);
+}
+
+
+template
+bool
+RangeArray::IntersectsWith(const Value& offset, const Value& size) const
+{
+	int32 index = InsertionIndex(offset);
+	return index < CountRanges() && RangeAt(index).offset < offset + size;
+}
+
+
+/*!	Returns the insertion index of a range starting at \a offset.
+
+	If the array contains a range that starts at, includes (but doesn't end at)
+	\a offset, the index of that range is returned. If \a offset lies in between
+	two ranges or before the first range, the index of the range following
+	\a offset is returned. Otherwise \c CountRanges() is returned.
+
+	\return The insertion index for a range starting at \a offset.
+*/
+template
+int32
+RangeArray::InsertionIndex(const Value& offset) const
+{
+	// binary search the index
+	int32 lower = 0;
+	int32 upper = CountRanges();
+
+	while (lower < upper) {
+		int32 mid = (lower + upper) / 2;
+		const RangeType& range = RangeAt(mid);
+		if (offset >= range.EndOffset())
+			lower = mid + 1;
+		else
+			upper = mid;
+	}
+
+	return lower;
+}
+
+
+template
+inline RangeArray&
+RangeArray::operator=(const RangeArray& other)
+{
+	fRanges = other.fRanges;
+	return *this;
+}
+
+
+}	// namespace BPrivate
+
+
+using BPrivate::Range;
+using BPrivate::RangeArray;
+
+
+#endif	// _RANGE_ARRAY_H

From fce74facea3cb8d6b156d0e3e5b3f466e5e41bd1 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 03:58:19 +0200
Subject: [PATCH 0195/1170] Add Array.h and RangeArray.h build headers

---
 headers/build/private/shared/Array.h      | 1 +
 headers/build/private/shared/RangeArray.h | 1 +
 2 files changed, 2 insertions(+)
 create mode 100644 headers/build/private/shared/Array.h
 create mode 100644 headers/build/private/shared/RangeArray.h

diff --git a/headers/build/private/shared/Array.h b/headers/build/private/shared/Array.h
new file mode 100644
index 0000000000..304f936883
--- /dev/null
+++ b/headers/build/private/shared/Array.h
@@ -0,0 +1 @@
+#include <../private/shared/Array.h>
diff --git a/headers/build/private/shared/RangeArray.h b/headers/build/private/shared/RangeArray.h
new file mode 100644
index 0000000000..44ff6888ec
--- /dev/null
+++ b/headers/build/private/shared/RangeArray.h
@@ -0,0 +1 @@
+#include <../private/shared/RangeArray.h>

From b3211314fce9f0147e7743259826ce062bac9b02 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 04:00:23 +0200
Subject: [PATCH 0196/1170] Define IDs for package section

---
 headers/os/package/hpkg/HPKGDefs.h | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/headers/os/package/hpkg/HPKGDefs.h b/headers/os/package/hpkg/HPKGDefs.h
index f50d0bdf23..094b90bcf8 100644
--- a/headers/os/package/hpkg/HPKGDefs.h
+++ b/headers/os/package/hpkg/HPKGDefs.h
@@ -24,6 +24,18 @@ enum {
 };
 
 
+// package attribute IDs
+enum BHPKGPackageSectionID {
+	B_HPKG_SECTION_HEADER					= 0,
+	B_HPKG_SECTION_HEAP						= 1,
+	B_HPKG_SECTION_PACKAGE_TOC				= 2,
+	B_HPKG_SECTION_PACKAGE_ATTRIBUTES		= 3,
+	B_HPKG_SECTION_REPOSITORY_INFO			= 4,
+	//
+	B_HPKG_SECTION_ENUM_COUNT
+};
+
+
 // attribute types
 enum {
 	// types

From 97aabbede911b549e50d7ad753b4755d5c8d85a7 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 04:07:47 +0200
Subject: [PATCH 0197/1170] Add BLowLevelPackageContentHandler section hooks

* Add hooks HandleSectionStart() and HandleSectionEnd(). They are
  invoked to bracket package file section, so the handler can
  discriminate which section the attributes belong to.
  HandleSectionStart() features a return parameter _handleSection, which
  allows to handler to pick which sections it wants to handle.
* "package dump" does now print the section names.
---
 .../os/package/hpkg/PackageContentHandler.h   |  6 +++
 headers/private/package/hpkg/ReaderImplBase.h | 16 ++++--
 src/bin/package/command_dump.cpp              | 37 ++++++++++++++
 src/kits/package/hpkg/PackageReaderImpl.cpp   | 25 +++++++---
 src/kits/package/hpkg/ReaderImplBase.cpp      | 50 ++++++++++++++++---
 .../package/hpkg/RepositoryReaderImpl.cpp     |  8 +--
 6 files changed, 122 insertions(+), 20 deletions(-)

diff --git a/headers/os/package/hpkg/PackageContentHandler.h b/headers/os/package/hpkg/PackageContentHandler.h
index 2d421155d1..b09992b85c 100644
--- a/headers/os/package/hpkg/PackageContentHandler.h
+++ b/headers/os/package/hpkg/PackageContentHandler.h
@@ -26,6 +26,12 @@ class BLowLevelPackageContentHandler {
 public:
 	virtual						~BLowLevelPackageContentHandler();
 
+	virtual	status_t			HandleSectionStart(
+									BHPKGPackageSectionID sectionID,
+									bool& _handleSection) = 0;
+	virtual	status_t			HandleSectionEnd(
+									BHPKGPackageSectionID sectionID) = 0;
+
 	virtual	status_t			HandleAttribute(BHPKGAttributeID attributeID,
 									const BPackageAttributeValue& value,
 									void* parentToken, void*& _token) = 0;
diff --git a/headers/private/package/hpkg/ReaderImplBase.h b/headers/private/package/hpkg/ReaderImplBase.h
index a65a7c80bc..75273e92c2 100644
--- a/headers/private/package/hpkg/ReaderImplBase.h
+++ b/headers/private/package/hpkg/ReaderImplBase.h
@@ -51,11 +51,15 @@ protected:
 				uint64			heapOffset;
 				uint64			heapSize;
 
-				AttributeHandlerContext(BErrorOutput* errorOutput,
-					BPackageContentHandler* packageContentHandler);
+				BHPKGPackageSectionID	section;
 
 				AttributeHandlerContext(BErrorOutput* errorOutput,
-					BLowLevelPackageContentHandler* lowLevelHandler);
+					BPackageContentHandler* packageContentHandler,
+					BHPKGPackageSectionID section);
+
+				AttributeHandlerContext(BErrorOutput* errorOutput,
+					BLowLevelPackageContentHandler* lowLevelHandler,
+					BHPKGPackageSectionID section);
 
 				void ErrorOccurred();
 			};
@@ -200,7 +204,8 @@ protected:
 									AttributeHandlerContext* context,
 									AttributeHandler* rootAttributeHandler);
 			status_t			ParseAttributeTree(
-									AttributeHandlerContext* context);
+									AttributeHandlerContext* context,
+									bool& _sectionHandled);
 
 	virtual	status_t			ReadAttributeValue(uint8 type, uint8 encoding,
 									AttributeValue& _value);
@@ -225,6 +230,9 @@ protected:
 			SectionInfo			fPackageAttributesSection;
 
 private:
+			status_t			_ParseAttributeTree(
+									AttributeHandlerContext* context);
+
 	template
 	inline	status_t			_Read(Type& _value);
 
diff --git a/src/bin/package/command_dump.cpp b/src/bin/package/command_dump.cpp
index c5387c31b6..fdf55d2d31 100644
--- a/src/bin/package/command_dump.cpp
+++ b/src/bin/package/command_dump.cpp
@@ -34,6 +34,43 @@ struct PackageContentDumpHandler : BLowLevelPackageContentHandler {
 	{
 	}
 
+	virtual status_t HandleSectionStart(BHPKGPackageSectionID sectionID,
+		bool& _handleSection)
+	{
+		const char* sectionName;
+
+		switch (sectionID) {
+			case B_HPKG_SECTION_HEADER:
+				sectionName = "header";
+				break;
+			case B_HPKG_SECTION_HEAP:
+				sectionName = "heap";
+				break;
+			case B_HPKG_SECTION_PACKAGE_TOC:
+				sectionName = "TOC";
+				break;
+			case B_HPKG_SECTION_PACKAGE_ATTRIBUTES:
+				sectionName = "package attributes";
+				break;
+			case B_HPKG_SECTION_REPOSITORY_INFO:
+				sectionName = "repository info";
+				break;
+			default:
+				sectionName = "";
+				break;
+		}
+
+		printf("\n====  SECTION: %s ====\n", sectionName);
+
+		_handleSection = true;
+		return B_OK;
+	}
+
+	virtual status_t HandleSectionEnd(BHPKGPackageSectionID sectionID)
+	{
+		return B_OK;
+	}
+
 	virtual status_t HandleAttribute(BHPKGAttributeID attributeID,
 		const BPackageAttributeValue& value, void* parentToken, void*& _token)
 	{
diff --git a/src/kits/package/hpkg/PackageReaderImpl.cpp b/src/kits/package/hpkg/PackageReaderImpl.cpp
index fe08df212b..6f7b2986d8 100644
--- a/src/kits/package/hpkg/PackageReaderImpl.cpp
+++ b/src/kits/package/hpkg/PackageReaderImpl.cpp
@@ -587,12 +587,18 @@ PackageReaderImpl::Init(int fd, bool keepFD)
 status_t
 PackageReaderImpl::ParseContent(BPackageContentHandler* contentHandler)
 {
-	AttributeHandlerContext context(ErrorOutput(), contentHandler);
+	AttributeHandlerContext context(ErrorOutput(), contentHandler,
+		B_HPKG_SECTION_PACKAGE_ATTRIBUTES);
 	RootAttributeHandler rootAttributeHandler;
+
 	status_t error
 		= ParsePackageAttributesSection(&context, &rootAttributeHandler);
-	if (error == B_OK)
+
+	if (error == B_OK) {
+		context.section = B_HPKG_SECTION_PACKAGE_TOC;
 		error = _ParseTOC(&context, &rootAttributeHandler);
+	}
+
 	return error;
 }
 
@@ -600,12 +606,18 @@ PackageReaderImpl::ParseContent(BPackageContentHandler* contentHandler)
 status_t
 PackageReaderImpl::ParseContent(BLowLevelPackageContentHandler* contentHandler)
 {
-	AttributeHandlerContext context(ErrorOutput(), contentHandler);
+	AttributeHandlerContext context(ErrorOutput(), contentHandler,
+		B_HPKG_SECTION_PACKAGE_ATTRIBUTES);
 	LowLevelAttributeHandler rootAttributeHandler;
+
 	status_t error
 		= ParsePackageAttributesSection(&context, &rootAttributeHandler);
-	if (error == B_OK)
+
+	if (error == B_OK) {
+		context.section = B_HPKG_SECTION_PACKAGE_TOC;
 		error = _ParseTOC(&context, &rootAttributeHandler);
+	}
+
 	return error;
 }
 
@@ -627,8 +639,9 @@ PackageReaderImpl::_ParseTOC(AttributeHandlerContext* context,
 	ClearAttributeHandlerStack();
 	PushAttributeHandler(rootAttributeHandler);
 
-	status_t error = ParseAttributeTree(context);
-	if (error == B_OK) {
+	bool sectionHandled;
+	status_t error = ParseAttributeTree(context, sectionHandled);
+	if (error == B_OK && sectionHandled) {
 		if (fTOCSection.currentOffset < fTOCSection.uncompressedLength) {
 			ErrorOutput()->PrintError("Error: %llu excess byte(s) in TOC "
 				"section\n",
diff --git a/src/kits/package/hpkg/ReaderImplBase.cpp b/src/kits/package/hpkg/ReaderImplBase.cpp
index 8da4d32073..727991d764 100644
--- a/src/kits/package/hpkg/ReaderImplBase.cpp
+++ b/src/kits/package/hpkg/ReaderImplBase.cpp
@@ -38,21 +38,25 @@ static const size_t kScratchBufferSize = 64 * 1024;
 
 
 ReaderImplBase::AttributeHandlerContext::AttributeHandlerContext(
-	BErrorOutput* errorOutput, BPackageContentHandler* packageContentHandler)
+	BErrorOutput* errorOutput, BPackageContentHandler* packageContentHandler,
+	BHPKGPackageSectionID section)
 	:
 	errorOutput(errorOutput),
 	packageContentHandler(packageContentHandler),
-	hasLowLevelHandler(false)
+	hasLowLevelHandler(false),
+	section(section)
 {
 }
 
 
 ReaderImplBase::AttributeHandlerContext::AttributeHandlerContext(
-	BErrorOutput* errorOutput, BLowLevelPackageContentHandler* lowLevelHandler)
+	BErrorOutput* errorOutput, BLowLevelPackageContentHandler* lowLevelHandler,
+	BHPKGPackageSectionID section)
 	:
 	errorOutput(errorOutput),
 	lowLevelHandler(lowLevelHandler),
-	hasLowLevelHandler(true)
+	hasLowLevelHandler(true),
+	section(section)
 {
 }
 
@@ -669,8 +673,9 @@ ReaderImplBase::ParsePackageAttributesSection(
 	ClearAttributeHandlerStack();
 	PushAttributeHandler(rootAttributeHandler);
 
-	status_t error = ParseAttributeTree(context);
-	if (error == B_OK) {
+	bool sectionHandled;
+	status_t error = ParseAttributeTree(context, sectionHandled);
+	if (error == B_OK && sectionHandled) {
 		if (fPackageAttributesSection.currentOffset
 				< fPackageAttributesSection.uncompressedLength) {
 			fErrorOutput->PrintError("Error: %llu excess byte(s) in package "
@@ -698,7 +703,38 @@ ReaderImplBase::ParsePackageAttributesSection(
 
 
 status_t
-ReaderImplBase::ParseAttributeTree(AttributeHandlerContext* context)
+ReaderImplBase::ParseAttributeTree(AttributeHandlerContext* context,
+	bool& _sectionHandled)
+{
+	if (context->hasLowLevelHandler) {
+		bool handleSection = false;
+		status_t error = context->lowLevelHandler->HandleSectionStart(
+			context->section, handleSection);
+		if (error != B_OK)
+			return error;
+
+		if (!handleSection) {
+			_sectionHandled = false;
+			return B_OK;
+		}
+	}
+
+	status_t error = _ParseAttributeTree(context);
+
+	if (context->hasLowLevelHandler) {
+		status_t endError = context->lowLevelHandler->HandleSectionEnd(
+			context->section);
+		if (error == B_OK)
+			error = endError;
+	}
+
+	_sectionHandled = true;
+	return error;
+}
+
+
+status_t
+ReaderImplBase::_ParseAttributeTree(AttributeHandlerContext* context)
 {
 	int level = 0;
 
diff --git a/src/kits/package/hpkg/RepositoryReaderImpl.cpp b/src/kits/package/hpkg/RepositoryReaderImpl.cpp
index 253faffbcb..5f315a4000 100644
--- a/src/kits/package/hpkg/RepositoryReaderImpl.cpp
+++ b/src/kits/package/hpkg/RepositoryReaderImpl.cpp
@@ -254,11 +254,13 @@ RepositoryReaderImpl::GetRepositoryInfo(BRepositoryInfo* _repositoryInfo) const
 status_t
 RepositoryReaderImpl::ParseContent(BRepositoryContentHandler* contentHandler)
 {
-	AttributeHandlerContext context(ErrorOutput(), contentHandler);
-	PackageAttributeHandler rootAttributeHandler;
 	status_t result = contentHandler->HandleRepositoryInfo(fRepositoryInfo);
-	if (result == B_OK)
+	if (result == B_OK) {
+		AttributeHandlerContext context(ErrorOutput(), contentHandler,
+			B_HPKG_SECTION_PACKAGE_ATTRIBUTES);
+		PackageAttributeHandler rootAttributeHandler;
 		result = ParsePackageAttributesSection(&context, &rootAttributeHandler);
+	}
 	return result;
 }
 

From c83c5423aa8375a9ba51ae600f0cd365f1042966 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 04:08:40 +0200
Subject: [PATCH 0198/1170] Add PackageReaderImpl heapOffset/Size getters

---
 .../private/package/hpkg/PackageReaderImpl.h    | 17 +++++++++++++++++
 1 file changed, 17 insertions(+)

diff --git a/headers/private/package/hpkg/PackageReaderImpl.h b/headers/private/package/hpkg/PackageReaderImpl.h
index c4522a49e8..b35ac5ec08 100644
--- a/headers/private/package/hpkg/PackageReaderImpl.h
+++ b/headers/private/package/hpkg/PackageReaderImpl.h
@@ -38,6 +38,9 @@ public:
 
 			int					PackageFileFD() const;
 
+			uint64				HeapOffset() const;
+			uint64				HeapSize() const;
+
 protected:
 								// from ReaderImplBase
 	virtual	status_t			ReadAttributeValue(uint8 type, uint8 encoding,
@@ -71,6 +74,20 @@ PackageReaderImpl::PackageFileFD() const
 }
 
 
+inline uint64
+PackageReaderImpl::HeapOffset() const
+{
+	return fHeapOffset;
+}
+
+
+inline uint64
+PackageReaderImpl::HeapSize() const
+{
+	return fHeapSize;
+}
+
+
 }	// namespace BPrivate
 
 }	// namespace BHPKG

From abbeb15ac4f2b6524852c09a35db7b3b90b0cd3c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 04:13:12 +0200
Subject: [PATCH 0199/1170] Move RegisterPackageInfo() to Finish()

---
 src/kits/package/hpkg/PackageWriterImpl.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 4c689aa70d..6af51210c1 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -327,8 +327,6 @@ PackageWriterImpl::AddEntry(const char* fileName, int fd)
 					return result;
 				}
 			}
-
-			RegisterPackageInfo(PackageAttributes(), fPackageInfo);
 		}
 
 		return _RegisterEntry(fileName, fd);
@@ -351,6 +349,8 @@ PackageWriterImpl::Finish()
 			return B_BAD_DATA;
 		}
 
+		RegisterPackageInfo(PackageAttributes(), fPackageInfo);
+
 		status_t result = _CheckLicenses();
 		if (result != B_OK)
 			return result;

From 04258e474118bc6d00e704d058723aec6fcf193f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 04:15:24 +0200
Subject: [PATCH 0200/1170] Use fHeapOffset instead of sizeof(hpkg_header)

---
 src/kits/package/hpkg/PackageWriterImpl.cpp | 7 +++----
 1 file changed, 3 insertions(+), 4 deletions(-)

diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 6af51210c1..240f137110 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -448,7 +448,7 @@ PackageWriterImpl::_Finish()
 		_AddEntry(AT_FDCWD, entry, entry->Name(), pathBuffer);
 	}
 
-	off_t heapSize = fHeapEnd - sizeof(hpkg_header);
+	off_t heapSize = fHeapEnd - fHeapOffset;
 
 	hpkg_header header;
 
@@ -458,7 +458,7 @@ PackageWriterImpl::_Finish()
 
 	off_t totalSize = fHeapEnd;
 
-	fListener->OnPackageSizeInfo(sizeof(hpkg_header), heapSize,
+	fListener->OnPackageSizeInfo(fHeapOffset, heapSize,
 		B_BENDIAN_TO_HOST_INT64(header.toc_length_compressed),
 		B_BENDIAN_TO_HOST_INT32(header.attributes_length_compressed),
 		totalSize);
@@ -467,8 +467,7 @@ PackageWriterImpl::_Finish()
 
 	// general
 	header.magic = B_HOST_TO_BENDIAN_INT32(B_HPKG_MAGIC);
-	header.header_size = B_HOST_TO_BENDIAN_INT16(
-		(uint16)sizeof(hpkg_header));
+	header.header_size = B_HOST_TO_BENDIAN_INT16((uint16)fHeapOffset);
 	header.version = B_HOST_TO_BENDIAN_INT16(B_HPKG_VERSION);
 	header.total_size = B_HOST_TO_BENDIAN_INT64(totalSize);
 

From 7b6bcdb146b8ac24ef3569fcb152627f724e156c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 04:20:35 +0200
Subject: [PATCH 0201/1170] Write uncompressed package attributes if necessary

When compression doesn't save space, using it nonetheless results in a
file that the reader complains about. So we fall back to writing an
uncompressed package attributes section in such a case.

The same still needs to be done for the TOC section.
---
 .../private/package/hpkg/PackageWriterImpl.h  |  6 ++
 src/kits/package/hpkg/PackageWriterImpl.cpp   | 76 +++++++++++++++----
 2 files changed, 67 insertions(+), 15 deletions(-)

diff --git a/headers/private/package/hpkg/PackageWriterImpl.h b/headers/private/package/hpkg/PackageWriterImpl.h
index e70514457d..d913bc4167 100644
--- a/headers/private/package/hpkg/PackageWriterImpl.h
+++ b/headers/private/package/hpkg/PackageWriterImpl.h
@@ -65,6 +65,12 @@ private:
 			void				_WriteAttributeChildren(Attribute* attribute);
 
 			void				_WritePackageAttributes(hpkg_header& header);
+			uint32				_WritePackageAttributesCompressed(
+									uint32& _stringsLengthUncompressed,
+									uint32& _attributesLengthUncompressed);
+			uint32				_WritePackageAttributesUncompressed(
+									uint32& _stringsLengthUncompressed,
+									uint32& _attributesLengthUncompressed);
 
 			void				_AddEntry(int dirFD, Entry* entry,
 									const char* fileName, char* pathBuffer);
diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 240f137110..48c21868cf 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -640,35 +640,81 @@ PackageWriterImpl::_WritePackageAttributes(hpkg_header& header)
 {
 	// write the package attributes (zlib writer on top of a file writer)
 	off_t startOffset = fHeapEnd;
+
+	uint32 compression = B_HPKG_COMPRESSION_ZLIB;
+	uint32 stringsLengthUncompressed;
+	uint32 attributesLengthUncompressed;
+	uint32 stringsCount = _WritePackageAttributesCompressed(
+		stringsLengthUncompressed, attributesLengthUncompressed);
+
+	off_t endOffset = fHeapEnd;
+
+	if ((off_t)attributesLengthUncompressed <= endOffset - startOffset) {
+		// the compressed section isn't shorter -- write uncompressed
+		fHeapEnd = startOffset;
+		compression = B_HPKG_COMPRESSION_NONE;
+		stringsCount = _WritePackageAttributesUncompressed(
+			stringsLengthUncompressed, attributesLengthUncompressed);
+
+		endOffset = fHeapEnd;
+	}
+
+	fListener->OnPackageAttributesSizeInfo(stringsCount,
+		attributesLengthUncompressed);
+
+	// update the header
+	header.attributes_compression = B_HOST_TO_BENDIAN_INT32(compression);
+	header.attributes_length_compressed
+		= B_HOST_TO_BENDIAN_INT32(endOffset - startOffset);
+	header.attributes_length_uncompressed
+		= B_HOST_TO_BENDIAN_INT32(attributesLengthUncompressed);
+	header.attributes_strings_count = B_HOST_TO_BENDIAN_INT32(stringsCount);
+	header.attributes_strings_length
+		= B_HOST_TO_BENDIAN_INT32(stringsLengthUncompressed);
+}
+
+
+uint32
+PackageWriterImpl::_WritePackageAttributesCompressed(
+	uint32& _stringsLengthUncompressed, uint32& _attributesLengthUncompressed)
+{
+	off_t startOffset = fHeapEnd;
 	FDDataWriter realWriter(FD(), startOffset, fListener);
 	ZlibDataWriter zlibWriter(&realWriter);
 	SetDataWriter(&zlibWriter);
 	zlibWriter.Init();
 
 	// write cached strings and package attributes tree
-	uint32 stringsLengthUncompressed;
 	uint32 stringsCount = WritePackageAttributes(PackageAttributes(),
-		stringsLengthUncompressed);
+		_stringsLengthUncompressed);
 
 	zlibWriter.Finish();
 	fHeapEnd = realWriter.Offset();
 	SetDataWriter(NULL);
 
-	off_t endOffset = fHeapEnd;
+	_attributesLengthUncompressed = zlibWriter.BytesWritten();
+	return stringsCount;
+}
 
-	fListener->OnPackageAttributesSizeInfo(stringsCount,
-		zlibWriter.BytesWritten());
 
-	// update the header
-	header.attributes_compression
-		= B_HOST_TO_BENDIAN_INT32(B_HPKG_COMPRESSION_ZLIB);
-	header.attributes_length_compressed
-		= B_HOST_TO_BENDIAN_INT32(endOffset - startOffset);
-	header.attributes_length_uncompressed
-		= B_HOST_TO_BENDIAN_INT32(zlibWriter.BytesWritten());
-	header.attributes_strings_count = B_HOST_TO_BENDIAN_INT32(stringsCount);
-	header.attributes_strings_length
-		= B_HOST_TO_BENDIAN_INT32(stringsLengthUncompressed);
+uint32
+PackageWriterImpl::_WritePackageAttributesUncompressed(
+	uint32& _stringsLengthUncompressed, uint32& _attributesLengthUncompressed)
+{
+	off_t startOffset = fHeapEnd;
+	FDDataWriter realWriter(FD(), startOffset, fListener);
+
+	SetDataWriter(&realWriter);
+
+	// write cached strings and package attributes tree
+	uint32 stringsCount = WritePackageAttributes(PackageAttributes(),
+		_stringsLengthUncompressed);
+
+	fHeapEnd = realWriter.Offset();
+	SetDataWriter(NULL);
+
+	_attributesLengthUncompressed = realWriter.BytesWritten();
+	return stringsCount;
 }
 
 

From 327b38d69c8d9a128c64d0535f15b0274b51c51b Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 04:26:54 +0200
Subject: [PATCH 0202/1170] Add support for adding/updating package entries

Add flags parameter to BPackageWriter::Init() (and the private
implementation classes) to indicate that an existing package file shall
be updated instead of created. Currently that always happens in-place.
---
 headers/os/package/hpkg/HPKGDefs.h            |  11 +
 headers/os/package/hpkg/PackageWriter.h       |   2 +-
 .../private/package/hpkg/PackageWriterImpl.h  |  29 +-
 headers/private/package/hpkg/WriterImplBase.h |  12 +-
 src/kits/package/hpkg/PackageWriter.cpp       |   4 +-
 src/kits/package/hpkg/PackageWriterImpl.cpp   | 858 +++++++++++++++++-
 .../package/hpkg/RepositoryWriterImpl.cpp     |   2 +-
 src/kits/package/hpkg/WriterImplBase.cpp      |  17 +-
 8 files changed, 881 insertions(+), 54 deletions(-)

diff --git a/headers/os/package/hpkg/HPKGDefs.h b/headers/os/package/hpkg/HPKGDefs.h
index 094b90bcf8..af83bf3cce 100644
--- a/headers/os/package/hpkg/HPKGDefs.h
+++ b/headers/os/package/hpkg/HPKGDefs.h
@@ -157,6 +157,17 @@ enum {
 };
 
 
+// Writer Init() flags
+enum {
+	B_HPKG_WRITER_UPDATE_PACKAGE	= 0x01,
+		// update the package (don't truncate)
+	B_HPKG_WRITER_FORCE_ADD			= 0x02,
+		// when updating a pre-existing entry, don't fail, but replace the
+		// entry, if possible (directories will be merged, but won't replace a
+		// non-directory)
+};
+
+
 }	// namespace BHPKG
 
 }	// namespace BPackageKit
diff --git a/headers/os/package/hpkg/PackageWriter.h b/headers/os/package/hpkg/PackageWriter.h
index 7ab04a5d5e..92e3ce1b55 100644
--- a/headers/os/package/hpkg/PackageWriter.h
+++ b/headers/os/package/hpkg/PackageWriter.h
@@ -47,7 +47,7 @@ public:
 									BPackageWriterListener* listener);
 								~BPackageWriter();
 
-			status_t			Init(const char* fileName);
+			status_t			Init(const char* fileName, uint32 flags = 0);
 			status_t			AddEntry(const char* fileName, int fd = -1);
 			status_t			Finish();
 
diff --git a/headers/private/package/hpkg/PackageWriterImpl.h b/headers/private/package/hpkg/PackageWriterImpl.h
index d913bc4167..4e06a38270 100644
--- a/headers/private/package/hpkg/PackageWriterImpl.h
+++ b/headers/private/package/hpkg/PackageWriterImpl.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
  * Copyright 2011, Oliver Tappe 
  * Distributed under the terms of the MIT License.
  */
@@ -15,6 +15,11 @@
 #include 
 
 
+namespace BPrivate {
+	template class RangeArray;
+}
+
+
 namespace BPackageKit {
 
 namespace BHPKG {
@@ -37,19 +42,21 @@ public:
 									BPackageWriterListener* listener);
 								~PackageWriterImpl();
 
-			status_t			Init(const char* fileName);
+			status_t			Init(const char* fileName, uint32 flags);
 			status_t			AddEntry(const char* fileName, int fd = -1);
 			status_t			Finish();
 
 private:
 			struct Attribute;
+			struct PackageContentHandler;
 			struct Entry;
 			struct SubPathAdder;
+			struct HeapAttributeOffsetter;
 
 			typedef DoublyLinkedList EntryList;
 
 private:
-			status_t			_Init(const char* fileName);
+			status_t			_Init(const char* fileName, uint32 flags);
 			status_t			_Finish();
 
 			status_t			_RegisterEntry(const char* fileName, int fd);
@@ -58,6 +65,18 @@ private:
 									bool isImplicit);
 
 			status_t			_CheckLicenses();
+			bool				_IsEntryInPackage(const char* fileName);
+
+			void				_UpdateReadPackageInfo();
+			void				_UpdateCheckEntryCollisions();
+			void				_UpdateCheckEntryCollisions(
+									Attribute* parentAttribute, int dirFD,
+									Entry* entry, const char* fileName,
+									char* pathBuffer);
+			void				_CompactHeap();
+			void				_MoveHeapChunk(off_t fromOffset, off_t toOffset,
+									off_t size);
+			void				_AttributeRemoved(Attribute* attribute);
 
 			void				_WriteTOC(hpkg_header& header);
 			int32				_WriteTOCSections(uint64& _stringsSize,
@@ -74,6 +93,8 @@ private:
 
 			void				_AddEntry(int dirFD, Entry* entry,
 									const char* fileName, char* pathBuffer);
+			void				_AddDirectoryChildren(Entry* entry, int fd,
+									char* pathBuffer);
 
 			Attribute*			_AddAttribute(BHPKGAttributeID attributeID,
 									const AttributeValue& value);
@@ -105,6 +126,8 @@ private:
 			off_t				fHeapOffset;
 			off_t				fHeapEnd;
 
+			::BPrivate::RangeArray* fHeapRangesToRemove;
+
 			void*				fDataBuffer;
 			const size_t		fDataBufferSize;
 
diff --git a/headers/private/package/hpkg/WriterImplBase.h b/headers/private/package/hpkg/WriterImplBase.h
index 8108624543..54858bf7b5 100644
--- a/headers/private/package/hpkg/WriterImplBase.h
+++ b/headers/private/package/hpkg/WriterImplBase.h
@@ -147,7 +147,8 @@ protected:
 			typedef DoublyLinkedList PackageAttributeList;
 
 protected:
-			status_t			Init(const char* fileName, const char* type);
+			status_t			Init(const char* fileName, const char* type,
+									uint32 flags);
 
 			void				RegisterPackageInfo(
 									PackageAttributeList& attributeList,
@@ -188,6 +189,7 @@ protected:
 									off_t offset);
 
 	inline	int					FD() const;
+	inline	uint32				Flags() const;
 
 	inline	const PackageAttributeList&	PackageAttributes() const;
 	inline	PackageAttributeList&	PackageAttributes();
@@ -211,6 +213,7 @@ private:
 private:
 			BErrorOutput*		fErrorOutput;
 			const char*			fFileName;
+			uint32				fFlags;
 			int					fFD;
 			bool				fFinished;
 
@@ -266,6 +269,13 @@ WriterImplBase::FD() const
 }
 
 
+inline uint32
+WriterImplBase::Flags() const
+{
+	return fFlags;
+}
+
+
 inline WriterImplBase::AbstractDataWriter*
 WriterImplBase::DataWriter() const
 {
diff --git a/src/kits/package/hpkg/PackageWriter.cpp b/src/kits/package/hpkg/PackageWriter.cpp
index 1966b5a84f..67304d0dcc 100644
--- a/src/kits/package/hpkg/PackageWriter.cpp
+++ b/src/kits/package/hpkg/PackageWriter.cpp
@@ -30,12 +30,12 @@ BPackageWriter::~BPackageWriter()
 
 
 status_t
-BPackageWriter::Init(const char* fileName)
+BPackageWriter::Init(const char* fileName, uint32 flags)
 {
 	if (fImpl == NULL)
 		return B_NO_MEMORY;
 
-	return fImpl->Init(fileName);
+	return fImpl->Init(fileName, flags);
 }
 
 
diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 48c21868cf..de7564e2e8 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -26,12 +26,21 @@
 #include 
 #include 
 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
 #include 
+#include 
 
 #include 
 
 #include 
 #include 
+#include 
 #include 
 
 
@@ -79,11 +88,175 @@ struct PackageWriterImpl::Attribute
 		children.Add(child);
 	}
 
+	void RemoveChild(Attribute* child)
+	{
+		children.Remove(child);
+	}
+
 	void DeleteChildren()
 	{
 		while (Attribute* child = children.RemoveHead())
 			delete child;
 	}
+
+	Attribute* FindEntryChild(const char* fileName) const
+	{
+		for (DoublyLinkedList::ConstIterator it
+				= children.GetIterator(); Attribute* child = it.Next();) {
+			if (child->id != B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY)
+				continue;
+			if (child->value.type != B_HPKG_ATTRIBUTE_TYPE_STRING)
+				continue;
+			const char* childName = child->value.string->string;
+			if (strcmp(fileName, childName) == 0)
+				return child;
+		}
+
+		return NULL;
+	}
+
+	Attribute* FindEntryChild(const char* fileName, size_t nameLength) const
+	{
+		BString name(fileName, nameLength);
+		return (size_t)name.Length() == nameLength
+			? FindEntryChild(name) : NULL;
+	}
+
+	Attribute* FindNodeAttributeChild(const char* attributeName) const
+	{
+		for (DoublyLinkedList::ConstIterator it
+				= children.GetIterator(); Attribute* child = it.Next();) {
+			if (child->id != B_HPKG_ATTRIBUTE_ID_FILE_ATTRIBUTE)
+				continue;
+			if (child->value.type != B_HPKG_ATTRIBUTE_TYPE_STRING)
+				continue;
+			const char* childName = child->value.string->string;
+			if (strcmp(attributeName, childName) == 0)
+				return child;
+		}
+
+		return NULL;
+	}
+
+	Attribute* ChildWithID(BHPKGAttributeID id) const
+	{
+		for (DoublyLinkedList::ConstIterator it
+				= children.GetIterator(); Attribute* child = it.Next();) {
+			if (child->id == id)
+				return child;
+		}
+
+		return NULL;
+	}
+};
+
+
+// #pragma mark - PackageContentHandler
+
+
+struct PackageWriterImpl::PackageContentHandler
+	: BLowLevelPackageContentHandler {
+	PackageContentHandler(Attribute* rootAttribute, BErrorOutput* errorOutput,
+		StringCache& stringCache, uint64 heapOffset)
+		:
+		fErrorOutput(errorOutput),
+		fStringCache(stringCache),
+		fRootAttribute(rootAttribute),
+		fHeapOffset(heapOffset),
+		fErrorOccurred(false)
+	{
+	}
+
+static const char* AttributeNameForID(uint8 id)
+{
+	return BLowLevelPackageContentHandler::AttributeNameForID(id);
+}
+
+	virtual status_t HandleSectionStart(BHPKGPackageSectionID sectionID,
+		bool& _handleSection)
+	{
+		// we're only interested in the TOC
+		_handleSection = sectionID == B_HPKG_SECTION_PACKAGE_TOC;
+		return B_OK;
+	}
+
+	virtual status_t HandleSectionEnd(BHPKGPackageSectionID sectionID)
+	{
+		return B_OK;
+	}
+
+	virtual status_t HandleAttribute(BHPKGAttributeID attributeID,
+		const BPackageAttributeValue& value, void* parentToken, void*& _token)
+	{
+		if (fErrorOccurred)
+			return B_OK;
+
+		Attribute* parentAttribute = parentToken != NULL
+			? (Attribute*)parentToken : fRootAttribute;
+
+		Attribute* attribute = new Attribute(attributeID);
+		parentAttribute->AddChild(attribute);
+
+		switch (value.type) {
+			case B_HPKG_ATTRIBUTE_TYPE_INT:
+				attribute->value.SetTo(value.signedInt);
+				break;
+
+			case B_HPKG_ATTRIBUTE_TYPE_UINT:
+				attribute->value.SetTo(value.unsignedInt);
+				break;
+
+			case B_HPKG_ATTRIBUTE_TYPE_STRING:
+			{
+				CachedString* string = fStringCache.Get(value.string);
+				if (string == NULL)
+					throw std::bad_alloc();
+				attribute->value.SetTo(string);
+				break;
+			}
+
+			case B_HPKG_ATTRIBUTE_TYPE_RAW:
+				if (value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) {
+					attribute->value.SetToData(value.data.size,
+						value.data.offset - fHeapOffset);
+				} else if (value.encoding
+						== B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) {
+					attribute->value.SetToData(value.data.size, value.data.raw);
+				} else {
+					fErrorOutput->PrintError("Invalid attribute value encoding "
+						"%d (attribute %d)\n", value.encoding, attributeID);
+					return B_BAD_DATA;
+				}
+				break;
+
+			case B_HPKG_ATTRIBUTE_TYPE_INVALID:
+			default:
+				fErrorOutput->PrintError("Invalid attribute value type %d "
+					"(attribute %d)\n", value.type, attributeID);
+				return B_BAD_DATA;
+		}
+
+		_token = attribute;
+		return B_OK;
+	}
+
+	virtual status_t HandleAttributeDone(BHPKGAttributeID attributeID,
+		const BPackageAttributeValue& value, void* parentToken, void* token)
+	{
+		return B_OK;
+	}
+
+	virtual void HandleErrorOccurred()
+	{
+		fErrorOccurred = true;
+	}
+
+private:
+	BErrorOutput*	fErrorOutput;
+	StringCache&	fStringCache;
+	Attribute*		fRootAttribute;
+	uint64			fHeapOffset;
+	bool			fErrorOccurred;
 };
 
 
@@ -223,6 +396,40 @@ private:
 };
 
 
+struct PackageWriterImpl::HeapAttributeOffsetter {
+	HeapAttributeOffsetter(const RangeArray& ranges,
+		const Array& deltas)
+		:
+		fRanges(ranges),
+		fDeltas(deltas)
+	{
+	}
+
+	void ProcessAttribute(Attribute* attribute)
+	{
+		// If the attribute refers to a heap value, adjust it
+		AttributeValue& value = attribute->value;
+
+		if (value.type == B_HPKG_ATTRIBUTE_TYPE_RAW
+			&& value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) {
+			off_t delta = fDeltas[fRanges.InsertionIndex(value.data.offset)];
+			value.data.offset -= delta;
+		}
+
+		// recurse
+		for (DoublyLinkedList::Iterator it
+					= attribute->children.GetIterator();
+				Attribute* child = it.Next();) {
+			ProcessAttribute(child);
+		}
+	}
+
+private:
+	const RangeArray&	fRanges;
+	const Array&			fDeltas;
+};
+
+
 // #pragma mark - PackageWriterImpl (Inline Methods)
 
 
@@ -243,6 +450,7 @@ PackageWriterImpl::PackageWriterImpl(BPackageWriterListener* listener)
 	:
 	inherited(listener),
 	fListener(listener),
+	fHeapRangesToRemove(NULL),
 	fDataBuffer(NULL),
 	fDataBufferSize(2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB),
 	fRootEntry(NULL),
@@ -263,10 +471,10 @@ PackageWriterImpl::~PackageWriterImpl()
 
 
 status_t
-PackageWriterImpl::Init(const char* fileName)
+PackageWriterImpl::Init(const char* fileName, uint32 flags)
 {
 	try {
-		return _Init(fileName);
+		return _Init(fileName, flags);
 	} catch (status_t error) {
 		return error;
 	} catch (std::bad_alloc) {
@@ -343,6 +551,16 @@ status_t
 PackageWriterImpl::Finish()
 {
 	try {
+		RangeArray heapRangesToRemove;
+		fHeapRangesToRemove = &heapRangesToRemove;
+
+		if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0) {
+			_UpdateCheckEntryCollisions();
+
+			if (fPackageInfo.InitCheck() != B_OK)
+				_UpdateReadPackageInfo();
+		}
+
 		if (fPackageInfo.InitCheck() != B_OK) {
 			fListener->PrintError("No package-info file found (%s)!\n",
 				B_HPKG_PACKAGE_INFO_FILE_NAME);
@@ -355,6 +573,11 @@ PackageWriterImpl::Finish()
 		if (result != B_OK)
 			return result;
 
+		if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0)
+			_CompactHeap();
+
+		fHeapRangesToRemove = NULL;
+
 		return _Finish();
 	} catch (status_t error) {
 		return error;
@@ -366,9 +589,9 @@ PackageWriterImpl::Finish()
 
 
 status_t
-PackageWriterImpl::_Init(const char* fileName)
+PackageWriterImpl::_Init(const char* fileName, uint32 flags)
 {
-	status_t result = inherited::Init(fileName, "package");
+	status_t result = inherited::Init(fileName, "package", flags);
 	if (result != B_OK)
 		return result;
 
@@ -388,6 +611,29 @@ PackageWriterImpl::_Init(const char* fileName)
 	fHeapOffset = fHeapEnd = sizeof(hpkg_header);
 	fTopAttribute = fRootAttribute;
 
+	// in update mode, parse the TOC
+	if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0) {
+		PackageReaderImpl packageReader(fListener);
+		result = packageReader.Init(FD(), false);
+		if (result != B_OK)
+			return result;
+
+		fHeapOffset = packageReader.HeapOffset();
+		fHeapEnd = fHeapOffset + packageReader.HeapSize();
+
+		PackageContentHandler handler(fRootAttribute, fListener, fStringCache,
+			fHeapOffset);
+
+		result = packageReader.ParseContent(&handler);
+		if (result != B_OK)
+			return result;
+
+		if ((uint64)fHeapOffset > packageReader.HeapOffset()) {
+			fListener->PrintError("Unexpected heap offset in package file.\n");
+			return B_BAD_DATA;
+		}
+	}
+
 	return B_OK;
 }
 
@@ -412,7 +658,6 @@ PackageWriterImpl::_CheckLicenses()
 	}
 
 	BDirectory systemLicenseDir(systemLicensePath.Path());
-	BDirectory packageLicenseDir("./data/licenses");
 
 	const BObjectList& licenseList = fPackageInfo.LicenseList();
 	for (int i = 0; i < licenseList.CountItems(); ++i) {
@@ -425,8 +670,10 @@ PackageWriterImpl::_CheckLicenses()
 			continue;
 
 		// license is not a system license, so it must be contained in package
-		if (packageLicenseDir.FindEntry(licenseName.String(),
-				&license) != B_OK) {
+		BString licensePath("data/licenses/");
+		licensePath << licenseName;
+
+		if (!_IsEntryInPackage(licensePath)) {
 			fListener->PrintError("License '%s' isn't contained in package!\n",
 				licenseName.String());
 			return B_BAD_DATA;
@@ -437,6 +684,507 @@ PackageWriterImpl::_CheckLicenses()
 }
 
 
+bool
+PackageWriterImpl::_IsEntryInPackage(const char* fileName)
+{
+	const char* originalFileName = fileName;
+
+	// find the closest ancestor of the entry that is in the added entries
+	bool added = false;
+	Entry* entry = fRootEntry;
+	while (entry != NULL) {
+		if (!entry->IsImplicit()) {
+			added = true;
+			break;
+		}
+
+		if (*fileName == '\0')
+			break;
+
+		const char* nextSlash = strchr(fileName, '/');
+
+		if (nextSlash == NULL) {
+			// no slash, just the file name
+			size_t length = strlen(fileName);
+			entry  = entry->GetChild(fileName, length);
+			fileName += length;
+			continue;
+		}
+
+		// find the start of the next component, skipping slashes
+		const char* nextComponent = nextSlash + 1;
+		while (*nextComponent == '/')
+			nextComponent++;
+
+		entry = entry->GetChild(fileName, nextSlash - fileName);
+
+		fileName = nextComponent;
+	}
+
+	if (added) {
+		// the entry itself or one of its ancestors has been added to the
+		// package explicitly -- stat it, to see, if it exists
+		struct stat st;
+		if (entry->FD() >= 0) {
+			if (fstatat(entry->FD(), *fileName != '\0' ? fileName : NULL, &st,
+					AT_SYMLINK_NOFOLLOW) == 0) {
+				return true;
+			}
+		} else {
+			if (lstat(originalFileName, &st) == 0)
+				return true;
+		}
+	}
+
+	// In update mode the entry might already be in the package.
+	Attribute* attribute = fRootAttribute;
+	fileName = originalFileName;
+
+	while (attribute != NULL) {
+		if (*fileName == '\0')
+			return true;
+
+		const char* nextSlash = strchr(fileName, '/');
+
+		if (nextSlash == NULL) {
+			// no slash, just the file name
+			return attribute->FindEntryChild(fileName) != NULL;
+		}
+
+		// find the start of the next component, skipping slashes
+		const char* nextComponent = nextSlash + 1;
+		while (*nextComponent == '/')
+			nextComponent++;
+
+		attribute = attribute->FindEntryChild(fileName, nextSlash - fileName);
+
+		fileName = nextComponent;
+	}
+
+	return false;
+}
+
+
+void
+PackageWriterImpl::_UpdateReadPackageInfo()
+{
+	// get the .PackageInfo entry attribute
+	Attribute* attribute = fRootAttribute->FindEntryChild(
+		B_HPKG_PACKAGE_INFO_FILE_NAME);
+	if (attribute == NULL) {
+		fListener->PrintError("No %s in package file.\n",
+			B_HPKG_PACKAGE_INFO_FILE_NAME);
+		throw status_t(B_BAD_DATA);
+	}
+
+	// get the data attribute
+	Attribute* dataAttribute = attribute->ChildWithID(B_HPKG_ATTRIBUTE_ID_DATA);
+	if (dataAttribute == NULL)  {
+		fListener->PrintError("%s entry in package file doesn't have data.\n",
+			B_HPKG_PACKAGE_INFO_FILE_NAME);
+		throw status_t(B_BAD_DATA);
+	}
+
+	AttributeValue& value = dataAttribute->value;
+	if (value.type != B_HPKG_ATTRIBUTE_TYPE_RAW) {
+		fListener->PrintError("%s entry in package file has an invalid data "
+			"attribute (not of type raw).\n", B_HPKG_PACKAGE_INFO_FILE_NAME);
+		throw status_t(B_BAD_DATA);
+	}
+
+	BPackageData data;
+	if (value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE)
+		data.SetData(value.data.size, value.data.raw);
+	else
+		data.SetData(value.data.size, value.data.offset + fHeapOffset);
+
+	// get the compression
+	uint8 compression = B_HPKG_DEFAULT_DATA_COMPRESSION;
+	if (Attribute* compressionAttribute = dataAttribute->ChildWithID(
+			B_HPKG_ATTRIBUTE_ID_DATA_COMPRESSION)) {
+		if (compressionAttribute->value.type != B_HPKG_ATTRIBUTE_TYPE_UINT) {
+			fListener->PrintError("%s entry in package file has an invalid "
+				"data compression attribute (not of type uint).\n",
+				B_HPKG_PACKAGE_INFO_FILE_NAME);
+			throw status_t(B_BAD_DATA);
+		}
+		compression = compressionAttribute->value.unsignedInt;
+	}
+
+	data.SetCompression(compression);
+
+	// get the size
+	uint64 size;
+	Attribute* sizeAttribute = dataAttribute->ChildWithID(
+		B_HPKG_ATTRIBUTE_ID_DATA_SIZE);
+	if (sizeAttribute == NULL) {
+		size = value.data.size;
+	} else if (sizeAttribute->value.type != B_HPKG_ATTRIBUTE_TYPE_UINT) {
+		fListener->PrintError("%s entry in package file has an invalid data "
+			"size attribute (not of type uint).\n",
+			B_HPKG_PACKAGE_INFO_FILE_NAME);
+		throw status_t(B_BAD_DATA);
+	} else
+		size = sizeAttribute->value.unsignedInt;
+
+	data.SetUncompressedSize(size);
+
+	// get the chunk size
+	uint64 chunkSize = compression == B_HPKG_COMPRESSION_ZLIB
+		? B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB : 0;
+	if (Attribute* chunkSizeAttribute = dataAttribute->ChildWithID(
+			B_HPKG_ATTRIBUTE_ID_DATA_CHUNK_SIZE)) {
+		if (chunkSizeAttribute->value.type != B_HPKG_ATTRIBUTE_TYPE_UINT) {
+			fListener->PrintError("%s entry in package file has an invalid "
+				"data chunk size attribute (not of type uint).\n",
+				B_HPKG_PACKAGE_INFO_FILE_NAME);
+			throw status_t(B_BAD_DATA);
+		}
+		chunkSize = chunkSizeAttribute->value.unsignedInt;
+	}
+
+	data.SetChunkSize(chunkSize);
+
+	// read the value into a string
+	BString valueString;
+	char* valueBuffer = valueString.LockBuffer(size);
+	if (valueBuffer == NULL)
+		throw std::bad_alloc();
+
+	if (value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_INLINE) {
+		// data encoded inline -- just copy to buffer
+		if (size != value.data.size) {
+			fListener->PrintError("%s entry in package file has an invalid "
+				"data attribute (mismatching size).\n",
+				B_HPKG_PACKAGE_INFO_FILE_NAME);
+			throw status_t(B_BAD_DATA);
+		}
+		memcpy(valueBuffer, value.data.raw, value.data.size);
+	} else {
+		// data on heap -- read from there
+		BBlockBufferCacheNoLock	bufferCache(16 * 1024, 1);
+		status_t error = bufferCache.Init();
+		if (error != B_OK) {
+			fListener->PrintError("Failed to initialize buffer cache: %s\n",
+				strerror(error));
+			throw status_t(error);
+		}
+
+		// create a BPackageDataReader
+		BFDDataReader packageFileReader(FD());
+		BPackageDataReader* reader;
+		error = BPackageDataReaderFactory(&bufferCache)
+			.CreatePackageDataReader(&packageFileReader, data, reader);
+		if (error != B_OK) {
+			fListener->PrintError("Failed to create package data reader: %s\n",
+				strerror(error));
+			throw status_t(error);
+		}
+		ObjectDeleter readerDeleter(reader);
+
+		// read the data
+		error = reader->ReadData(0, valueBuffer, size);
+		if (error != B_OK) {
+			fListener->PrintError("Failed to read data of %s entry in package "
+				"file: %s\n", B_HPKG_PACKAGE_INFO_FILE_NAME, strerror(error));
+			throw status_t(error);
+		}
+	}
+
+	valueString.UnlockBuffer();
+
+	// parse the package info
+	status_t error = fPackageInfo.ReadFromConfigString(valueString);
+	if (error != B_OK) {
+		fListener->PrintError("Failed to parse package info data from package "
+			"file: %s\n", strerror(error));
+		throw status_t(error);
+	}
+}
+
+
+void
+PackageWriterImpl::_UpdateCheckEntryCollisions()
+{
+	for (EntryList::ConstIterator it = fRootEntry->ChildIterator();
+			Entry* entry = it.Next();) {
+		char pathBuffer[B_PATH_NAME_LENGTH];
+		pathBuffer[0] = '\0';
+		_UpdateCheckEntryCollisions(fRootAttribute, AT_FDCWD, entry,
+			entry->Name(), pathBuffer);
+	}
+}
+
+
+void
+PackageWriterImpl::_UpdateCheckEntryCollisions(Attribute* parentAttribute,
+	int dirFD, Entry* entry, const char* fileName, char* pathBuffer)
+{
+	bool isImplicitEntry = entry != NULL && entry->IsImplicit();
+
+	SubPathAdder pathAdder(fListener, pathBuffer, fileName);
+
+	// Check wether there's an entry attribute for this entry. If not, we can
+	// ignore this entry.
+	Attribute* entryAttribute = parentAttribute->FindEntryChild(fileName);
+	if (entryAttribute == NULL)
+		return;
+
+	// open the node
+	int fd;
+	FileDescriptorCloser fdCloser;
+
+	if (entry != NULL && entry->FD() >= 0) {
+		// a file descriptor is already given -- use that
+		fd = entry->FD();
+	} else {
+		fd = openat(dirFD, fileName,
+			O_RDONLY | (isImplicitEntry ? 0 : O_NOTRAVERSE));
+		if (fd < 0) {
+			fListener->PrintError("Failed to open entry \"%s\": %s\n",
+				pathBuffer, strerror(errno));
+			throw status_t(errno);
+		}
+		fdCloser.SetTo(fd);
+	}
+
+	// stat the node
+	struct stat st;
+	if (fstat(fd, &st) < 0) {
+		fListener->PrintError("Failed to fstat() file \"%s\": %s\n", pathBuffer,
+			strerror(errno));
+		throw status_t(errno);
+	}
+
+	// implicit entries must be directories
+	if (isImplicitEntry && !S_ISDIR(st.st_mode)) {
+		fListener->PrintError("Non-leaf path component \"%s\" is not a "
+			"directory.\n", pathBuffer);
+		throw status_t(B_BAD_VALUE);
+	}
+
+	// get the pre-existing node's file type
+	uint32 preExistingFileType = B_HPKG_DEFAULT_FILE_TYPE;
+	if (Attribute* fileTypeAttribute
+			= entryAttribute->ChildWithID(B_HPKG_ATTRIBUTE_ID_FILE_TYPE)) {
+		if (fileTypeAttribute->value.type == B_HPKG_ATTRIBUTE_TYPE_UINT)
+			preExistingFileType = fileTypeAttribute->value.unsignedInt;
+	}
+
+	// Compare the node type with that of the pre-existing one.
+	if (!S_ISDIR(st.st_mode)) {
+		// the pre-existing must not a directory either -- we'll remove it
+		if (preExistingFileType == B_HPKG_FILE_TYPE_DIRECTORY) {
+			fListener->PrintError("Specified file \"%s\" clashes with an "
+				"archived directory.\n", pathBuffer);
+			throw status_t(B_BAD_VALUE);
+		}
+
+		if ((Flags() & B_HPKG_WRITER_FORCE_ADD) == 0) {
+			fListener->PrintError("Specified file \"%s\" clashes with an "
+				"archived file.\n", pathBuffer);
+			throw status_t(B_FILE_EXISTS);
+		}
+
+		parentAttribute->RemoveChild(entryAttribute);
+		_AttributeRemoved(entryAttribute);
+
+		return;
+	}
+
+	// the pre-existing entry needs to be a directory too -- we will merge
+	if (preExistingFileType != B_HPKG_FILE_TYPE_DIRECTORY) {
+		fListener->PrintError("Specified directory \"%s\" clashes with an "
+			"archived non-directory.\n", pathBuffer);
+		throw status_t(B_BAD_VALUE);
+	}
+
+	// directory -- recursively add children
+	if (isImplicitEntry) {
+		// this is an implicit entry -- just check the child entries
+		for (EntryList::ConstIterator it = entry->ChildIterator();
+				Entry* child = it.Next();) {
+			_UpdateCheckEntryCollisions(entryAttribute, fd, child,
+				child->Name(), pathBuffer);
+		}
+	} else {
+		// explicitly specified directory -- we need to read the directory
+
+		// first we check for colliding node attributes, though
+		if (DIR* attrDir = fs_fopen_attr_dir(fd)) {
+			CObjectDeleter attrDirCloser(attrDir, fs_close_attr_dir);
+
+			while (dirent* entry = fs_read_attr_dir(attrDir)) {
+				attr_info attrInfo;
+				if (fs_stat_attr(fd, entry->d_name, &attrInfo) < 0) {
+					fListener->PrintError(
+						"Failed to stat attribute \"%s\" of directory \"%s\": "
+						"%s\n", entry->d_name, pathBuffer, strerror(errno));
+					throw status_t(errno);
+				}
+
+				// check whether the attribute exists
+				Attribute* attributeAttribute
+					= entryAttribute->FindNodeAttributeChild(entry->d_name);
+				if (attributeAttribute == NULL)
+					continue;
+
+				if ((Flags() & B_HPKG_WRITER_FORCE_ADD) == 0) {
+					fListener->PrintError("Attribute \"%s\" of specified "
+						"directory \"%s\" clashes with an archived "
+						"attribute.\n", pathBuffer);
+					throw status_t(B_FILE_EXISTS);
+				}
+
+				// remove it
+				entryAttribute->RemoveChild(attributeAttribute);
+				_AttributeRemoved(attributeAttribute);
+			}
+		}
+
+		// we need to clone the directory FD for fdopendir()
+		int clonedFD = dup(fd);
+		if (clonedFD < 0) {
+			fListener->PrintError(
+				"Failed to dup() directory FD: %s\n", strerror(errno));
+			throw status_t(errno);
+		}
+
+		DIR* dir = fdopendir(clonedFD);
+		if (dir == NULL) {
+			fListener->PrintError(
+				"Failed to open directory \"%s\": %s\n", pathBuffer,
+				strerror(errno));
+			close(clonedFD);
+			throw status_t(errno);
+		}
+		CObjectDeleter dirCloser(dir, closedir);
+
+		while (dirent* entry = readdir(dir)) {
+			// skip "." and ".."
+			if (strcmp(entry->d_name, ".") == 0
+				|| strcmp(entry->d_name, "..") == 0) {
+				continue;
+			}
+
+			_AddEntry(fd, NULL, entry->d_name, pathBuffer);
+			_UpdateCheckEntryCollisions(entryAttribute, fd, NULL, entry->d_name,
+				pathBuffer);
+		}
+	}
+}
+
+
+void
+PackageWriterImpl::_CompactHeap()
+{
+	int32 count = fHeapRangesToRemove->CountRanges();
+	if (count == 0)
+		return;
+
+	// compute the move deltas for the ranges
+	Array deltas;
+	off_t delta = 0;
+	for (int32 i = 0; i < count; i++) {
+		if (!deltas.Add(delta))
+			throw std::bad_alloc();
+
+		delta += fHeapRangesToRemove->RangeAt(i).size;
+	}
+
+	if (!deltas.Add(delta))
+		throw std::bad_alloc();
+
+	// offset the attributes
+	HeapAttributeOffsetter(*fHeapRangesToRemove, deltas).ProcessAttribute(
+		fRootAttribute);
+
+	// move the heap chunks in the file around
+	off_t chunkOffset = fHeapOffset;
+	delta = 0;
+
+	for (int32 i = 0; i < count; i++) {
+		const Range& range = fHeapRangesToRemove->RangeAt(i);
+
+		if (delta > 0 && chunkOffset < range.offset) {
+			// move chunk
+			_MoveHeapChunk(chunkOffset, chunkOffset - delta,
+				range.offset - chunkOffset);
+		}
+
+		chunkOffset = range.EndOffset();
+		delta += range.size;
+	}
+
+	// move the final chunk
+	if (delta > 0 && chunkOffset < fHeapEnd) {
+		_MoveHeapChunk(chunkOffset, chunkOffset - delta,
+			fHeapEnd - chunkOffset);
+	}
+
+	fHeapEnd -= delta;
+}
+
+
+void
+PackageWriterImpl::_MoveHeapChunk(off_t fromOffset, off_t toOffset, off_t size)
+{
+	// convert heap offsets to file offsets
+	fromOffset += fHeapOffset;
+	toOffset += fHeapOffset;
+
+	while (size > 0) {
+		size_t toCopy = std::min(size, (off_t)fDataBufferSize);
+
+		// read data into buffer
+		ssize_t bytesRead = read_pos(FD(), fromOffset, fDataBuffer, toCopy);
+		if (bytesRead < 0) {
+			fListener->PrintError("Failed to read from package file: %s\n",
+				strerror(errno));
+			throw status_t(errno);
+		}
+		if ((size_t)bytesRead < toCopy) {
+			fListener->PrintError("Failed to read from package file.\n");
+			throw status_t(B_IO_ERROR);
+		}
+
+		// write data to target offset
+		ssize_t bytesWritten = write_pos(FD(), toOffset, fDataBuffer, toCopy);
+		if (bytesWritten < 0) {
+			fListener->PrintError("Failed to write to package file: %s\n",
+				strerror(errno));
+			throw status_t(errno);
+		}
+		if ((size_t)bytesWritten < toCopy) {
+			fListener->PrintError("Failed to write to package file.\n");
+			throw status_t(B_IO_ERROR);
+		}
+
+		fromOffset += toCopy;
+		toOffset += toCopy;
+		size -= toCopy;
+	}
+}
+
+
+void
+PackageWriterImpl::_AttributeRemoved(Attribute* attribute)
+{
+	AttributeValue& value = attribute->value;
+	if (value.type == B_HPKG_ATTRIBUTE_TYPE_RAW
+		&& value.encoding == B_HPKG_ATTRIBUTE_ENCODING_RAW_HEAP) {
+		if (!fHeapRangesToRemove->AddRange(value.data.offset, value.data.size))
+			throw std::bad_alloc();
+	}
+
+	for (DoublyLinkedList::Iterator it
+				= attribute->children.GetIterator();
+			Attribute* child = it.Next();) {
+		_AttributeRemoved(child);
+	}
+}
+
+
 status_t
 PackageWriterImpl::_Finish()
 {
@@ -458,6 +1206,16 @@ PackageWriterImpl::_Finish()
 
 	off_t totalSize = fHeapEnd;
 
+	// Truncate the file to the size it is supposed to have. In update mode, it
+	// can be greater when one or more files are shrunk. In creation mode, when
+	// writing compressed TOC or package attributes yields a larger size than
+	// uncompressed, the file size may also be greater than it should be.
+	if (ftruncate(FD(), totalSize) != 0) {
+		fListener->PrintError("Failed to truncate package file to new "
+			"size: %s\n", strerror(errno));
+		return errno;
+	}
+
 	fListener->OnPackageSizeInfo(fHeapOffset, heapSize,
 		B_BENDIAN_TO_HOST_INT64(header.toc_length_compressed),
 		B_BENDIAN_TO_HOST_INT32(header.attributes_length_compressed),
@@ -761,6 +1519,18 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 		throw status_t(B_BAD_VALUE);
 	}
 
+	// In update mode we don't need to add an entry attribute for an implicit
+	// directory, if there already is one.
+	if (isImplicitEntry && (Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0) {
+		Attribute* entryAttribute = fTopAttribute->FindEntryChild(fileName);
+		if (entryAttribute != NULL) {
+			Stacker entryAttributeStacker(fTopAttribute,
+				entryAttribute);
+			_AddDirectoryChildren(entry, fd, pathBuffer);
+			return;
+		}
+	}
+
 	// check/translate the node type
 	uint8 fileType;
 	uint32 defaultPermissions;
@@ -856,42 +1626,48 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 		}
 	}
 
-	if (S_ISDIR(st.st_mode)) {
-		// directory -- recursively add children
-		if (isImplicitEntry) {
-			// this is an implicit entry -- just add it's children
-			for (EntryList::ConstIterator it = entry->ChildIterator();
-					Entry* child = it.Next();) {
-				_AddEntry(fd, child, child->Name(), pathBuffer);
-			}
-		} else {
-			// we need to clone the directory FD for fdopendir()
-			int clonedFD = dup(fd);
-			if (clonedFD < 0) {
-				fListener->PrintError(
-					"Failed to dup() directory FD: %s\n", strerror(errno));
-				throw status_t(errno);
+	if (S_ISDIR(st.st_mode))
+		_AddDirectoryChildren(entry, fd, pathBuffer);
+}
+
+
+void
+PackageWriterImpl::_AddDirectoryChildren(Entry* entry, int fd, char* pathBuffer)
+{
+	// directory -- recursively add children
+	if (entry != NULL && entry->IsImplicit()) {
+		// this is an implicit entry -- just add it's children
+		for (EntryList::ConstIterator it = entry->ChildIterator();
+				Entry* child = it.Next();) {
+			_AddEntry(fd, child, child->Name(), pathBuffer);
+		}
+	} else {
+		// we need to clone the directory FD for fdopendir()
+		int clonedFD = dup(fd);
+		if (clonedFD < 0) {
+			fListener->PrintError(
+				"Failed to dup() directory FD: %s\n", strerror(errno));
+			throw status_t(errno);
+		}
+
+		DIR* dir = fdopendir(clonedFD);
+		if (dir == NULL) {
+			fListener->PrintError(
+				"Failed to open directory \"%s\": %s\n", pathBuffer,
+				strerror(errno));
+			close(clonedFD);
+			throw status_t(errno);
+		}
+		CObjectDeleter dirCloser(dir, closedir);
+
+		while (dirent* entry = readdir(dir)) {
+			// skip "." and ".."
+			if (strcmp(entry->d_name, ".") == 0
+				|| strcmp(entry->d_name, "..") == 0) {
+				continue;
 			}
 
-			DIR* dir = fdopendir(clonedFD);
-			if (dir == NULL) {
-				fListener->PrintError(
-					"Failed to open directory \"%s\": %s\n", pathBuffer,
-					strerror(errno));
-				close(clonedFD);
-				throw status_t(errno);
-			}
-			CObjectDeleter dirCloser(dir, closedir);
-
-			while (dirent* entry = readdir(dir)) {
-				// skip "." and ".."
-				if (strcmp(entry->d_name, ".") == 0
-					|| strcmp(entry->d_name, "..") == 0) {
-					continue;
-				}
-
-				_AddEntry(fd, NULL, entry->d_name, pathBuffer);
-			}
+			_AddEntry(fd, NULL, entry->d_name, pathBuffer);
 		}
 	}
 }
diff --git a/src/kits/package/hpkg/RepositoryWriterImpl.cpp b/src/kits/package/hpkg/RepositoryWriterImpl.cpp
index 814a485ab0..3da9e94d9b 100644
--- a/src/kits/package/hpkg/RepositoryWriterImpl.cpp
+++ b/src/kits/package/hpkg/RepositoryWriterImpl.cpp
@@ -328,7 +328,7 @@ RepositoryWriterImpl::Finish()
 status_t
 RepositoryWriterImpl::_Init(const char* fileName)
 {
-	return inherited::Init(fileName, "repository");
+	return inherited::Init(fileName, "repository", 0);
 }
 
 
diff --git a/src/kits/package/hpkg/WriterImplBase.cpp b/src/kits/package/hpkg/WriterImplBase.cpp
index d2b43f3025..74224ff23a 100644
--- a/src/kits/package/hpkg/WriterImplBase.cpp
+++ b/src/kits/package/hpkg/WriterImplBase.cpp
@@ -314,6 +314,7 @@ WriterImplBase::WriterImplBase(BErrorOutput* errorOutput)
 	:
 	fErrorOutput(errorOutput),
 	fFileName(NULL),
+	fFlags(0),
 	fFD(-1),
 	fFinished(false),
 	fDataWriter(NULL)
@@ -326,20 +327,25 @@ WriterImplBase::~WriterImplBase()
 	if (fFD >= 0)
 		close(fFD);
 
-	if (!fFinished && fFileName != NULL)
+	if (!fFinished && fFileName != NULL
+		&& (fFlags & B_HPKG_WRITER_UPDATE_PACKAGE) == 0) {
 		unlink(fFileName);
+	}
 }
 
 
 status_t
-WriterImplBase::Init(const char* fileName, const char* type)
+WriterImplBase::Init(const char* fileName, const char* type, uint32 flags)
 {
 	if (fPackageStringCache.Init() != B_OK)
 		throw std::bad_alloc();
 
-	// open file
-	fFD = open(fileName, O_WRONLY | O_CREAT | O_TRUNC,
-		S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
+	// open file (don't truncate in update mode)
+	int openMode = O_RDWR;
+	if ((flags & B_HPKG_WRITER_UPDATE_PACKAGE) == 0)
+		openMode |= O_CREAT | O_TRUNC;
+
+	fFD = open(fileName, openMode, S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH);
 	if (fFD < 0) {
 		fErrorOutput->PrintError("Failed to open %s file \"%s\": %s\n", type,
 			fileName, strerror(errno));
@@ -347,6 +353,7 @@ WriterImplBase::Init(const char* fileName, const char* type)
 	}
 
 	fFileName = fileName;
+	fFlags = flags;
 
 	return B_OK;
 }

From 1bd38c43184fef526026c8c9d93ded7d1c9ff635 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 04:29:33 +0200
Subject: [PATCH 0203/1170] Move PackageWriterListener to separate file

---
 src/bin/package/Jamfile                   |  1 +
 src/bin/package/PackageWriterListener.cpp | 87 +++++++++++++++++++++++
 src/bin/package/PackageWriterListener.h   | 41 +++++++++++
 src/bin/package/command_create.cpp        | 70 +-----------------
 src/tools/package/Jamfile                 |  1 +
 5 files changed, 131 insertions(+), 69 deletions(-)
 create mode 100644 src/bin/package/PackageWriterListener.cpp
 create mode 100644 src/bin/package/PackageWriterListener.h

diff --git a/src/bin/package/Jamfile b/src/bin/package/Jamfile
index f15ae3f7f3..ec5150666c 100644
--- a/src/bin/package/Jamfile
+++ b/src/bin/package/Jamfile
@@ -8,6 +8,7 @@ BinCommand package :
 	command_extract.cpp
 	command_list.cpp
 	package.cpp
+	PackageWriterListener.cpp
 	StandardErrorOutput.cpp
 
 	:
diff --git a/src/bin/package/PackageWriterListener.cpp b/src/bin/package/PackageWriterListener.cpp
new file mode 100644
index 0000000000..0ab1374955
--- /dev/null
+++ b/src/bin/package/PackageWriterListener.cpp
@@ -0,0 +1,87 @@
+/*
+ * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2011, Oliver Tappe 
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "PackageWriterListener.h"
+
+#include 
+
+
+using BPackageKit::BHPKG::BPackageWriterListener;
+using BPackageKit::BHPKG::BPackageWriter;
+
+
+PackageWriterListener::PackageWriterListener(bool verbose, bool quiet)
+	:
+	fVerbose(verbose), fQuiet(quiet)
+{
+}
+
+
+void
+PackageWriterListener::PrintErrorVarArgs(const char* format, va_list args)
+{
+	vfprintf(stderr, format, args);
+}
+
+
+void
+PackageWriterListener::OnEntryAdded(const char* path)
+{
+	if (fQuiet || !fVerbose)
+		return;
+
+	printf("\t%s\n", path);
+}
+
+
+void
+PackageWriterListener::OnTOCSizeInfo(uint64 uncompressedStringsSize,
+	uint64 uncompressedMainSize, uint64 uncompressedTOCSize)
+{
+	if (fQuiet || !fVerbose)
+		return;
+
+	printf("----- TOC Info -----------------------------------\n");
+	printf("cached strings size:     %10" B_PRIu64 " (uncompressed)\n",
+		uncompressedStringsSize);
+	printf("TOC main size:           %10" B_PRIu64 " (uncompressed)\n",
+		uncompressedMainSize);
+	printf("total TOC size:          %10" B_PRIu64 " (uncompressed)\n",
+		uncompressedTOCSize);
+}
+
+
+void
+PackageWriterListener::OnPackageAttributesSizeInfo(uint32 stringCount,
+	uint32 uncompressedSize)
+{
+	if (fQuiet || !fVerbose)
+		return;
+
+	printf("----- Package Attribute Info ---------------------\n");
+	printf("string count:            %10" B_PRIu32 "\n", stringCount);
+	printf("package attributes size: %10" B_PRIu32 " (uncompressed)\n",
+		uncompressedSize);
+}
+
+
+void
+PackageWriterListener::OnPackageSizeInfo(uint32 headerSize, uint64 heapSize,
+	uint64 tocSize, uint32 packageAttributesSize, uint64 totalSize)
+{
+	if (fQuiet)
+		return;
+
+	printf("----- Package Info ----------------\n");
+	printf("header size:             %10" B_PRIu32 "\n", headerSize);
+	printf("heap size:               %10" B_PRIu64 "\n", heapSize);
+	printf("TOC size:                %10" B_PRIu64 "\n", tocSize);
+	printf("package attributes size: %10" B_PRIu32 "\n",
+		packageAttributesSize);
+	printf("total size:              %10" B_PRIu64 "\n", totalSize);
+	printf("-----------------------------------\n");
+}
diff --git a/src/bin/package/PackageWriterListener.h b/src/bin/package/PackageWriterListener.h
new file mode 100644
index 0000000000..efe57817e3
--- /dev/null
+++ b/src/bin/package/PackageWriterListener.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2011, Oliver Tappe 
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef PACKAGE_WRITER_LISTENER_H
+#define PACKAGE_WRITER_LISTENER_H
+
+
+#include 
+
+
+using BPackageKit::BHPKG::BPackageWriterListener;
+using BPackageKit::BHPKG::BPackageWriter;
+
+
+class PackageWriterListener	: public BPackageWriterListener {
+public:
+								PackageWriterListener(bool verbose, bool quiet);
+
+	virtual	void				PrintErrorVarArgs(const char* format,
+									va_list args);
+
+	virtual	void				OnEntryAdded(const char* path);
+	virtual	void				OnTOCSizeInfo(uint64 uncompressedStringsSize,
+									uint64 uncompressedMainSize,
+									uint64 uncompressedTOCSize);
+	virtual	void				OnPackageAttributesSizeInfo(uint32 stringCount,
+									uint32 uncompressedSize);
+	virtual	void				OnPackageSizeInfo(uint32 headerSize,
+									uint64 heapSize, uint64 tocSize,
+									uint32 packageAttributesSize,
+									uint64 totalSize);
+
+private:
+			bool				fVerbose;
+			bool				fQuiet;
+};
+
+
+#endif	// PACKAGE_WRITER_LISTENER_H
diff --git a/src/bin/package/command_create.cpp b/src/bin/package/command_create.cpp
index 7e7af90676..23d7fe97dd 100644
--- a/src/bin/package/command_create.cpp
+++ b/src/bin/package/command_create.cpp
@@ -21,6 +21,7 @@
 #include 
 
 #include "package.h"
+#include "PackageWriterListener.h"
 #include "StandardErrorOutput.h"
 
 
@@ -28,75 +29,6 @@ using BPackageKit::BHPKG::BPackageWriterListener;
 using BPackageKit::BHPKG::BPackageWriter;
 
 
-class PackageWriterListener	: public BPackageWriterListener {
-public:
-	PackageWriterListener(bool verbose, bool quiet)
-		: fVerbose(verbose), fQuiet(quiet)
-	{
-	}
-
-	virtual void PrintErrorVarArgs(const char* format, va_list args)
-	{
-		vfprintf(stderr, format, args);
-	}
-
-	virtual void OnEntryAdded(const char* path)
-	{
-		if (fQuiet || !fVerbose)
-			return;
-
-		printf("\t%s\n", path);
-	}
-
-	virtual void OnTOCSizeInfo(uint64 uncompressedStringsSize,
-		uint64 uncompressedMainSize, uint64 uncompressedTOCSize)
-	{
-		if (fQuiet || !fVerbose)
-			return;
-
-		printf("----- TOC Info -----------------------------------\n");
-		printf("cached strings size:     %10" B_PRIu64 " (uncompressed)\n",
-			uncompressedStringsSize);
-		printf("TOC main size:           %10" B_PRIu64 " (uncompressed)\n",
-			uncompressedMainSize);
-		printf("total TOC size:          %10" B_PRIu64 " (uncompressed)\n",
-			uncompressedTOCSize);
-	}
-
-	virtual void OnPackageAttributesSizeInfo(uint32 stringCount,
-		uint32 uncompressedSize)
-	{
-		if (fQuiet || !fVerbose)
-			return;
-
-		printf("----- Package Attribute Info ---------------------\n");
-		printf("string count:            %10" B_PRIu32 "\n", stringCount);
-		printf("package attributes size: %10" B_PRIu32 " (uncompressed)\n",
-			uncompressedSize);
-	}
-
-	virtual void OnPackageSizeInfo(uint32 headerSize, uint64 heapSize,
-		uint64 tocSize, uint32 packageAttributesSize, uint64 totalSize)
-	{
-		if (fQuiet)
-			return;
-
-		printf("----- Package Info ----------------\n");
-		printf("header size:             %10" B_PRIu32 "\n", headerSize);
-		printf("heap size:               %10" B_PRIu64 "\n", heapSize);
-		printf("TOC size:                %10" B_PRIu64 "\n", tocSize);
-		printf("package attributes size: %10" B_PRIu32 "\n",
-			packageAttributesSize);
-		printf("total size:              %10" B_PRIu64 "\n", totalSize);
-		printf("-----------------------------------\n");
-	}
-
-private:
-	bool fVerbose;
-	bool fQuiet;
-};
-
-
 int
 command_create(int argc, const char* const* argv)
 {
diff --git a/src/tools/package/Jamfile b/src/tools/package/Jamfile
index 92baf1fe33..650ad04910 100644
--- a/src/tools/package/Jamfile
+++ b/src/tools/package/Jamfile
@@ -12,6 +12,7 @@ BuildPlatformMain package :
 	command_extract.cpp
 	command_list.cpp
 	package.cpp
+	PackageWriterListener.cpp
 	StandardErrorOutput.cpp
 
 	:

From 35f8c67c17d5a35756ef419d51c640fa9eea4cdc Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 04:31:30 +0200
Subject: [PATCH 0204/1170] Move directory iteration helper to own file

---
 src/bin/package/Jamfile                 |  1 +
 src/bin/package/PackageWritingUtils.cpp | 49 +++++++++++++++++++++++++
 src/bin/package/PackageWritingUtils.h   | 22 +++++++++++
 src/bin/package/command_create.cpp      | 26 ++-----------
 src/tools/package/Jamfile               |  1 +
 5 files changed, 76 insertions(+), 23 deletions(-)
 create mode 100644 src/bin/package/PackageWritingUtils.cpp
 create mode 100644 src/bin/package/PackageWritingUtils.h

diff --git a/src/bin/package/Jamfile b/src/bin/package/Jamfile
index ec5150666c..b015b5f837 100644
--- a/src/bin/package/Jamfile
+++ b/src/bin/package/Jamfile
@@ -9,6 +9,7 @@ BinCommand package :
 	command_list.cpp
 	package.cpp
 	PackageWriterListener.cpp
+	PackageWritingUtils.cpp
 	StandardErrorOutput.cpp
 
 	:
diff --git a/src/bin/package/PackageWritingUtils.cpp b/src/bin/package/PackageWritingUtils.cpp
new file mode 100644
index 0000000000..da83e349b0
--- /dev/null
+++ b/src/bin/package/PackageWritingUtils.cpp
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "PackageWritingUtils.h"
+
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+
+
+status_t
+add_current_directory_entries(BPackageWriter& packageWriter,
+	BPackageWriterListener& listener, bool skipPackageInfo)
+{
+	// open the current directory
+	DIR* dir = opendir(".");
+	if (dir == NULL) {
+		listener.PrintError("Error: Failed to opendir '.': %s\n",
+			strerror(errno));
+		return errno;
+	}
+	CObjectDeleter dirCloser(dir, &closedir);
+
+	while (dirent* entry = readdir(dir)) {
+		// skip "." and ".."
+		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+			continue;
+
+		// skip the .PackageInfo, if requested
+		if (skipPackageInfo
+			&& strcmp(entry->d_name, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) {
+			continue;
+		}
+
+		status_t error = packageWriter.AddEntry(entry->d_name);
+		if (error != B_OK)
+			return error;
+	}
+
+	return B_OK;
+}
diff --git a/src/bin/package/PackageWritingUtils.h b/src/bin/package/PackageWritingUtils.h
new file mode 100644
index 0000000000..ba696c9eb8
--- /dev/null
+++ b/src/bin/package/PackageWritingUtils.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef PACKAGE_WRITING_UTILS_H
+#define PACKAGE_WRITING_UTILS_H
+
+
+#include 
+
+#include 
+
+
+using BPackageKit::BHPKG::BPackageWriter;
+using BPackageKit::BHPKG::BPackageWriterListener;
+
+
+status_t	add_current_directory_entries(BPackageWriter& packageWriter,
+				BPackageWriterListener& listener, bool skipPackageInfo);
+
+
+#endif	// PACKAGE_WRITING_UTILS_H
diff --git a/src/bin/package/command_create.cpp b/src/bin/package/command_create.cpp
index 23d7fe97dd..c575a7964a 100644
--- a/src/bin/package/command_create.cpp
+++ b/src/bin/package/command_create.cpp
@@ -5,7 +5,6 @@
  */
 
 
-#include 
 #include 
 #include 
 #include 
@@ -22,6 +21,7 @@
 
 #include "package.h"
 #include "PackageWriterListener.h"
+#include "PackageWritingUtils.h"
 #include "StandardErrorOutput.h"
 
 
@@ -109,29 +109,9 @@ command_create(int argc, const char* const* argv)
 		}
 	}
 
-	// add all files of current directory
-	DIR* dir = opendir(".");
-	if (dir == NULL) {
-		listener.PrintError("Error: Failed to opendir '.': %s\n",
-			strerror(errno));
+	// add all files of the current directory, save for the .PackageInfo
+	if (add_current_directory_entries(packageWriter, listener, true) != B_OK)
 		return 1;
-	}
-
-	while (dirent* entry = readdir(dir)) {
-		// skip "." and ".."
-		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
-			continue;
-
-		// also skip the .PackageInfo -- we'll add it later
-		if (strcmp(entry->d_name, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0)
-			continue;
-
-		result = packageWriter.AddEntry(entry->d_name);
-		if (result != B_OK)
-			return 1;
-	}
-
-	closedir(dir);
 
 	// add the .PackageInfo
 	result = packageWriter.AddEntry(B_HPKG_PACKAGE_INFO_FILE_NAME,
diff --git a/src/tools/package/Jamfile b/src/tools/package/Jamfile
index 650ad04910..1f08a8d597 100644
--- a/src/tools/package/Jamfile
+++ b/src/tools/package/Jamfile
@@ -13,6 +13,7 @@ BuildPlatformMain package :
 	command_list.cpp
 	package.cpp
 	PackageWriterListener.cpp
+	PackageWritingUtils.cpp
 	StandardErrorOutput.cpp
 
 	:

From c1b5ec4065becc1c7bb35390ac88800de9012e34 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 04:31:59 +0200
Subject: [PATCH 0205/1170] Add "package add" command.

---
 src/bin/package/Jamfile         |   1 +
 src/bin/package/command_add.cpp | 165 ++++++++++++++++++++++++++++++++
 src/bin/package/package.cpp     |  20 +++-
 src/bin/package/package.h       |   1 +
 src/tools/package/Jamfile       |   1 +
 5 files changed, 187 insertions(+), 1 deletion(-)
 create mode 100644 src/bin/package/command_add.cpp

diff --git a/src/bin/package/Jamfile b/src/bin/package/Jamfile
index b015b5f837..0ee72e967a 100644
--- a/src/bin/package/Jamfile
+++ b/src/bin/package/Jamfile
@@ -3,6 +3,7 @@ SubDir HAIKU_TOP src bin package ;
 UsePrivateHeaders kernel shared ;
 
 BinCommand package :
+	command_add.cpp
 	command_create.cpp
 	command_dump.cpp
 	command_extract.cpp
diff --git a/src/bin/package/command_add.cpp b/src/bin/package/command_add.cpp
new file mode 100644
index 0000000000..36336842d3
--- /dev/null
+++ b/src/bin/package/command_add.cpp
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2011, Oliver Tappe 
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
+
+#include "package.h"
+#include "PackageWriterListener.h"
+#include "PackageWritingUtils.h"
+#include "StandardErrorOutput.h"
+
+
+using namespace BPackageKit::BHPKG;
+
+
+int
+command_add(int argc, const char* const* argv)
+{
+	const char* changeToDirectory = NULL;
+	const char* packageInfoFileName = NULL;
+	bool quiet = false;
+	bool verbose = false;
+	bool force = false;
+
+	while (true) {
+		static struct option sLongOptions[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ "quiet", no_argument, 0, 'q' },
+			{ "verbose", no_argument, 0, 'v' },
+			{ 0, 0, 0, 0 }
+		};
+
+		opterr = 0; // don't print errors
+		int c = getopt_long(argc, (char**)argv, "+C:fhi:qv", sLongOptions,
+			NULL);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'C':
+				changeToDirectory = optarg;
+				break;
+
+			case 'h':
+				print_usage_and_exit(false);
+				break;
+
+			case 'f':
+				force = true;
+				break;
+
+			case 'i':
+				packageInfoFileName = optarg;
+				break;
+
+			case 'q':
+				quiet = true;
+				break;
+
+			case 'v':
+				verbose = true;
+				break;
+
+			default:
+				print_usage_and_exit(true);
+				break;
+		}
+	}
+
+	// The remaining arguments are the package file and the entries to add.
+	if (optind >= argc)
+		print_usage_and_exit(true);
+
+	const char* packageFileName = argv[optind++];
+
+	// entries must be specified, if a .PackageInfo hasn't been specified via
+	// an option
+	if (optind >= argc && packageInfoFileName == NULL)
+		print_usage_and_exit(true);
+
+	const char* const* entriesToAdd = argv + optind;
+	int entriesToAddCount = argc - optind;
+
+	// create package
+	PackageWriterListener listener(verbose, quiet);
+	BPackageWriter packageWriter(&listener);
+	status_t result = packageWriter.Init(packageFileName,
+		B_HPKG_WRITER_UPDATE_PACKAGE | (force ? B_HPKG_WRITER_FORCE_ADD : 0));
+	if (result != B_OK)
+		return 1;
+
+	// If a package info file has been specified explicitly, open it.
+	int packageInfoFD = -1;
+	if (packageInfoFileName != NULL) {
+		packageInfoFD = open(packageInfoFileName, O_RDONLY);
+		if (packageInfoFD < 0) {
+			fprintf(stderr, "Error: Failed to open package info file \"%s\": "
+				"%s\n", packageInfoFileName, strerror(errno));
+		}
+	}
+
+	// change directory, if requested
+	if (changeToDirectory != NULL) {
+		if (chdir(changeToDirectory) != 0) {
+			listener.PrintError(
+				"Error: Failed to change the current working directory to "
+				"\"%s\": %s\n", changeToDirectory, strerror(errno));
+		}
+	}
+
+	// add the entries
+	for (int i = 0; i < entriesToAddCount; i++) {
+		const char* entry = entriesToAdd[i];
+
+		if (strcmp(entry, ".") == 0) {
+			// add all entries in the current directory; skip .PackageInfo,
+			// if a different file was specified
+			if (add_current_directory_entries(packageWriter,
+					listener, packageInfoFileName != NULL) != B_OK)
+				return 1;
+		} else {
+			// skip .PackageInfo, if a different file was specified
+			if (packageInfoFileName != NULL
+				&& strcmp(entry, B_HPKG_PACKAGE_INFO_FILE_NAME) == 0) {
+				continue;
+			}
+
+			if (packageWriter.AddEntry(entry) != B_OK)
+				return 1;
+		}
+	}
+
+	// add the .PackageInfo, if explicitly specified
+	if (packageInfoFileName != NULL) {
+		result = packageWriter.AddEntry(B_HPKG_PACKAGE_INFO_FILE_NAME,
+			packageInfoFD);
+		if (result != B_OK)
+			return 1;
+	}
+
+	// write the package
+	result = packageWriter.Finish();
+	if (result != B_OK)
+		return 1;
+
+	if (verbose)
+		printf("\nsuccessfully created package '%s'\n", packageFileName);
+
+	return 0;
+}
diff --git a/src/bin/package/package.cpp b/src/bin/package/package.cpp
index cebeff5fc4..93797fd656 100644
--- a/src/bin/package/package.cpp
+++ b/src/bin/package/package.cpp
@@ -23,10 +23,25 @@ static const char* kUsage =
 	"Creates, inspects, or extracts a Haiku package.\n"
 	"\n"
 	"Commands:\n"
+	"  add [  ]  ...\n"
+	"    Adds the specified entries  to package file .\n"
+	"\n"
+	"    -C    - Change to directory  before adding entries.\n"
+	"    -f         - Force adding, replacing already existing entries. "
+		"Without\n"
+	"                 this option adding will fail when encountering a "
+		"pre-exiting\n"
+	"                 entry (directories will be merged, though).\n"
+	"    -i   - Use the package info file . It will be added as\n"
+	"                 \".PackageInfo\", overriding a \".PackageInfo\" file,\n"
+	"                 existing.\n"
+	"    -q         - Be quiet (don't show any output except for errors).\n"
+	"    -v         - Be verbose (show more info about created package).\n"
+	"\n"
 	"  create [  ] \n"
 	"    Creates package file  from contents of current directory.\n"
 	"\n"
-	"    -C    - Change to directory  before starting.\n"
+	"    -C    - Change to directory  before adding entries.\n"
 	"    -i   - Use the package info file . It will be added as\n"
 	"                 \".PackageInfo\", overriding a \".PackageInfo\" file,\n"
 	"                 existing.\n"
@@ -71,6 +86,9 @@ main(int argc, const char* const* argv)
 		print_usage_and_exit(true);
 
 	const char* command = argv[1];
+	if (strcmp(command, "add") == 0)
+		return command_add(argc - 1, argv + 1);
+
 	if (strcmp(command, "create") == 0)
 		return command_create(argc - 1, argv + 1);
 
diff --git a/src/bin/package/package.h b/src/bin/package/package.h
index b1b5d9a6fb..05ebf17fde 100644
--- a/src/bin/package/package.h
+++ b/src/bin/package/package.h
@@ -8,6 +8,7 @@
 
 void	print_usage_and_exit(bool error);
 
+int		command_add(int argc, const char* const* argv);
 int		command_create(int argc, const char* const* argv);
 int		command_dump(int argc, const char* const* argv);
 int		command_extract(int argc, const char* const* argv);
diff --git a/src/tools/package/Jamfile b/src/tools/package/Jamfile
index 1f08a8d597..2609ede7ad 100644
--- a/src/tools/package/Jamfile
+++ b/src/tools/package/Jamfile
@@ -7,6 +7,7 @@ SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src bin package ] ;
 USES_BE_API on package = true ;
 
 BuildPlatformMain package :
+	command_add.cpp
 	command_create.cpp
 	command_dump.cpp
 	command_extract.cpp

From 6f785748aa1fef5bb193e17ff243794250004ac6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 04:46:26 +0200
Subject: [PATCH 0206/1170] Write uncompressed package file TOC, if necessary

---
 .../private/package/hpkg/PackageWriterImpl.h  |  8 ++
 src/kits/package/hpkg/PackageWriterImpl.cpp   | 81 ++++++++++++++-----
 2 files changed, 71 insertions(+), 18 deletions(-)

diff --git a/headers/private/package/hpkg/PackageWriterImpl.h b/headers/private/package/hpkg/PackageWriterImpl.h
index 4e06a38270..298a159121 100644
--- a/headers/private/package/hpkg/PackageWriterImpl.h
+++ b/headers/private/package/hpkg/PackageWriterImpl.h
@@ -79,6 +79,14 @@ private:
 			void				_AttributeRemoved(Attribute* attribute);
 
 			void				_WriteTOC(hpkg_header& header);
+			int32				_WriteTOCCompressed(
+									uint64& _uncompressedStringsSize,
+									uint64& _uncompressedMainSize,
+									uint64& _tocUncompressedSize);
+			int32				_WriteTOCUncompressed(
+									uint64& _uncompressedStringsSize,
+									uint64& _uncompressedMainSize,
+									uint64& _tocUncompressedSize);
 			int32				_WriteTOCSections(uint64& _stringsSize,
 									uint64& _mainSize);
 			void				_WriteAttributeChildren(Attribute* attribute);
diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index de7564e2e8..5181c5e16a 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -1316,40 +1316,85 @@ PackageWriterImpl::_WriteTOC(hpkg_header& header)
 {
 	// prepare the writer (zlib writer on top of a file writer)
 	off_t startOffset = fHeapEnd;
-	FDDataWriter realWriter(FD(), startOffset, fListener);
+
+	// write the sections
+	uint32 compression = B_HPKG_COMPRESSION_ZLIB;
+	uint64 uncompressedStringsSize;
+	uint64 uncompressedMainSize;
+	uint64 tocUncompressedSize;
+	int32 cachedStringsWritten = _WriteTOCCompressed(uncompressedStringsSize,
+		uncompressedMainSize, tocUncompressedSize);
+
+	off_t endOffset = fHeapEnd;
+
+	if (endOffset - startOffset >= (off_t)tocUncompressedSize) {
+		// the compressed section isn't shorter -- write uncompressed
+		fHeapEnd = startOffset;
+		compression = B_HPKG_COMPRESSION_NONE;
+		cachedStringsWritten = _WriteTOCUncompressed(uncompressedStringsSize,
+			uncompressedMainSize, tocUncompressedSize);
+
+		endOffset = fHeapEnd;
+	}
+
+	fListener->OnTOCSizeInfo(uncompressedStringsSize, uncompressedMainSize,
+		tocUncompressedSize);
+
+	// update the header
+
+	// TOC
+	header.toc_compression = B_HOST_TO_BENDIAN_INT32(compression);
+	header.toc_length_compressed = B_HOST_TO_BENDIAN_INT64(
+		endOffset - startOffset);
+	header.toc_length_uncompressed = B_HOST_TO_BENDIAN_INT64(
+		tocUncompressedSize);
+
+	// TOC subsections
+	header.toc_strings_length = B_HOST_TO_BENDIAN_INT64(
+		uncompressedStringsSize);
+	header.toc_strings_count = B_HOST_TO_BENDIAN_INT64(cachedStringsWritten);
+}
+
+
+int32
+PackageWriterImpl::_WriteTOCCompressed(uint64& _uncompressedStringsSize,
+	uint64& _uncompressedMainSize, uint64& _tocUncompressedSize)
+{
+	FDDataWriter realWriter(FD(), fHeapEnd, fListener);
 	ZlibDataWriter zlibWriter(&realWriter);
 	SetDataWriter(&zlibWriter);
 	zlibWriter.Init();
 
 	// write the sections
-	uint64 uncompressedStringsSize;
-	uint64 uncompressedMainSize;
 	int32 cachedStringsWritten
-		= _WriteTOCSections(uncompressedStringsSize, uncompressedMainSize);
+		= _WriteTOCSections(_uncompressedStringsSize, _uncompressedMainSize);
 
 	// finish the writer
 	zlibWriter.Finish();
 	fHeapEnd = realWriter.Offset();
 	SetDataWriter(NULL);
 
-	off_t endOffset = fHeapEnd;
+	_tocUncompressedSize = zlibWriter.BytesWritten();
+	return cachedStringsWritten;
+}
 
-	fListener->OnTOCSizeInfo(uncompressedStringsSize, uncompressedMainSize,
-		zlibWriter.BytesWritten());
 
-	// update the header
+int32
+PackageWriterImpl::_WriteTOCUncompressed(uint64& _uncompressedStringsSize,
+	uint64& _uncompressedMainSize, uint64& _tocUncompressedSize)
+{
+	FDDataWriter realWriter(FD(), fHeapEnd, fListener);
+	SetDataWriter(&realWriter);
 
-	// TOC
-	header.toc_compression = B_HOST_TO_BENDIAN_INT32(B_HPKG_COMPRESSION_ZLIB);
-	header.toc_length_compressed = B_HOST_TO_BENDIAN_INT64(
-		endOffset - startOffset);
-	header.toc_length_uncompressed = B_HOST_TO_BENDIAN_INT64(
-		zlibWriter.BytesWritten());
+	// write the sections
+	int32 cachedStringsWritten
+		= _WriteTOCSections(_uncompressedStringsSize, _uncompressedMainSize);
 
-	// TOC subsections
-	header.toc_strings_length = B_HOST_TO_BENDIAN_INT64(
-		uncompressedStringsSize);
-	header.toc_strings_count = B_HOST_TO_BENDIAN_INT64(cachedStringsWritten);
+	fHeapEnd = realWriter.Offset();
+	SetDataWriter(NULL);
+
+	_tocUncompressedSize = realWriter.BytesWritten();
+	return cachedStringsWritten;
 }
 
 

From cc3f28c0b5237b9afc9a26ebc90aed6e50c2dc32 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 08:28:32 +0200
Subject: [PATCH 0207/1170] PackageWriterImpl::_MoveHeapChunk(): better output

---
 src/kits/package/hpkg/PackageWriterImpl.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 5181c5e16a..9bf4913b62 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -1144,7 +1144,8 @@ PackageWriterImpl::_MoveHeapChunk(off_t fromOffset, off_t toOffset, off_t size)
 			throw status_t(errno);
 		}
 		if ((size_t)bytesRead < toCopy) {
-			fListener->PrintError("Failed to read from package file.\n");
+			fListener->PrintError("Failed to read from package file (wanted "
+				"%zu bytes, got %zd).\n", toCopy, bytesRead);
 			throw status_t(B_IO_ERROR);
 		}
 

From f79277d0e707ed8ec4d2349108d17b99a2287488 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 08:31:19 +0200
Subject: [PATCH 0208/1170] Fix "package add" heap compacting

PackageWriterImpl::_CompactHeap(): Incorrectly used fHeapEnd instead of
the heap size. So the last copied chunk was too large.
---
 src/kits/package/hpkg/PackageWriterImpl.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 9bf4913b62..03a117d6dd 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -1117,9 +1117,10 @@ PackageWriterImpl::_CompactHeap()
 	}
 
 	// move the final chunk
-	if (delta > 0 && chunkOffset < fHeapEnd) {
+	off_t heapSize = fHeapEnd - fHeapOffset;
+	if (delta > 0 && chunkOffset < heapSize) {
 		_MoveHeapChunk(chunkOffset, chunkOffset - delta,
-			fHeapEnd - chunkOffset);
+			heapSize - chunkOffset);
 	}
 
 	fHeapEnd -= delta;

From 161d45feb55fde0e00e3e065ddd800529bdd1074 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 08:44:19 +0200
Subject: [PATCH 0209/1170] Support for package "update" build profile action

* Add global HAIKU_PACKAGES_UPDATE_ONLY build system variable, which is
  set for the "update" and "update-all" build profile actions.
* Change the HAIKU_INCLUDE_IN_CONTAINER_VAR variable on packages to
  HAIKU_INCLUDE_IN_PACKAGES for all packages. The variable is also
  set for the "update" and "update-all" build profile actions.
* Introduce HAIKU_CONTAINER_INHERIT_UPDATE_VARIABLE on container
  variable. If set, the contained variable will be set on the container
  when one or more files in it are updated. It is set on packages so an
  update of a file in a package causes the package to be updated in the
  image.
* Introduce HAIKU_CONTAINER_ALWAYS_CREATE_DIRECTORIES on container
  variable. If set, directories will be created also in update mode. It
  is set on packages.
---
 build/jam/ImageRules              | 16 +++++++++++++++-
 build/jam/MiscRules               |  4 ++++
 build/jam/PackageRules            | 13 +++++++++++--
 build/scripts/build_haiku_package | 10 +++++++---
 4 files changed, 37 insertions(+), 6 deletions(-)

diff --git a/build/jam/ImageRules b/build/jam/ImageRules
index 48fb107f73..ae4ecd6516 100644
--- a/build/jam/ImageRules
+++ b/build/jam/ImageRules
@@ -177,6 +177,18 @@ rule AddFilesToContainer container : directoryTokens : targets : destName
 		if $(filterVar) {
 			targets = [ FilterContainerUpdateTargets $(targets)
 				: $(filterVar) ] ;
+
+			# If there are any targets, mark the container as to be included in
+			# an update, too, if it has set the update inheritance variable.
+			# This makes updating a target that lives in a package on an image
+			# work.
+			if $(targets) {
+				local updateVariable = [ on $(container) return
+					$(HAIKU_CONTAINER_INHERIT_UPDATE_VARIABLE) ] ;
+				if $(updateVariable) {
+					$(updateVariable) on $(container) = 1 ;
+				}
+			}
 		}
 	}
 
@@ -480,7 +492,9 @@ rule CreateContainerMakeDirectoriesScript container : script
 	# If the image shall only be updated, we don't create directories.
 	if $(dirsToCreate)
 		&& ( ! [ on $(container) return $(HAIKU_CONTAINER_UPDATE_ONLY) ]
-			|| [ IncludeAllTargetsInContainer $(container) ] ) {
+			|| [ IncludeAllTargetsInContainer $(container) ]
+			|| [ on $(container) return
+				$(HAIKU_CONTAINER_ALWAYS_CREATE_DIRECTORIES) ] ) {
 		Depends $(scriptBody) : $(dirsToCreate) ;
 		CreateContainerMakeDirectoriesScript1 $(scriptBody) : $(dirsToCreate) ;
 
diff --git a/build/jam/MiscRules b/build/jam/MiscRules
index 973c368e08..326f0b90d1 100644
--- a/build/jam/MiscRules
+++ b/build/jam/MiscRules
@@ -394,13 +394,17 @@ rule DefineBuildProfile name : type : path {
 		case "update" : {
 			JAM_TARGETS = $(buildTarget) ;
 			SetUpdateHaikuImageOnly 1 ;
+			HAIKU_PACKAGES_UPDATE_ONLY = 1 ;
 			HAIKU_INCLUDE_IN_IMAGE on $(HAIKU_BUILD_PROFILE_PARAMETERS) = 1 ;
+			HAIKU_INCLUDE_IN_PACKAGES on $(HAIKU_BUILD_PROFILE_PARAMETERS) = 1 ;
 		}
 
 		case "update-all" : {
 			JAM_TARGETS = $(buildTarget) ;
 			SetUpdateHaikuImageOnly 1 ;
+			HAIKU_PACKAGES_UPDATE_ONLY = 1 ;
 			HAIKU_INCLUDE_IN_IMAGE = 1 ;
+			HAIKU_INCLUDE_IN_PACKAGES = 1 ;
 		}
 
 		case "mount" : {
diff --git a/build/jam/PackageRules b/build/jam/PackageRules
index b6bf583e35..4011cb8e37 100644
--- a/build/jam/PackageRules
+++ b/build/jam/PackageRules
@@ -268,13 +268,20 @@ rule HaikuPackage package
 	local grist = [ FHaikuPackageGrist $(package) ] ;
 
 	HAIKU_CONTAINER_GRIST on $(package) = $(grist) ;
-	HAIKU_INCLUDE_IN_CONTAINER_VAR on $(package)
-		= $(grist)_HAIKU_INCLUDE_IN_PACKAGE ;
+	HAIKU_INCLUDE_IN_CONTAINER_VAR on $(package) = HAIKU_INCLUDE_IN_PACKAGES ;
 	HAIKU_INSTALL_TARGETS_VAR on $(package)
 		= $(grist)_HAIKU_PACKAGE_INSTALL_TARGETS ;
 	HAIKU_CONTAINER_SYSTEM_DIR_TOKENS on $(package) = ;
 
 	HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE = $(package) ;
+
+	if $(HAIKU_PACKAGES_UPDATE_ONLY) {
+		HAIKU_CONTAINER_UPDATE_ONLY on $(package) = 1 ;
+		HAIKU_CONTAINER_INHERIT_UPDATE_VARIABLE on $(package)
+			= HAIKU_INCLUDE_IN_IMAGE ;
+	}
+
+	HAIKU_CONTAINER_ALWAYS_CREATE_DIRECTORIES on $(package) = 1 ;
 }
 
 
@@ -301,6 +308,8 @@ rule BuildHaikuPackage package : packageInfo
 	AddVariableToScript $(script) : tmpDir : $(tempDir) ;
 	AddVariableToScript $(script) : addBuildCompatibilityLibDir
 		: $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) ;
+	AddVariableToScript $(script) : updateOnly
+		: [ on $(package) return $(HAIKU_CONTAINER_UPDATE_ONLY) ] ;
 	AddTargetVariableToScript $(script) : addattr ;
 	AddTargetVariableToScript $(script) : copyattr ;
 	AddTargetVariableToScript $(script) : package ;
diff --git a/build/scripts/build_haiku_package b/build/scripts/build_haiku_package
index 0e8228dd88..fbbefdfd81 100755
--- a/build/scripts/build_haiku_package
+++ b/build/scripts/build_haiku_package
@@ -6,6 +6,7 @@ set -o errexit
 # outputDir
 # tmpDir
 # addBuildCompatibilityLibDir
+# updateOnly
 #
 # addattr
 # copyattr
@@ -23,7 +24,6 @@ fi
 packagePath="$1"
 packageInfoPath="$2"
 shift 2
-echo "Building package $1 with info $2..."
 
 if [ $# -gt 0 ]; then
 	. $1
@@ -61,5 +61,9 @@ done
 
 
 # create the package
-rm -f "$packagePath"
-$package create -i "$packageInfoPath" -C "$contentsDir" "$packagePath"
+if [ ! $updateOnly ]; then
+	rm -f "$packagePath"
+	$package create -q -i "$packageInfoPath" -C "$contentsDir" "$packagePath"
+else
+	$package add -q -f -i "$packageInfoPath" -C "$contentsDir" "$packagePath" .
+fi

From 204261b63a8cad0629912a9cecfe982b4b78ae44 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 09:06:10 +0200
Subject: [PATCH 0210/1170] AddFilesToContainer: avoid unnecessary work

* If after filtering the list of targets is empty, return.
* Get the directory only afterwards.
---
 build/jam/ImageRules | 9 +++++++--
 1 file changed, 7 insertions(+), 2 deletions(-)

diff --git a/build/jam/ImageRules b/build/jam/ImageRules
index ae4ecd6516..1b43a717cb 100644
--- a/build/jam/ImageRules
+++ b/build/jam/ImageRules
@@ -162,8 +162,6 @@ rule AddFilesToContainer container : directoryTokens : targets : destName
 	# AddFilesToContainer  :  : 
 	#	[ : dest name ]
 	#
-	local directory = [ AddDirectoryToContainer $(container)
-		: $(directoryTokens) ] ;
 	local containerGrist = [ on $(container) return $(HAIKU_CONTAINER_GRIST) ] ;
 	local systemDirTokens
 		= [ on $(container) return $(HAIKU_CONTAINER_SYSTEM_DIR_TOKENS) ] ;
@@ -192,6 +190,13 @@ rule AddFilesToContainer container : directoryTokens : targets : destName
 		}
 	}
 
+	if ! $(targets) {
+		return ;
+	}
+
+	local directory = [ AddDirectoryToContainer $(container)
+		: $(directoryTokens) ] ;
+
 	# We create a unique dummy target per target to install.
 	local installTargetsVar
 		= [ on $(container) return $(HAIKU_INSTALL_TARGETS_VAR) ] ;

From 319b1a7b3b488f5a6621e9888564e5f42051f096 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 09:10:27 +0200
Subject: [PATCH 0211/1170] Don't add directories explicitly to packages

Directories are added implicitly when entries are added, so there's no
need to add those directories. Directories without content don't need to
be added either, since due to the read-only nature of packages they will
remain empty.
---
 build/jam/HaikuPackages | 11 ++++-------
 1 file changed, 4 insertions(+), 7 deletions(-)

diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages
index e043cfff58..b97c704bf9 100644
--- a/build/jam/HaikuPackages
+++ b/build/jam/HaikuPackages
@@ -172,8 +172,6 @@ local logoArtwork =
 SEARCH on $(logoArtwork) = [ FDirName $(HAIKU_TOP) data artwork ] ;
 AddFilesToPackage data artwork : $(logoArtwork) ;
 
-AddDirectoryToPackage data sounds ;
-
 # Mail spell check dictionaries
 local spellFiles = words geekspeak ;
 spellFiles = $(spellFiles:G=spell) ;
@@ -204,8 +202,10 @@ local cannaDicCanna = [ Glob $(cannaDir)/dic/canna
 AddFilesToPackage data Canna default	: $(cannaDefault) ;
 AddFilesToPackage data Canna dic		: $(cannaDic) ;
 AddFilesToPackage data Canna dic canna	: $(cannaDicCanna) ;
-AddDirectoryToPackage data Canna dic group ;
-AddDirectoryToPackage data Canna dic user ;
+#AddDirectoryToPackage data Canna dic group ;
+#AddDirectoryToPackage data Canna dic user ;
+	# TODO: If those serve any purpose, they should probably live in a writable
+	# subtree.
 
 local keymapFiles = [ Glob [ FDirName $(HAIKU_TOP) src data keymaps ]
 	: *.keymap ] ;
@@ -281,9 +281,6 @@ AddFilesToPackage add-ons Screen\ Savers : $(SYSTEM_ADD_ONS_SCREENSAVERS) ;
 AddFilesToPackage add-ons disk_systems : intel bfs ;
 
 
-AddDirectoryToPackage data synth ;
-AddDirectoryToPackage add-ons input_server methods ;
-
 # optional
 # TODO: We should probably build another package (including the data files
 # above) that can be installed, if desired.

From fd03be4838549e6e44627471b7692fc6a75ccf33 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 09:12:57 +0200
Subject: [PATCH 0212/1170] ExtractArchiveToContainer: Add update support

Add an alwaysUpdate parameter like the ExtractArchiveTo{Image,Package}
rules have and do the handling in the base rule.
---
 build/jam/ImageRules   | 21 ++++++++++++---------
 build/jam/PackageRules |  3 +--
 2 files changed, 13 insertions(+), 11 deletions(-)

diff --git a/build/jam/ImageRules b/build/jam/ImageRules
index 1b43a717cb..ba8c541037 100644
--- a/build/jam/ImageRules
+++ b/build/jam/ImageRules
@@ -339,7 +339,7 @@ rule AddWifiFirmwareToContainer container : driver : package : archive : extract
 	local dirTokens = $(systemDirTokens) data firmware $(driver) ;
 	if $(extract) = true || $(extract) = 1 {
 		ExtractArchiveToContainer $(container) : $(dirTokens)
-			: $(firmwareArchive) : $(package) ;
+			: $(firmwareArchive) : : $(package) ;
 	} else {
 		AddFilesToContainer $(container) : $(dirTokens) : $(firmwareArchive)  ;
 	}
@@ -347,10 +347,17 @@ rule AddWifiFirmwareToContainer container : driver : package : archive : extract
 
 
 rule ExtractArchiveToContainer container : directoryTokens : archiveFile
-	: extractedSubDir
+	: alwaysUpdate : extractedSubDir
 {
 	# ExtractArchiveToContainer  :  : 
-	#	:  ;
+	#	:  :  ;
+
+	# If the container shall only be updated, we extract only, if explicitely
+	# requested.
+	if [ on $(container) return $(HAIKU_CONTAINER_UPDATE_ONLY) ]
+		&& ! $(alwaysUpdate) {
+		return ;
+	}
 
 	local directory = [ AddDirectoryToContainer $(container)
 		: $(directoryTokens) ] ;
@@ -815,12 +822,8 @@ rule ExtractArchiveToHaikuImage dirTokens : archiveFile : alwaysUpdate
 	# ExtractArchiveToHaikuImage  :  : 
 	#	:  ;
 
-	# If the image shall only be updated, we extract only, if explicitely
-	# requested.
-	if ! [ IsUpdateHaikuImageOnly ] || $(alwaysUpdate) {
-		ExtractArchiveToContainer $(HAIKU_IMAGE_CONTAINER_NAME) : $(dirTokens)
-			: $(archiveFile) : $(extractedSubDir) ;
-	}
+	ExtractArchiveToContainer $(HAIKU_IMAGE_CONTAINER_NAME) : $(dirTokens)
+		: $(archiveFile) : $(alwaysUpdate) : $(extractedSubDir) ;
 }
 
 rule AddDriversToHaikuImage relativeDirectoryTokens : targets
diff --git a/build/jam/PackageRules b/build/jam/PackageRules
index 4011cb8e37..86e3ed7847 100644
--- a/build/jam/PackageRules
+++ b/build/jam/PackageRules
@@ -400,9 +400,8 @@ rule AddWifiFirmwareToPackage driver : subDirToExtract : archive
 rule ExtractArchiveToPackage dirTokens : archiveFile : alwaysUpdate
 	: extractedSubDir
 {
-	# TODO: Update support?
 	ExtractArchiveToContainer $(HAIKU_CURRENTLY_BUILT_HAIKU_PACKAGE)
-		: $(dirTokens) : $(archiveFile) : $(extractedSubDir) ;
+		: $(dirTokens) : $(archiveFile) : $(alwaysUpdate) : $(extractedSubDir) ;
 }
 
 

From 5e2b65028135d2f4f0d9051002476ff12593c4b4 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 09:28:30 +0200
Subject: [PATCH 0213/1170] Update support for update-* targets

Set HAIKU_PACKAGES_UPDATE_ONLY and HAIKU_INCLUDE_IN_PACKAGES when one of
the pre-build-profile update-* targets are used.
---
 build/jam/CommandLineArguments | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/build/jam/CommandLineArguments b/build/jam/CommandLineArguments
index 84d9d633a3..01dd5e008a 100644
--- a/build/jam/CommandLineArguments
+++ b/build/jam/CommandLineArguments
@@ -81,7 +81,9 @@ rule ProcessCommandLineArguments
 				if $(JAM_TARGETS[1]) in update-image update-vmware-image
 						update-install {
 					SetUpdateHaikuImageOnly 1 ;
+					HAIKU_PACKAGES_UPDATE_ONLY = 1 ;
 					HAIKU_INCLUDE_IN_IMAGE on $(JAM_TARGETS[2-]) = 1 ;
+					HAIKU_INCLUDE_IN_PACKAGES on $(JAM_TARGETS[2-]) = 1 ;
 
 					if $(JAM_TARGETS[1]) = update-image {
 						JAM_TARGETS = haiku-image ;

From b059c5e4fce866ea79969342bbe385b324be94ed Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 09:29:24 +0200
Subject: [PATCH 0214/1170] Add PropagateContainerUpdateTargetFlags rule

It propagates the HAIKU_INCLUDE_IN_IMAGE and HAIKU_INCLUDE_IN_PACKAGES
variables from one target to another.
---
 build/jam/ImageRules | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/build/jam/ImageRules b/build/jam/ImageRules
index ba8c541037..f267dea633 100644
--- a/build/jam/ImageRules
+++ b/build/jam/ImageRules
@@ -157,6 +157,18 @@ rule IncludeAllTargetsInContainer container
 }
 
 
+rule PropagateContainerUpdateTargetFlags toTarget : fromTarget
+{
+	if [ on $(fromTarget) return $(HAIKU_INCLUDE_IN_IMAGE) ] {
+		HAIKU_INCLUDE_IN_IMAGE on $(toTarget) = 1 ;
+	}
+
+	if [ on $(fromTarget) return $(HAIKU_INCLUDE_IN_PACKAGES) ] {
+		HAIKU_INCLUDE_IN_PACKAGES on $(toTarget) = 1 ;
+	}
+}
+
+
 rule AddFilesToContainer container : directoryTokens : targets : destName
 {
 	# AddFilesToContainer  :  : 

From c9c6e365376258f4f29d474675c37f7e4ca75498 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 09:30:54 +0200
Subject: [PATCH 0215/1170] Use PropagateContainerUpdateTargetFlags rule

Propagate all update variables in CopySetHaikuRevision and for the
kernel pseudo target.
---
 build/jam/FileRules       | 3 +--
 src/system/kernel/Jamfile | 5 ++---
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/build/jam/FileRules b/build/jam/FileRules
index c2193840fc..054c916e56 100644
--- a/build/jam/FileRules
+++ b/build/jam/FileRules
@@ -341,8 +341,7 @@ rule CopySetHaikuRevision target : source
 		Depends $(target) : $(hgStore) ;
 	}
 
-	HAIKU_INCLUDE_IN_IMAGE on $(target)
-		= [ on $(source) return $(HAIKU_INCLUDE_IN_IMAGE) ] ;
+	PropagateContainerUpdateTargetFlags $(target) : $(source) ;
 
 	Depends $(target) : copyattr set_haiku_revision $(source) ;
 	CopySetHaikuRevision1 $(target)
diff --git a/src/system/kernel/Jamfile b/src/system/kernel/Jamfile
index bfc433f38a..05a1be7963 100644
--- a/src/system/kernel/Jamfile
+++ b/src/system/kernel/Jamfile
@@ -170,9 +170,8 @@ Depends kernel : kernel_$(TARGET_ARCH) ;
 Depends kernel.so : kernel ;
 	# kernel.so will be rebuilt with the kernel
 
-# propagate HAIKU_INCLUDE_IN_IMAGE variable from kernel to kernel_$(TARGET_ARCH)
-HAIKU_INCLUDE_IN_IMAGE on kernel_$(TARGET_ARCH)
-		= [ on kernel return $(HAIKU_INCLUDE_IN_IMAGE) ] ;
+# propagate the container update variable from kernel to kernel_$(TARGET_ARCH)
+PropagateContainerUpdateTargetFlags kernel_$(TARGET_ARCH) : kernel ;
 
 # Copy kernel and update the copy's revision section. We link everything
 # against the original, but the copy will end up on the disk image (this way

From 3095cb1bc9f5d9bafa4b5d2ead76449c99567c4a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 10:28:03 +0200
Subject: [PATCH 0216/1170] Remove copy'n'paste left-over

---
 src/kits/package/hpkg/PackageWriterImpl.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 03a117d6dd..f192f36469 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -1067,7 +1067,6 @@ PackageWriterImpl::_UpdateCheckEntryCollisions(Attribute* parentAttribute,
 				continue;
 			}
 
-			_AddEntry(fd, NULL, entry->d_name, pathBuffer);
 			_UpdateCheckEntryCollisions(entryAttribute, fd, NULL, entry->d_name,
 				pathBuffer);
 		}

From 718fba99c819b419a8eccff713a3ff71b44a2ecb Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 10:33:12 +0200
Subject: [PATCH 0217/1170] PackageWriterImpl::_AddEntry(): Fix update logic

* Don't only look up the entry attribute when the entry is implicit.
  Look it up, when it is a directory instead. This aligns it the logic
  with _UpdateCheckEntryCollisions().
* When the entry attribute exits and the entry is not implicit, add file
  attributes, but not stat data. This also aligns the logic with
  _UpdateCheckEntryCollisions(), which removes colliding attributes, but
  keeps stat data.
---
 src/kits/package/hpkg/PackageWriterImpl.cpp | 85 +++++++++++----------
 1 file changed, 46 insertions(+), 39 deletions(-)

diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index f192f36469..7ce51700a8 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -1567,9 +1567,10 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 
 	// In update mode we don't need to add an entry attribute for an implicit
 	// directory, if there already is one.
-	if (isImplicitEntry && (Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0) {
-		Attribute* entryAttribute = fTopAttribute->FindEntryChild(fileName);
-		if (entryAttribute != NULL) {
+	Attribute* entryAttribute = NULL;
+	if (S_ISDIR(st.st_mode) && (Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0) {
+		entryAttribute = fTopAttribute->FindEntryChild(fileName);
+		if (entryAttribute != NULL && isImplicitEntry) {
 			Stacker entryAttributeStacker(fTopAttribute,
 				entryAttribute);
 			_AddDirectoryChildren(entry, fd, pathBuffer);
@@ -1596,49 +1597,55 @@ PackageWriterImpl::_AddEntry(int dirFD, Entry* entry, const char* fileName,
 		throw status_t(B_UNSUPPORTED);
 	}
 
-	// add attribute entry
-	Attribute* entryAttribute = _AddStringAttribute(
-		B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY, fileName);
+	// add attribute entry, if it doesn't already exist (update mode, directory)
+	bool isNewEntry = entryAttribute == NULL;
+	if (entryAttribute == NULL) {
+		entryAttribute = _AddStringAttribute(
+			B_HPKG_ATTRIBUTE_ID_DIRECTORY_ENTRY, fileName);
+	}
+
 	Stacker entryAttributeStacker(fTopAttribute, entryAttribute);
 
-	// add stat data
-	if (fileType != B_HPKG_DEFAULT_FILE_TYPE)
-		_AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_TYPE, fileType);
-	if (defaultPermissions != uint32(st.st_mode & ALLPERMS)) {
-		_AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_PERMISSIONS,
-			uint32(st.st_mode & ALLPERMS));
-	}
-	_AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_ATIME, uint32(st.st_atime));
-	_AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_MTIME, uint32(st.st_mtime));
+	if (isNewEntry) {
+		// add stat data
+		if (fileType != B_HPKG_DEFAULT_FILE_TYPE)
+			_AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_TYPE, fileType);
+		if (defaultPermissions != uint32(st.st_mode & ALLPERMS)) {
+			_AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_PERMISSIONS,
+				uint32(st.st_mode & ALLPERMS));
+		}
+		_AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_ATIME, uint32(st.st_atime));
+		_AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_MTIME, uint32(st.st_mtime));
 #ifdef __HAIKU__
-	_AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_CRTIME, uint32(st.st_crtime));
+		_AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_CRTIME, uint32(st.st_crtime));
 #else
-	_AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_CRTIME, uint32(st.st_mtime));
+		_AddAttribute(B_HPKG_ATTRIBUTE_ID_FILE_CRTIME, uint32(st.st_mtime));
 #endif
-	// TODO: File user/group!
+		// TODO: File user/group!
 
-	// add file data/symlink path
-	if (S_ISREG(st.st_mode)) {
-		// regular file -- add data
-		if (st.st_size > 0) {
-			BFDDataReader dataReader(fd);
-			status_t error = _AddData(dataReader, st.st_size);
-			if (error != B_OK)
-				throw status_t(error);
-		}
-	} else if (S_ISLNK(st.st_mode)) {
-		// symlink -- add link address
-		char path[B_PATH_NAME_LENGTH + 1];
-		ssize_t bytesRead = readlinkat(dirFD, fileName, path,
-			B_PATH_NAME_LENGTH);
-		if (bytesRead < 0) {
-			fListener->PrintError("Failed to read symlink \"%s\": %s\n",
-				pathBuffer, strerror(errno));
-			throw status_t(errno);
-		}
+		// add file data/symlink path
+		if (S_ISREG(st.st_mode)) {
+			// regular file -- add data
+			if (st.st_size > 0) {
+				BFDDataReader dataReader(fd);
+				status_t error = _AddData(dataReader, st.st_size);
+				if (error != B_OK)
+					throw status_t(error);
+			}
+		} else if (S_ISLNK(st.st_mode)) {
+			// symlink -- add link address
+			char path[B_PATH_NAME_LENGTH + 1];
+			ssize_t bytesRead = readlinkat(dirFD, fileName, path,
+				B_PATH_NAME_LENGTH);
+			if (bytesRead < 0) {
+				fListener->PrintError("Failed to read symlink \"%s\": %s\n",
+					pathBuffer, strerror(errno));
+				throw status_t(errno);
+			}
 
-		path[bytesRead] = '\0';
-		_AddStringAttribute(B_HPKG_ATTRIBUTE_ID_SYMLINK_PATH, path);
+			path[bytesRead] = '\0';
+			_AddStringAttribute(B_HPKG_ATTRIBUTE_ID_SYMLINK_PATH, path);
+		}
 	}
 
 	// add attributes

From 76ca98339d0b98f4f3c17c510ddcf134bb001cab Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 3 Jul 2011 11:24:56 +0200
Subject: [PATCH 0218/1170] Postpone setting gBootDevice until after packagefs

The modules code uses gBootDevice as an indicator that modules can be
loaded from the boot volume. This is not the case until packagefs has
been mounted, though, so we postpone setting gBootDevice.
---
 src/system/kernel/fs/vfs_boot.cpp | 14 ++++++++++----
 1 file changed, 10 insertions(+), 4 deletions(-)

diff --git a/src/system/kernel/fs/vfs_boot.cpp b/src/system/kernel/fs/vfs_boot.cpp
index cd1e681327..f7657ab45d 100644
--- a/src/system/kernel/fs/vfs_boot.cpp
+++ b/src/system/kernel/fs/vfs_boot.cpp
@@ -469,6 +469,8 @@ vfs_mount_boot_file_system(kernel_args* args)
 		panic("did not find any boot partitions!");
 	}
 
+	dev_t bootDevice = -1;
+
 	KPartition* bootPartition;
 	while (partitions.Pop(&bootPartition)) {
 		KPath path;
@@ -487,21 +489,22 @@ vfs_mount_boot_file_system(kernel_args* args)
 		}
 
 		TRACE(("trying to mount boot partition: %s\n", path.Path()));
-		gBootDevice = _kern_mount("/boot", path.Path(), fsName, 0, NULL, 0);
-		if (gBootDevice >= 0) {
+
+		bootDevice = _kern_mount("/boot", path.Path(), fsName, 0, NULL, 0);
+		if (bootDevice >= 0) {
 			dprintf("Mounted boot partition: %s\n", path.Path());
 			gReadOnlyBootDevice = readOnly;
 			break;
 		}
 	}
 
-	if (gBootDevice < B_OK)
+	if (bootDevice < B_OK)
 		panic("could not mount boot device!\n");
 
 	// create link for the name of the boot device
 
 	fs_info info;
-	if (_kern_read_fs_info(gBootDevice, &info) == B_OK) {
+	if (_kern_read_fs_info(bootDevice, &info) == B_OK) {
 		char path[B_FILE_NAME_LENGTH + 1];
 		snprintf(path, sizeof(path), "/%s", info.volume_name);
 
@@ -531,6 +534,9 @@ vfs_mount_boot_file_system(kernel_args* args)
 		}
 	}
 
+	// Now that packagefs is mounted, the boot volume is really ready.
+	gBootDevice = bootDevice;
+
 	// Do post-boot-volume module initialization. The module code wants to know
 	// whether the module images the boot loader has pre-loaded are the same as
 	// on the boot volume. That is the case when booting from hard disk or CD,

From b750c6bf71ae381ed7f6d84585dd8009f35fe300 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 4 Jul 2011 18:48:47 +0200
Subject: [PATCH 0219/1170] Fix Dependency version comparisons

---
 src/add-ons/kernel/file_systems/packagefs/Dependency.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp
index 8bf1c17741..c4c34a4132 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Dependency.cpp
@@ -58,7 +58,7 @@ Dependency::ResolvableVersionMatches(Version* resolvableVersion) const
 		return true;
 
 	return resolvableVersion != NULL
-		&& fVersion->Compare(fVersionOperator, *resolvableVersion);
+		&& resolvableVersion->Compare(fVersionOperator, *fVersion);
 }
 
 
@@ -75,7 +75,7 @@ Dependency::ResolvableCompatibleVersionMatches(Version* resolvableVersion) const
 	if (fVersionOperator == B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL
 		|| fVersionOperator == B_PACKAGE_RESOLVABLE_OP_GREATER) {
 		return resolvableVersion != NULL
-			&& fVersion->Compare(fVersionOperator, *resolvableVersion);
+			&& fVersion->Compare(*resolvableVersion) >= 0;
 	}
 
 	return true;

From a77ad30938d369e45cb172ec6a5d718d78e61ec6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 4 Jul 2011 18:49:13 +0200
Subject: [PATCH 0220/1170] Fix loading the resolvable compatible version

---
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 53c4e4f33e..ba772f23cb 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -326,7 +326,8 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
 						= value.resolvable.compatibleVersion;
 					status_t error = Version::Create(versionInfo.major,
 						versionInfo.minor, versionInfo.micro,
-						versionInfo.preRelease, versionInfo.release, version);
+						versionInfo.preRelease, versionInfo.release,
+						compatibleVersion);
 					if (error != B_OK)
 						RETURN_ERROR(error);
 				}

From b5831cdf17727e08d6c1e6d28ded5d9a5275d844 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 4 Jul 2011 19:53:24 +0200
Subject: [PATCH 0221/1170] Disable WonderBrush until repackaged

---
 build/jam/OptionalPackages | 11 ++++++-----
 1 file changed, 6 insertions(+), 5 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 60eac94043..80dcf07356 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -1648,11 +1648,12 @@ if [ IsOptionalHaikuImagePackageAdded WonderBrush ] {
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		Echo "No optional package WonderBrush available for gcc4" ;
 	} else {
-		InstallOptionalHaikuImagePackage WonderBrush-2.1.2.zip
-			: $(baseURL)/WonderBrush-2.1.2-x86-gcc2-2008-11-08.zip
-			: apps ;
-		AddSymlinkToHaikuImage home config be Applications
-			: /boot/apps/WonderBrush/WonderBrush ;
+# TODO: Package as HPKG!
+#		InstallOptionalHaikuImagePackage WonderBrush-2.1.2.zip
+#			: $(baseURL)/WonderBrush-2.1.2-x86-gcc2-2008-11-08.zip
+#			: common apps ;
+#		AddSymlinkToHaikuImage home config be Applications
+#			: /boot/apps/WonderBrush/WonderBrush ;
 	}
 }
 

From b489481920ca9974bae86b70871f1757e7a31db6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 4 Jul 2011 19:53:44 +0200
Subject: [PATCH 0222/1170] Create /boot/apps and /boot/preferences symlinks

---
 build/jam/HaikuImage | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage
index 4393b38964..b3c53aa720 100644
--- a/build/jam/HaikuImage
+++ b/build/jam/HaikuImage
@@ -201,6 +201,8 @@ include [ FDirName $(HAIKU_BUILD_RULES_DIR) HaikuPackages ] ;
 AddFilesToHaikuImage system packages : haiku.hpkg ;
 
 
+AddSymlinkToHaikuImage . : /boot/common/apps ;
+AddSymlinkToHaikuImage . : /boot/common/preferences ;
 AddSymlinkToHaikuImage home Desktop : /boot/home : Home ;
 
 # Mailbox folders and symlink

From 7210d7aa5879a9aa5ede74478cd544e6f377239d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 5 Jul 2011 22:25:12 +0200
Subject: [PATCH 0223/1170] Create a generalized version of BFS's query code

The new version is templatized over a QueryPolicy which provides the
interface to the file system specifics.
---
 headers/private/file_systems/QueryParser.h | 1919 ++++++++++++++++++++
 1 file changed, 1919 insertions(+)
 create mode 100644 headers/private/file_systems/QueryParser.h

diff --git a/headers/private/file_systems/QueryParser.h b/headers/private/file_systems/QueryParser.h
new file mode 100644
index 0000000000..05d82ca7e2
--- /dev/null
+++ b/headers/private/file_systems/QueryParser.h
@@ -0,0 +1,1919 @@
+/*
+ * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2010, Clemens Zeidler 
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * This file may be used under the terms of the MIT License.
+ */
+#ifndef _FILE_SYSTEMS_QUERY_H
+#define _FILE_SYSTEMS_QUERY_H
+
+
+/*!	Query parsing and evaluation
+
+	The pattern matching is roughly based on code originally written
+	by J. Kercheval, and on code written by Kenneth Almquist, though
+	it shares no code.
+*/
+
+
+// The parser has a very static design, but it will do what is required.
+//
+// ParseOr(), ParseAnd(), ParseEquation() are guarantying the operator
+// precedence, that is =,!=,>,<,>=,<= .. && .. ||.
+// Apparently, the "!" (not) can only be used with brackets.
+//
+// If you think that there are too few NULL pointer checks in some places
+// of the code, just read the beginning of the query constructor.
+// The API is not fully available, just the Query and the Expression class
+// are.
+
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include 
+
+#include 
+
+
+//#define DEBUG_QUERY
+
+#ifndef QUERY_RETURN_ERROR
+#	define QUERY_RETURN_ERROR(error)	return (error)
+#endif
+
+#ifndef QUERY_REPORT_ERROR
+#	define QUERY_REPORT_ERROR(error)	do {} while (false)
+#endif
+
+#ifndef QUERY_FATAL
+#	define QUERY_FATAL(message...)		panic(message)
+#endif
+
+#ifndef QUERY_INFORM
+#	define QUERY_INFORM(message...)		dprintf(message)
+#endif
+
+#ifndef QUERY_D
+#	define QUERY_D(block)
+#endif
+
+
+namespace QueryParser {
+
+
+template class Equation;
+template class Expression;
+template class Term;
+template class Query;
+
+
+enum ops {
+	OP_NONE,
+
+	OP_AND,
+	OP_OR,
+
+	OP_EQUATION,
+		// is only used for invalid equations
+
+	OP_EQUAL,
+	OP_UNEQUAL,
+	OP_GREATER_THAN,
+	OP_LESS_THAN,
+	OP_GREATER_THAN_OR_EQUAL,
+	OP_LESS_THAN_OR_EQUAL,
+};
+
+enum match {
+	NO_MATCH = 0,
+	MATCH_OK = 1,
+
+	MATCH_BAD_PATTERN = -2,
+	MATCH_INVALID_CHARACTER
+};
+
+// return values from isValidPattern()
+enum {
+	PATTERN_INVALID_ESCAPE = -3,
+	PATTERN_INVALID_RANGE,
+	PATTERN_INVALID_SET
+};
+
+template
+union value {
+	int64	Int64;
+	uint64	Uint64;
+	int32	Int32;
+	uint32	Uint32;
+	float	Float;
+	double	Double;
+	char	String[QueryPolicy::kMaxFileNameLength];
+};
+
+
+// B_MIME_STRING_TYPE is defined in storage/Mime.h, but we
+// don't need the whole file here; the type can't change anyway
+#ifndef _MIME_H
+#	define B_MIME_STRING_TYPE 'MIMS'
+#endif
+
+
+template
+class Query {
+public:
+			typedef typename QueryPolicy::Entry Entry;
+			typedef typename QueryPolicy::Index Index;
+			typedef typename QueryPolicy::IndexIterator IndexIterator;
+			typedef typename QueryPolicy::Node Node;
+			typedef typename QueryPolicy::Context Context;
+
+public:
+							Query(Context* context,
+								Expression* expression,
+								uint32 flags, port_id port, uint32 token);
+							~Query();
+
+	static	status_t		Create(Context* context, const char* queryString,
+								uint32 flags, port_id port, uint32 token,
+								Query*& _query);
+
+			status_t		Rewind();
+			status_t		GetNextEntry(struct dirent* , size_t size);
+
+			void			LiveUpdate(Entry* entry, Node* node,
+								const char* attribute, int32 type,
+								const uint8* oldKey, size_t oldLength,
+								const uint8* newKey, size_t newLength);
+			void			LiveUpdateRenameMove(Entry* entry, Node* node,
+								ino_t oldDirectoryID, const char* oldName,
+								size_t oldLength, ino_t newDirectoryID,
+								const char* newName, size_t newLength);
+
+			Expression* GetExpression() const
+								{ return fExpression; }
+
+			uint32			Flags() const
+								{ return fFlags; }
+
+private:
+			void			_SendEntryNotification(Entry* entry,
+								status_t (*notify)(port_id, int32, dev_t, ino_t,
+									const char*, ino_t));
+
+private:
+			Context*		fContext;
+			Expression* fExpression;
+			Equation* fCurrent;
+			IndexIterator*	fIterator;
+			Index			fIndex;
+			Stack*> fStack;
+
+			uint32			fFlags;
+			port_id			fPort;
+			int32			fToken;
+			bool			fNeedsEntry;
+};
+
+
+/*!	Abstract base class for the operator/equation classes.
+*/
+template
+class Term {
+public:
+			typedef typename QueryPolicy::Entry Entry;
+			typedef typename QueryPolicy::Index Index;
+			typedef typename QueryPolicy::IndexIterator IndexIterator;
+			typedef typename QueryPolicy::Node Node;
+			typedef typename QueryPolicy::Context Context;
+
+public:
+						Term(int8 op) : fOp(op), fParent(NULL) {}
+	virtual				~Term() {}
+
+			int8		Op() const { return fOp; }
+
+			void		SetParent(Term* parent)
+							{ fParent = parent; }
+			Term* Parent() const { return fParent; }
+
+	virtual	status_t	Match(Entry* entry, Node* node,
+							const char* attribute = NULL, int32 type = 0,
+							const uint8* key = NULL, size_t size = 0) = 0;
+	virtual	void		Complement() = 0;
+
+	virtual	void		CalculateScore(Index& index) = 0;
+	virtual	int32		Score() const = 0;
+
+	virtual	status_t	InitCheck() = 0;
+
+	virtual	bool		NeedsEntry() = 0;
+
+#ifdef DEBUG_QUERY
+	virtual	void		PrintToStream() = 0;
+#endif
+
+protected:
+			int8		fOp;
+			Term* fParent;
+};
+
+
+/*!	An Equation object represents an "attribute-equation operator-value" pair.
+
+	Although an Equation object is quite independent from the volume on which
+	the query is run, there are some dependencies that are produced while
+	querying:
+	The type/size of the value, the score, and if it has an index or not.
+	So you could run more than one query on the same volume, but it might return
+	wrong values when it runs concurrently on another volume.
+	That's not an issue right now, because we run single-threaded and don't use
+	queries more than once.
+*/
+template
+class Equation : public Term {
+public:
+			typedef typename QueryPolicy::Entry Entry;
+			typedef typename QueryPolicy::Index Index;
+			typedef typename QueryPolicy::IndexIterator IndexIterator;
+			typedef typename QueryPolicy::Node Node;
+			typedef typename QueryPolicy::Context Context;
+
+public:
+						Equation(char** expression);
+	virtual				~Equation();
+
+	virtual	status_t	InitCheck();
+
+			status_t	ParseQuotedString(char** _start, char** _end);
+			char*		CopyString(char* start, char* end);
+
+	virtual	status_t	Match(Entry* entry, Node* node,
+							const char* attribute = NULL, int32 type = 0,
+							const uint8* key = NULL, size_t size = 0);
+	virtual void		Complement();
+
+			status_t	PrepareQuery(Context* context, Index& index,
+							IndexIterator** iterator, bool queryNonIndexed);
+			status_t	GetNextMatching(Context* context,
+							IndexIterator* iterator, struct dirent* dirent,
+							size_t bufferSize);
+
+	virtual	void		CalculateScore(Index &index);
+	virtual	int32		Score() const { return fScore; }
+
+	virtual	bool		NeedsEntry();
+
+#ifdef DEBUG_QUERY
+	virtual	void		PrintToStream();
+#endif
+
+private:
+						Equation(const Equation& other);
+						Equation& operator=(const Equation& other);
+							// no implementation
+
+			status_t	ConvertValue(type_code type);
+			bool		CompareTo(const uint8* value, size_t size);
+			uint8*		Value() const { return (uint8*)&fValue; }
+			status_t	MatchEmptyString();
+
+			char*		fAttribute;
+			char*		fString;
+			union value fValue;
+			type_code	fType;
+			size_t		fSize;
+			bool		fIsPattern;
+
+			int32		fScore;
+			bool		fHasIndex;
+};
+
+
+/*!	The Operator class does not represent a generic operator, but only those
+	that combine two equations, namely "or", and "and".
+*/
+template
+class Operator : public Term {
+public:
+			typedef typename QueryPolicy::Entry Entry;
+			typedef typename QueryPolicy::Index Index;
+			typedef typename QueryPolicy::IndexIterator IndexIterator;
+			typedef typename QueryPolicy::Node Node;
+			typedef typename QueryPolicy::Context Context;
+
+public:
+						Operator(Term* left, int8 op,
+							Term* right);
+	virtual				~Operator();
+
+			Term* Left() const { return fLeft; }
+			Term* Right() const { return fRight; }
+
+	virtual	status_t	Match(Entry* entry, Node* node,
+							const char* attribute = NULL, int32 type = 0,
+							const uint8* key = NULL, size_t size = 0);
+	virtual	void		Complement();
+
+	virtual	void		CalculateScore(Index& index);
+	virtual	int32		Score() const;
+
+	virtual	status_t	InitCheck();
+
+	virtual	bool		NeedsEntry();
+
+#ifdef DEBUG_QUERY
+	virtual	void		PrintToStream();
+#endif
+
+private:
+						Operator(const Operator& other);
+						Operator& operator=(const Operator& other);
+							// no implementation
+
+			Term* fLeft;
+			Term* fRight;
+};
+
+
+template
+class Expression {
+public:
+			typedef typename QueryPolicy::Entry Entry;
+			typedef typename QueryPolicy::Index Index;
+			typedef typename QueryPolicy::IndexIterator IndexIterator;
+			typedef typename QueryPolicy::Node Node;
+			typedef typename QueryPolicy::Context Context;
+
+public:
+							Expression(char* expr);
+							~Expression();
+
+			status_t		InitCheck();
+			const char*		Position() const { return fPosition; }
+			Term* Root() const { return fTerm; }
+
+protected:
+			Term* ParseOr(char** expr);
+			Term* ParseAnd(char** expr);
+			Term* ParseEquation(char** expr);
+
+			bool			IsOperator(char** expr, char op);
+
+private:
+							Expression(const Expression& other);
+							Expression& operator=(const Expression& other);
+								// no implementation
+
+			char*			fPosition;
+			Term* fTerm;
+};
+
+
+//	#pragma mark -
+
+
+void
+skipWhitespace(char** expr, int32 skip = 0)
+{
+	char* string = (*expr) + skip;
+	while (*string == ' ' || *string == '\t') string++;
+	*expr = string;
+}
+
+
+void
+skipWhitespaceReverse(char** expr, char* stop)
+{
+	char* string = *expr;
+	while (string > stop && (*string == ' ' || *string == '\t'))
+		string--;
+	*expr = string;
+}
+
+
+// compare_integral
+template
+static inline
+int
+compare_integral(const Key &a, const Key &b)
+{
+	if (a < b)
+		return -1;
+	else if (a > b)
+		return 1;
+	return 0;
+}
+
+// compare_keys
+static
+int
+compare_keys(const uint8 *key1, size_t length1, const uint8 *key2,
+			 size_t length2, uint32 type)
+{
+	switch (type) {
+		case B_INT32_TYPE:
+			return compare_integral(*(int32*)key1, *(int32*)key2);
+		case B_UINT32_TYPE:
+			return compare_integral(*(uint32*)key1, *(uint32*)key2);
+		case B_INT64_TYPE:
+			return compare_integral(*(int64*)key1, *(int64*)key2);
+		case B_UINT64_TYPE:
+			return compare_integral(*(uint64*)key1, *(uint64*)key2);
+		case B_FLOAT_TYPE:
+			return compare_integral(*(float*)key1, *(float*)key2);
+		case B_DOUBLE_TYPE:
+			return compare_integral(*(double*)key1, *(double*)key2);
+		case B_STRING_TYPE:
+		{
+			int result = strncmp((const char*)key1, (const char*)key2,
+				std::min(length1, length2));
+			if (result == 0) {
+				result = compare_integral(strnlen((const char*)key1, length1),
+					strnlen((const char*)key2, length2));
+			}
+			return result;
+		}
+	}
+	return -1;
+}
+
+// compareKeys
+static inline
+int
+compareKeys(uint32 type, const uint8 *key1, size_t length1, const uint8 *key2,
+			size_t length2)
+{
+	return compare_keys(key1, length1, key2, length2, type);
+}
+
+
+//	#pragma mark -
+
+
+uint32
+utf8ToUnicode(char** string)
+{
+	uint8* bytes = (uint8*)*string;
+	int32 length;
+	uint8 mask = 0x1f;
+
+	switch (bytes[0] & 0xf0) {
+		case 0xc0:
+		case 0xd0:
+			length = 2;
+			break;
+		case 0xe0:
+			length = 3;
+			break;
+		case 0xf0:
+			mask = 0x0f;
+			length = 4;
+			break;
+		default:
+			// valid 1-byte character
+			// and invalid characters
+			(*string)++;
+			return bytes[0];
+	}
+	uint32 c = bytes[0] & mask;
+	int32 i = 1;
+	for (; i < length && (bytes[i] & 0x80) > 0; i++)
+		c = (c << 6) | (bytes[i] & 0x3f);
+
+	if (i < length) {
+		// invalid character
+		(*string)++;
+		return (uint32)bytes[0];
+	}
+	*string += length;
+	return c;
+}
+
+
+int32
+getFirstPatternSymbol(char* string)
+{
+	char c;
+
+	for (int32 index = 0; (c = *string++); index++) {
+		if (c == '*' || c == '?' || c == '[')
+			return index;
+	}
+	return -1;
+}
+
+
+bool
+isPattern(char* string)
+{
+	return getFirstPatternSymbol(string) >= 0 ? true : false;
+}
+
+
+status_t
+isValidPattern(char* pattern)
+{
+	while (*pattern) {
+		switch (*pattern++) {
+			case '\\':
+				// the escape character must not be at the end of the pattern
+				if (!*pattern++)
+					return PATTERN_INVALID_ESCAPE;
+				break;
+
+			case '[':
+				if (pattern[0] == ']' || !pattern[0])
+					return PATTERN_INVALID_SET;
+
+				while (*pattern != ']') {
+					if (*pattern == '\\' && !*++pattern)
+						return PATTERN_INVALID_ESCAPE;
+
+					if (!*pattern)
+						return PATTERN_INVALID_SET;
+
+					if (pattern[0] == '-' && pattern[1] == '-')
+						return PATTERN_INVALID_RANGE;
+
+					pattern++;
+				}
+				break;
+		}
+	}
+	return B_OK;
+}
+
+
+/*!	Matches the string against the given wildcard pattern.
+	Returns either MATCH_OK, or NO_MATCH when everything went fine, or
+	values < 0 (see enum at the top of Query.cpp) if an error occurs.
+*/
+status_t
+matchString(char* pattern, char* string)
+{
+	while (*pattern) {
+		// end of string == valid end of pattern?
+		if (!string[0]) {
+			while (pattern[0] == '*')
+				pattern++;
+			return !pattern[0] ? MATCH_OK : NO_MATCH;
+		}
+
+		switch (*pattern++) {
+			case '?':
+			{
+				// match exactly one UTF-8 character; we are
+				// not interested in the result
+				utf8ToUnicode(&string);
+				break;
+			}
+
+			case '*':
+			{
+				// compact pattern
+				while (true) {
+					if (pattern[0] == '?') {
+						if (!*++string)
+							return NO_MATCH;
+					} else if (pattern[0] != '*')
+						break;
+
+					pattern++;
+				}
+
+				// if the pattern is done, we have matched the string
+				if (!pattern[0])
+					return MATCH_OK;
+
+				while(true) {
+					// we have removed all occurences of '*' and '?'
+					if (pattern[0] == string[0]
+						|| pattern[0] == '['
+						|| pattern[0] == '\\') {
+						status_t status = matchString(pattern, string);
+						if (status < B_OK || status == MATCH_OK)
+							return status;
+					}
+
+					// we could be nice here and just jump to the next
+					// UTF-8 character - but we wouldn't gain that much
+					// and it'd be slower (since we're checking for
+					// equality before entering the recursion)
+					if (!*++string)
+						return NO_MATCH;
+				}
+				break;
+			}
+
+			case '[':
+			{
+				bool invert = false;
+				if (pattern[0] == '^' || pattern[0] == '!') {
+					invert = true;
+					pattern++;
+				}
+
+				if (!pattern[0] || pattern[0] == ']')
+					return MATCH_BAD_PATTERN;
+
+				uint32 c = utf8ToUnicode(&string);
+				bool matched = false;
+
+				while (pattern[0] != ']') {
+					if (!pattern[0])
+						return MATCH_BAD_PATTERN;
+
+					if (pattern[0] == '\\')
+						pattern++;
+
+					uint32 first = utf8ToUnicode(&pattern);
+
+					// Does this character match, or is this a range?
+					if (first == c) {
+						matched = true;
+						break;
+					} else if (pattern[0] == '-' && pattern[1] != ']'
+							&& pattern[1]) {
+						pattern++;
+
+						if (pattern[0] == '\\') {
+							pattern++;
+							if (!pattern[0])
+								return MATCH_BAD_PATTERN;
+						}
+						uint32 last = utf8ToUnicode(&pattern);
+
+						if (c >= first && c <= last) {
+							matched = true;
+							break;
+						}
+					}
+				}
+
+				if (invert)
+					matched = !matched;
+
+				if (matched) {
+					while (pattern[0] != ']') {
+						if (!pattern[0])
+							return MATCH_BAD_PATTERN;
+						pattern++;
+					}
+					pattern++;
+					break;
+				}
+				return NO_MATCH;
+			}
+
+            case '\\':
+				if (!pattern[0])
+					return MATCH_BAD_PATTERN;
+				// supposed to fall through
+			default:
+				if (pattern[-1] != string[0])
+					return NO_MATCH;
+				string++;
+				break;
+		}
+	}
+
+	if (string[0])
+		return NO_MATCH;
+
+	return MATCH_OK;
+}
+
+
+//	#pragma mark -
+
+
+template
+Equation::Equation(char** expr)
+	:
+	Term(OP_EQUATION),
+	fAttribute(NULL),
+	fString(NULL),
+	fType(0),
+	fIsPattern(false)
+{
+	char* string = *expr;
+	char* start = string;
+	char* end = NULL;
+
+	// Since the equation is the integral part of any query, we're just parsing
+	// the whole thing here.
+	// The whitespace at the start is already removed in
+	// Expression::ParseEquation()
+
+	if (*start == '"' || *start == '\'') {
+		// string is quoted (start has to be on the beginning of a string)
+		if (ParseQuotedString(&start, &end) < B_OK)
+			return;
+
+		// set string to a valid start of the equation symbol
+		string = end + 2;
+		skipWhitespace(&string);
+		if (*string != '=' && *string != '<' && *string != '>'
+			&& *string != '!') {
+			*expr = string;
+			return;
+		}
+	} else {
+		// search the (in)equation for the actual equation symbol (and for other operators
+		// in case the equation is malformed)
+		while (*string && *string != '=' && *string != '<' && *string != '>'
+			&& *string != '!' && *string != '&' && *string != '|') {
+			string++;
+		}
+
+		// get the attribute string	(and trim whitespace), in case
+		// the string was not quoted
+		end = string - 1;
+		skipWhitespaceReverse(&end, start);
+	}
+
+	// attribute string is empty (which is not allowed)
+	if (start > end)
+		return;
+
+	// At this point, "start" points to the beginning of the string, "end"
+	// points to the last character of the string, and "string" points to the
+	// first character of the equation symbol
+
+	// test for the right symbol (as this doesn't need any memory)
+	switch (*string) {
+		case '=':
+			Term::fOp = OP_EQUAL;
+			break;
+		case '>':
+			Term::fOp = *(string + 1) == '='
+				? OP_GREATER_THAN_OR_EQUAL : OP_GREATER_THAN;
+			break;
+		case '<':
+			Term::fOp = *(string + 1) == '='
+				? OP_LESS_THAN_OR_EQUAL : OP_LESS_THAN;
+			break;
+		case '!':
+			if (*(string + 1) != '=')
+				return;
+			Term::fOp = OP_UNEQUAL;
+			break;
+
+		// any invalid characters will be rejected
+		default:
+			*expr = string;
+			return;
+	}
+
+	// lets change "start" to point to the first character after the symbol
+	if (*(string + 1) == '=')
+		string++;
+	string++;
+	skipWhitespace(&string);
+
+	// allocate & copy the attribute string
+
+	fAttribute = CopyString(start, end);
+	if (fAttribute == NULL)
+		return;
+
+	start = string;
+	if (*start == '"' || *start == '\'') {
+		// string is quoted (start has to be on the beginning of a string)
+		if (ParseQuotedString(&start, &end) < B_OK)
+			return;
+
+		string = end + 2;
+		skipWhitespace(&string);
+	} else {
+		while (*string && *string != '&' && *string != '|' && *string != ')')
+			string++;
+
+		end = string - 1;
+		skipWhitespaceReverse(&end, start);
+	}
+
+	// at this point, "start" will point to the first character of the value,
+	// "end" will point to its last character, and "start" to the first non-
+	// whitespace character after the value string
+
+	fString = CopyString(start, end);
+	if (fString == NULL)
+		return;
+
+	// patterns are only allowed for these operations (and strings)
+	if (Term::fOp == OP_EQUAL
+		|| Term::fOp == OP_UNEQUAL) {
+		fIsPattern = isPattern(fString);
+		if (fIsPattern && isValidPattern(fString) < B_OK) {
+			// we only want to have valid patterns; setting fString
+			// to NULL will cause InitCheck() to fail
+			free(fString);
+			fString = NULL;
+		}
+	}
+
+	*expr = string;
+}
+
+
+template
+Equation::~Equation()
+{
+	free(fAttribute);
+	free(fString);
+}
+
+
+template
+status_t
+Equation::InitCheck()
+{
+	if (fAttribute == NULL || fString == NULL
+		|| Term::fOp == OP_NONE) {
+		return B_BAD_VALUE;
+	}
+
+	return B_OK;
+}
+
+
+template
+status_t
+Equation::ParseQuotedString(char** _start, char** _end)
+{
+	char* start = *_start;
+	char quote = *start++;
+	char* end = start;
+
+	for (; *end && *end != quote; end++) {
+		if (*end == '\\')
+			end++;
+	}
+	if (*end == '\0')
+		return B_BAD_VALUE;
+
+	*_start = start;
+	*_end = end - 1;
+
+	return B_OK;
+}
+
+
+template
+char*
+Equation::CopyString(char* start, char* end)
+{
+	// end points to the last character of the string - and the length
+	// also has to include the null-termination
+	int32 length = end + 2 - start;
+	// just to make sure; since that's the max. attribute name length and
+	// the max. string in an index, it make sense to have it that way
+	if (length > QueryPolicy::kMaxFileNameLength || length <= 0)
+		return NULL;
+
+	char* copy = (char*)malloc(length);
+	if (copy == NULL)
+		return NULL;
+
+	memcpy(copy, start, length - 1);
+	copy[length - 1] = '\0';
+
+	return copy;
+}
+
+
+template
+status_t
+Equation::ConvertValue(type_code type)
+{
+	// Has the type already been converted?
+	if (type == fType)
+		return B_OK;
+
+	char* string = fString;
+
+	switch (type) {
+		case B_MIME_STRING_TYPE:
+			type = B_STRING_TYPE;
+			// supposed to fall through
+		case B_STRING_TYPE:
+			strncpy(fValue.String, string, QueryPolicy::kMaxFileNameLength);
+			fValue.String[QueryPolicy::kMaxFileNameLength - 1] = '\0';
+			fSize = strlen(fValue.String);
+			break;
+		case B_INT32_TYPE:
+			fValue.Int32 = strtol(string, &string, 0);
+			fSize = sizeof(int32);
+			break;
+		case B_UINT32_TYPE:
+			fValue.Int32 = strtoul(string, &string, 0);
+			fSize = sizeof(uint32);
+			break;
+		case B_INT64_TYPE:
+			fValue.Int64 = strtoll(string, &string, 0);
+			fSize = sizeof(int64);
+			break;
+		case B_UINT64_TYPE:
+			fValue.Uint64 = strtoull(string, &string, 0);
+			fSize = sizeof(uint64);
+			break;
+		case B_FLOAT_TYPE:
+			fValue.Float = strtod(string, &string);
+			fSize = sizeof(float);
+			break;
+		case B_DOUBLE_TYPE:
+			fValue.Double = strtod(string, &string);
+			fSize = sizeof(double);
+			break;
+		default:
+			QUERY_FATAL("query value conversion to 0x%x requested!\n",
+				(int)type);
+			// should we fail here or just do a safety int32 conversion?
+			return B_ERROR;
+	}
+
+	fType = type;
+
+	// patterns are only allowed for string types
+	if (fType != B_STRING_TYPE && fIsPattern)
+		fIsPattern = false;
+
+	return B_OK;
+}
+
+
+/*!	Returns true when the key matches the equation. You have to
+	call ConvertValue() before this one.
+*/
+template
+bool
+Equation::CompareTo(const uint8* value, size_t size)
+{
+	int32 compare;
+
+	// fIsPattern is only true if it's a string type, and fOp OP_EQUAL, or
+	// OP_UNEQUAL
+	if (fIsPattern) {
+		// we have already validated the pattern, so we don't check for failing
+		// here - if something is broken, and matchString() returns an error,
+		// we just don't match
+		compare = matchString(fValue.String, (char*)value) == MATCH_OK ? 0 : 1;
+	} else
+		compare = compareKeys(fType, value, size, Value(), fSize);
+
+	switch (Term::fOp) {
+		case OP_EQUAL:
+			return compare == 0;
+		case OP_UNEQUAL:
+			return compare != 0;
+		case OP_LESS_THAN:
+			return compare < 0;
+		case OP_LESS_THAN_OR_EQUAL:
+			return compare <= 0;
+		case OP_GREATER_THAN:
+			return compare > 0;
+		case OP_GREATER_THAN_OR_EQUAL:
+			return compare >= 0;
+	}
+	QUERY_FATAL("Unknown/Unsupported operation: %d\n", Term::fOp);
+	return false;
+}
+
+
+template
+void
+Equation::Complement()
+{
+	QUERY_D(if (fOp <= OP_EQUATION || fOp > OP_LESS_THAN_OR_EQUAL) {
+		QUERY_FATAL("op out of range!\n");
+		return;
+	});
+
+	int8 complementOp[] = {OP_UNEQUAL, OP_EQUAL, OP_LESS_THAN_OR_EQUAL,
+			OP_GREATER_THAN_OR_EQUAL, OP_LESS_THAN, OP_GREATER_THAN};
+	Term::fOp = complementOp[Term::fOp - OP_EQUAL];
+}
+
+
+template
+status_t
+Equation::MatchEmptyString()
+{
+	// There is no matching attribute, we will just bail out if we
+	// already know that our value is not of a string type.
+	// If not, it will be converted to a string - and then be compared with "".
+	// That's why we have to call ConvertValue() here - but it will be
+	// a cheap call for the next time
+	// TODO: Should we do this only for OP_UNEQUAL?
+	if (fType != 0 && fType != B_STRING_TYPE)
+		return NO_MATCH;
+
+	status_t status = ConvertValue(B_STRING_TYPE);
+	if (status == B_OK)
+		status = CompareTo((const uint8*)"", fSize) ? MATCH_OK : NO_MATCH;
+
+	return status;
+}
+
+
+/*!	Matches the node's attribute value with the equation.
+	Returns MATCH_OK if it matches, NO_MATCH if not, < 0 if something went
+	wrong.
+*/
+template
+status_t
+Equation::Match(Entry* entry, Node* node,
+	const char* attributeName, int32 type, const uint8* key, size_t size)
+{
+	// get a pointer to the attribute in question
+	union value value;
+	uint8* buffer = (uint8*)&value;
+
+	// first, check if we are matching for a live query and use that value
+	if (attributeName != NULL && !strcmp(fAttribute, attributeName)) {
+		if (key == NULL) {
+			if (type == B_STRING_TYPE)
+				return MatchEmptyString();
+
+			return NO_MATCH;
+		}
+		buffer = const_cast(key);
+	} else if (!strcmp(fAttribute, "name")) {
+		// if not, check for "fake" attributes ("name", "size", "last_modified")
+		if (entry == NULL)
+			return B_ERROR;
+		buffer = (uint8*)QueryPolicy::EntryGetNameNoCopy(entry, buffer,
+			sizeof(value));
+		if (buffer == NULL)
+			return B_ERROR;
+
+		type = B_STRING_TYPE;
+		size = strlen((const char*)buffer);
+	} else if (!strcmp(fAttribute, "size")) {
+		value.Int64 = QueryPolicy::NodeGetSize(node);
+		type = B_INT64_TYPE;
+	} else if (!strcmp(fAttribute, "last_modified")) {
+		value.Int64 = QueryPolicy::NodeGetLastModifiedTime(node);
+		type = B_INT64_TYPE;
+	} else {
+		// then for attributes
+		if (QueryPolicy::NodeGetAttribute(node, fAttribute, buffer, &size,
+				&type) != B_OK) {
+			return MatchEmptyString();
+		}
+	}
+
+	// prepare own value for use, if it is possible to convert it
+	status_t status = ConvertValue(type);
+	if (status == B_OK)
+		status = CompareTo(buffer, size) ? MATCH_OK : NO_MATCH;
+
+	QUERY_RETURN_ERROR(status);
+}
+
+
+template
+void
+Equation::CalculateScore(Index &index)
+{
+	// As always, these values could be tuned and refined.
+	// And the code could also need some real world testing :-)
+
+	// do we have to operate on a "foreign" index?
+	if (Term::fOp == OP_UNEQUAL
+		|| QueryPolicy::IndexSetTo(index, fAttribute) < B_OK) {
+		fScore = 0;
+		return;
+	}
+
+	// if we have a pattern, how much does it help our search?
+	if (fIsPattern)
+		fScore = getFirstPatternSymbol(fString) << 3;
+	else {
+		// Score by operator
+		if (Term::fOp == OP_EQUAL) {
+			// higher than pattern="255 chars+*"
+			fScore = 2048;
+		} else {
+			// the pattern search is regarded cheaper when you have at
+			// least one character to set your index to
+			fScore = 5;
+		}
+	}
+
+	// take index size into account
+	fScore = QueryPolicy::IndexGetWeightedScore(index, fScore);
+}
+
+
+template
+status_t
+Equation::PrepareQuery(Context* /*context*/, Index& index,
+	IndexIterator** iterator, bool queryNonIndexed)
+{
+	status_t status = QueryPolicy::IndexSetTo(index, fAttribute);
+
+	// if we should query attributes without an index, we can just proceed here
+	if (status != B_OK && !queryNonIndexed)
+		return B_ENTRY_NOT_FOUND;
+
+	type_code type;
+
+	// Special case for OP_UNEQUAL - it will always operate through the whole
+	// index but we need the call to the original index to get the correct type
+	if (status != B_OK || Term::fOp == OP_UNEQUAL) {
+		// Try to get an index that holds all files (name)
+		// Also sets the default type for all attributes without index
+		// to string.
+		type = status < B_OK ? B_STRING_TYPE : QueryPolicy::IndexGetType(index);
+
+		if (QueryPolicy::IndexSetTo(index, "name") != B_OK)
+			return B_ENTRY_NOT_FOUND;
+
+		fHasIndex = false;
+	} else {
+		fHasIndex = true;
+		type = QueryPolicy::IndexGetType(index);
+	}
+
+	if (ConvertValue(type) < B_OK)
+		return B_BAD_VALUE;
+
+	*iterator = QueryPolicy::IndexCreateIterator(index);
+	if (*iterator == NULL)
+		return B_NO_MEMORY;
+
+	if ((Term::fOp == OP_EQUAL
+			|| Term::fOp == OP_GREATER_THAN
+			|| Term::fOp == OP_GREATER_THAN_OR_EQUAL || fIsPattern)
+		&& fHasIndex) {
+		// set iterator to the exact position
+
+		int32 keySize = QueryPolicy::IndexGetKeySize(index);
+
+		// At this point, fIsPattern is only true if it's a string type, and fOp
+		// is either OP_EQUAL or OP_UNEQUAL
+		if (fIsPattern) {
+			// let's see if we can use the beginning of the key for positioning
+			// the iterator and adjust the key size; if not, just leave the
+			// iterator at the start and return success
+			keySize = getFirstPatternSymbol(fString);
+			if (keySize <= 0)
+				return B_OK;
+		}
+
+		if (keySize == 0) {
+			// B_STRING_TYPE doesn't have a fixed length, so it was set
+			// to 0 before - we compute the correct value here
+			if (fType == B_STRING_TYPE) {
+				keySize = strlen(fValue.String);
+
+				// The empty string is a special case - we normally don't check
+				// for the trailing null byte, in the case for the empty string
+				// we do it explicitly, because there can't be keys in the
+				// B+tree with a length of zero
+				if (keySize == 0)
+					keySize = 1;
+			} else
+				QUERY_RETURN_ERROR(B_ENTRY_NOT_FOUND);
+		}
+
+		status = QueryPolicy::IndexIteratorFind(*iterator, Value(), keySize);
+		if (Term::fOp == OP_EQUAL && !fIsPattern)
+			return status;
+		else if (status == B_ENTRY_NOT_FOUND
+			&& (fIsPattern || Term::fOp == OP_GREATER_THAN
+				|| Term::fOp == OP_GREATER_THAN_OR_EQUAL))
+			return B_OK;
+
+		QUERY_RETURN_ERROR(status);
+	}
+
+	return B_OK;
+}
+
+
+template
+status_t
+Equation::GetNextMatching(Context* context,
+	IndexIterator* iterator, struct dirent* dirent, size_t bufferSize)
+{
+	while (true) {
+		union value indexValue;
+		size_t keyLength;
+		Entry* entry = NULL;
+
+		status_t status = QueryPolicy::IndexIteratorGetNextEntry(iterator,
+			&indexValue, &keyLength, (size_t)sizeof(indexValue), &entry);
+		if (status != B_OK)
+			return status;
+
+		// only compare against the index entry when this is the correct
+		// index for the equation
+		if (fHasIndex && !CompareTo((uint8*)&indexValue, keyLength)) {
+			// They aren't equal? Let the operation decide what to do. Since
+			// we always start at the beginning of the index (or the correct
+			// position), only some needs to be stopped if the entry doesn't
+			// fit.
+			if (Term::fOp == OP_LESS_THAN
+				|| Term::fOp == OP_LESS_THAN_OR_EQUAL
+				|| (Term::fOp == OP_EQUAL && !fIsPattern))
+				return B_ENTRY_NOT_FOUND;
+
+			continue;
+		}
+
+		// TODO: check user permissions here - but which one?!
+		// we could filter out all those where we don't have
+		// read access... (we should check for every parent
+		// directory if the X_OK is allowed)
+		// Although it's quite expensive to open all parents,
+		// it's likely that the application that runs the
+		// query will do something similar (and we don't have
+		// to do it for root, either).
+
+		// go up in the tree until a &&-operator is found, and check if the
+		// node matches with the rest of the expression - we don't have to
+		// check ||-operators for that
+		Term* term = this;
+		status = MATCH_OK;
+
+		if (!fHasIndex)
+			status = Match(entry, QueryPolicy::EntryGetNode(entry));
+
+		while (term != NULL && status == MATCH_OK) {
+			Operator* parent
+				= (Operator*)term->Parent();
+			if (parent == NULL)
+				break;
+
+			if (parent->Op() == OP_AND) {
+				// choose the other child of the parent
+				Term* other = parent->Right();
+				if (other == term)
+					other = parent->Left();
+
+				if (other == NULL) {
+					QUERY_FATAL("&&-operator has only one child... "
+						"(parent = %p)\n", parent);
+					break;
+				}
+				status = other->Match(entry, QueryPolicy::EntryGetNode(entry));
+				if (status < 0) {
+					QUERY_REPORT_ERROR(status);
+					status = NO_MATCH;
+				}
+			}
+			term = (Term*)parent;
+		}
+
+		if (status == MATCH_OK) {
+			ssize_t nameLength = QueryPolicy::EntryGetName(entry,
+				dirent->d_name,
+				(const char*)dirent + bufferSize - dirent->d_name);
+			if (nameLength < 0)
+				QUERY_RETURN_ERROR(nameLength);
+
+			dirent->d_dev = QueryPolicy::ContextGetVolumeID(context);
+			dirent->d_ino = QueryPolicy::EntryGetNodeID(entry);
+			dirent->d_pdev = dirent->d_dev;
+			dirent->d_pino = QueryPolicy::EntryGetParentID(entry);
+			dirent->d_reclen = sizeof(struct dirent) + strlen(dirent->d_name);
+		}
+
+		if (status == MATCH_OK)
+			return B_OK;
+	}
+	QUERY_RETURN_ERROR(B_ERROR);
+}
+
+
+template
+bool
+Equation::NeedsEntry()
+{
+	return strcmp(fAttribute, "name") == 0;
+}
+
+
+//	#pragma mark -
+
+
+template
+Operator::Operator(Term* left, int8 op,
+	Term* right)
+	:
+	Term(op),
+	fLeft(left),
+	fRight(right)
+{
+	if (left)
+		left->SetParent(this);
+	if (right)
+		right->SetParent(this);
+}
+
+
+template
+Operator::~Operator()
+{
+	delete fLeft;
+	delete fRight;
+}
+
+
+template
+status_t
+Operator::Match(Entry* entry, Node* node, const char* attribute,
+	int32 type, const uint8* key, size_t size)
+{
+	if (Term::fOp == OP_AND) {
+		status_t status = fLeft->Match(entry, node, attribute, type, key,
+			size);
+		if (status != MATCH_OK)
+			return status;
+
+		return fRight->Match(entry, node, attribute, type, key, size);
+	} else {
+		// choose the term with the better score for OP_OR
+		Term* first;
+		Term* second;
+		if (fRight->Score() > fLeft->Score()) {
+			first = fLeft;
+			second = fRight;
+		} else {
+			first = fRight;
+			second = fLeft;
+		}
+
+		status_t status = first->Match(entry, node, attribute, type, key,
+			size);
+		if (status != NO_MATCH)
+			return status;
+
+		return second->Match(entry, node, attribute, type, key, size);
+	}
+}
+
+
+template
+void
+Operator::Complement()
+{
+	if (Term::fOp == OP_AND)
+		Term::fOp = OP_OR;
+	else
+		Term::fOp = OP_AND;
+
+	fLeft->Complement();
+	fRight->Complement();
+}
+
+
+template
+void
+Operator::CalculateScore(Index &index)
+{
+	fLeft->CalculateScore(index);
+	fRight->CalculateScore(index);
+}
+
+
+template
+int32
+Operator::Score() const
+{
+	if (Term::fOp == OP_AND) {
+		// return the one with the better score
+		if (fRight->Score() > fLeft->Score())
+			return fRight->Score();
+
+		return fLeft->Score();
+	}
+
+	// for OP_OR, be honest, and return the one with the worse score
+	if (fRight->Score() < fLeft->Score())
+		return fRight->Score();
+
+	return fLeft->Score();
+}
+
+
+template
+status_t
+Operator::InitCheck()
+{
+	if ((Term::fOp != OP_AND && Term::fOp != OP_OR)
+		|| fLeft == NULL || fLeft->InitCheck() < B_OK
+		|| fRight == NULL || fRight->InitCheck() < B_OK)
+		return B_ERROR;
+
+	return B_OK;
+}
+
+
+template
+bool
+Operator::NeedsEntry()
+{
+	return ((fLeft && fLeft->NeedsEntry()) || (fRight && fRight->NeedsEntry()));
+}
+
+
+//	#pragma mark -
+
+#ifdef DEBUG_QUERY
+
+template
+void
+Operator::PrintToStream()
+{
+	D(__out("( "));
+	if (fLeft != NULL)
+		fLeft->PrintToStream();
+
+	const char* op;
+	switch (Term::fOp) {
+		case OP_OR: op = "OR"; break;
+		case OP_AND: op = "AND"; break;
+		default: op = "?"; break;
+	}
+	D(__out(" %s ", op));
+
+	if (fRight != NULL)
+		fRight->PrintToStream();
+
+	D(__out(" )"));
+}
+
+
+template
+void
+Equation::PrintToStream()
+{
+	const char* symbol = "???";
+	switch (Term::fOp) {
+		case OP_EQUAL: symbol = "=="; break;
+		case OP_UNEQUAL: symbol = "!="; break;
+		case OP_GREATER_THAN: symbol = ">"; break;
+		case OP_GREATER_THAN_OR_EQUAL: symbol = ">="; break;
+		case OP_LESS_THAN: symbol = "<"; break;
+		case OP_LESS_THAN_OR_EQUAL: symbol = "<="; break;
+	}
+	D(__out("[\"%s\" %s \"%s\"]", fAttribute, symbol, fString));
+}
+
+#endif	// DEBUG_QUERY
+
+//	#pragma mark -
+
+
+template
+Expression::Expression(char* expr)
+{
+	if (expr == NULL)
+		return;
+
+	fTerm = ParseOr(&expr);
+	if (fTerm != NULL && fTerm->InitCheck() < B_OK) {
+		QUERY_FATAL("Corrupt tree in expression!\n");
+		delete fTerm;
+		fTerm = NULL;
+	}
+	QUERY_D(if (fTerm != NULL) {
+		fTerm->PrintToStream();
+		D(__out("\n"));
+		if (*expr != '\0')
+			PRINT(("Unexpected end of string: \"%s\"!\n", expr));
+	});
+	fPosition = expr;
+}
+
+
+template
+Expression::~Expression()
+{
+	delete fTerm;
+}
+
+
+template
+Term*
+Expression::ParseEquation(char** expr)
+{
+	skipWhitespace(expr);
+
+	bool _not = false;
+	if (**expr == '!') {
+		skipWhitespace(expr, 1);
+		if (**expr != '(')
+			return NULL;
+
+		_not = true;
+	}
+
+	if (**expr == ')') {
+		// shouldn't be handled here
+		return NULL;
+	} else if (**expr == '(') {
+		skipWhitespace(expr, 1);
+
+		Term* term = ParseOr(expr);
+
+		skipWhitespace(expr);
+
+		if (**expr != ')') {
+			delete term;
+			return NULL;
+		}
+
+		// If the term is negated, we just complement the tree, to get
+		// rid of the not, a.k.a. DeMorgan's Law.
+		if (_not)
+			term->Complement();
+
+		skipWhitespace(expr, 1);
+
+		return term;
+	}
+
+	Equation* equation
+		= new(std::nothrow) Equation(expr);
+	if (equation == NULL || equation->InitCheck() < B_OK) {
+		delete equation;
+		return NULL;
+	}
+	return equation;
+}
+
+
+template
+Term*
+Expression::ParseAnd(char** expr)
+{
+	Term* left = ParseEquation(expr);
+	if (left == NULL)
+		return NULL;
+
+	while (IsOperator(expr, '&')) {
+		Term* right = ParseAnd(expr);
+		Term* newParent = NULL;
+
+		if (right == NULL
+			|| (newParent = new(std::nothrow) Operator(left,
+				OP_AND, right)) == NULL) {
+			delete left;
+			delete right;
+
+			return NULL;
+		}
+		left = newParent;
+	}
+
+	return left;
+}
+
+
+template
+Term*
+Expression::ParseOr(char** expr)
+{
+	Term* left = ParseAnd(expr);
+	if (left == NULL)
+		return NULL;
+
+	while (IsOperator(expr, '|')) {
+		Term* right = ParseAnd(expr);
+		Term* newParent = NULL;
+
+		if (right == NULL
+			|| (newParent = new(std::nothrow) Operator(left, OP_OR,
+				right)) == NULL) {
+			delete left;
+			delete right;
+
+			return NULL;
+		}
+		left = newParent;
+	}
+
+	return left;
+}
+
+
+template
+bool
+Expression::IsOperator(char** expr, char op)
+{
+	char* string = *expr;
+
+	if (*string == op && *(string + 1) == op) {
+		*expr += 2;
+		return true;
+	}
+	return false;
+}
+
+
+template
+status_t
+Expression::InitCheck()
+{
+	if (fTerm == NULL)
+		return B_BAD_VALUE;
+
+	return B_OK;
+}
+
+
+//	#pragma mark -
+
+
+template
+Query::Query(Context* context, Expression* expression,
+	uint32 flags, port_id port, uint32 token)
+	:
+	fContext(context),
+	fExpression(expression),
+	fCurrent(NULL),
+	fIterator(NULL),
+	fIndex(context),
+	fFlags(flags),
+	fPort(port),
+	fToken(token),
+	fNeedsEntry(false)
+{
+	// If the expression has a valid root pointer, the whole tree has
+	// already passed the sanity check, so that we don't have to check
+	// every pointer
+	if (context == NULL || expression == NULL || expression->Root() == NULL)
+		return;
+
+	// create index on the stack and delete it afterwards
+	fExpression->Root()->CalculateScore(fIndex);
+	QueryPolicy::IndexUnset(fIndex);
+
+	fNeedsEntry = fExpression->Root()->NeedsEntry();
+
+	Rewind();
+}
+
+
+template
+Query::~Query()
+{
+	delete fExpression;
+}
+
+
+template
+/*static*/ status_t
+Query::Create(Context* context, const char* queryString,
+	uint32 flags, port_id port, uint32 token, Query*& _query)
+{
+	Expression* expression
+		= new(std::nothrow) Expression((char*)queryString);
+	if (expression == NULL)
+		QUERY_RETURN_ERROR(B_NO_MEMORY);
+
+	if (expression->InitCheck() != B_OK) {
+		QUERY_INFORM("Could not parse query \"%s\", stopped at: \"%s\"\n",
+			queryString, expression->Position());
+
+		delete expression;
+		QUERY_RETURN_ERROR(B_BAD_VALUE);
+	}
+
+	Query* query = new(std::nothrow) Query(context,
+		expression, flags, port, token);
+	if (query == NULL) {
+		delete expression;
+		QUERY_RETURN_ERROR(B_NO_MEMORY);
+	}
+
+	_query = query;
+	return B_OK;
+}
+
+
+template
+status_t
+Query::Rewind()
+{
+	// free previous stuff
+
+	fStack.MakeEmpty();
+
+	QueryPolicy::IndexIteratorDelete(fIterator);
+	fIterator = NULL;
+	fCurrent = NULL;
+
+	// put the whole expression on the stack
+
+	Stack*> stack;
+	stack.Push(fExpression->Root());
+
+	Term* term;
+	while (stack.Pop(&term)) {
+		if (term->Op() < OP_EQUATION) {
+			Operator* op = (Operator*)term;
+
+			if (op->Op() == OP_OR) {
+				stack.Push(op->Left());
+				stack.Push(op->Right());
+			} else {
+				// For OP_AND, we can use the scoring system to decide which
+				// path to add
+				if (op->Right()->Score() > op->Left()->Score())
+					stack.Push(op->Right());
+				else
+					stack.Push(op->Left());
+			}
+		} else if (term->Op() == OP_EQUATION
+			|| fStack.Push((Equation*)term) != B_OK)
+			QUERY_FATAL("Unknown term on stack or stack error\n");
+	}
+
+	return B_OK;
+}
+
+
+template
+status_t
+Query::GetNextEntry(struct dirent* dirent, size_t size)
+{
+	// If we don't have an equation to use yet/anymore, get a new one
+	// from the stack
+	while (true) {
+		if (fIterator == NULL) {
+			if (!fStack.Pop(&fCurrent)
+				|| fCurrent == NULL)
+				return B_ENTRY_NOT_FOUND;
+
+			status_t status = fCurrent->PrepareQuery(fContext, fIndex,
+				&fIterator, fFlags & B_QUERY_NON_INDEXED);
+			if (status == B_ENTRY_NOT_FOUND) {
+				// try next equation
+				continue;
+			}
+
+			if (status != B_OK)
+				return status;
+		}
+		if (fCurrent == NULL)
+			QUERY_RETURN_ERROR(B_ERROR);
+
+		status_t status = fCurrent->GetNextMatching(fContext, fIterator, dirent,
+			size);
+		if (status != B_OK) {
+			QueryPolicy::IndexIteratorDelete(fIterator);
+			fIterator = NULL;
+			fCurrent = NULL;
+		} else {
+			// only return if we have another entry
+			return B_OK;
+		}
+	}
+}
+
+
+template
+void
+Query::LiveUpdate(Entry* entry, Node* node, const char* attribute,
+	int32 type, const uint8* oldKey, size_t oldLength, const uint8* newKey,
+	size_t newLength)
+{
+	if (fPort < 0 || fExpression == NULL || attribute == NULL)
+		return;
+
+	// TODO: check if the attribute is part of the query at all...
+
+	// If no entry has been supplied, but the we need one for the evaluation
+	// (i.e. the "name" attribute is used), we invoke ourselves for all entries
+	// referring to the given node.
+	if (entry == NULL && fNeedsEntry) {
+		entry = QueryPolicy::NodeGetFirstReferrer(node);
+		while (entry) {
+			LiveUpdate(entry, node, attribute, type, oldKey, oldLength, newKey,
+				newLength);
+			entry = QueryPolicy::NodeGetNextReferrer(node, entry);
+		}
+		return;
+	}
+
+	status_t oldStatus = fExpression->Root()->Match(entry, node, attribute,
+		type, oldKey, oldLength);
+	status_t newStatus = fExpression->Root()->Match(entry, node, attribute,
+		type, newKey, newLength);
+
+	bool entryCreated = false;
+	bool stillInQuery = false;
+
+	if (oldStatus != MATCH_OK) {
+		if (newStatus != MATCH_OK) {
+			// nothing has changed
+			return;
+		}
+		entryCreated = true;
+	} else if (newStatus != MATCH_OK) {
+		// entry got removed
+		entryCreated = false;
+	} else if ((fFlags & B_ATTR_CHANGE_NOTIFICATION) != 0) {
+		// The entry stays in the query
+		stillInQuery = true;
+	} else
+		return;
+
+	// notify query listeners
+	status_t (*notify)(port_id, int32, dev_t, ino_t, const char*, ino_t);
+
+	if (stillInQuery)
+		notify = notify_query_attr_changed;
+	else if (entryCreated)
+		notify = notify_query_entry_created;
+	else
+		notify = notify_query_entry_removed;
+
+	if (entry != NULL) {
+		_SendEntryNotification(entry, notify);
+	} else {
+		entry = QueryPolicy::NodeGetFirstReferrer(node);
+		while (entry) {
+			_SendEntryNotification(entry, notify);
+			entry = QueryPolicy::NodeGetNextReferrer(node, entry);
+		}
+	}
+}
+
+
+template
+void
+Query::LiveUpdateRenameMove(Entry* entry, Node* node,
+	ino_t oldDirectoryID, const char* oldName, size_t oldLength,
+	ino_t newDirectoryID, const char* newName, size_t newLength)
+{
+	if (fPort < 0 || fExpression == NULL)
+		return;
+
+	// TODO: check if the attribute is part of the query at all...
+
+	status_t oldStatus = fExpression->Root()->Match(entry, node, "name",
+		B_STRING_TYPE, (const uint8*)oldName, oldLength);
+	status_t newStatus = fExpression->Root()->Match(entry, node, "name",
+		B_STRING_TYPE, (const uint8*)newName, newLength);
+
+	if (oldStatus != MATCH_OK || oldStatus != newStatus)
+		return;
+
+	// The entry stays in the query, notify query listeners about the rename
+	// or move
+
+	// We send a notification for the given entry, if any, or otherwise for
+	// all entries referring to the node;
+	if (entry != NULL) {
+		_SendEntryNotification(entry, notify_query_entry_removed);
+		_SendEntryNotification(entry, notify_query_entry_created);
+	} else {
+		entry = QueryPolicy::NodeGetFirstReferrer(node);
+		while (entry) {
+			_SendEntryNotification(entry, notify_query_entry_removed);
+			_SendEntryNotification(entry, notify_query_entry_created);
+			entry = QueryPolicy::NodeGetNextReferrer(node, entry);
+		}
+	}
+}
+
+
+template
+void
+Query::_SendEntryNotification(Entry* entry,
+	status_t (*notify)(port_id, int32, dev_t, ino_t, const char*, ino_t))
+{
+	char nameBuffer[QueryPolicy::kMaxFileNameLength];
+	const char* name = QueryPolicy::EntryGetNameNoCopy(entry, nameBuffer,
+		sizeof(nameBuffer));
+	if (name != NULL) {
+		notify(fPort, fToken, QueryPolicy::ContextGetVolumeID(fContext),
+			QueryPolicy::EntryGetParentID(entry), name,
+			QueryPolicy::EntryGetNodeID(entry));
+	}
+}
+
+
+}	// namespace QueryParser
+
+
+#endif	// _FILE_SYSTEMS_QUERY_H

From 44de97031e45b987ab2adb473b1a9e42adf2782c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 5 Jul 2011 22:45:06 +0200
Subject: [PATCH 0224/1170] Add TwoKeyAVLTree to kernel utils

This is a tree implementation with elements with primary and secondary
key. The code is a cleaned up version of ramfs's implementation. ramfs
doesn't use this version yet.
---
 headers/private/kernel/util/TwoKeyAVLTree.h | 513 ++++++++++++++++++++
 1 file changed, 513 insertions(+)
 create mode 100644 headers/private/kernel/util/TwoKeyAVLTree.h

diff --git a/headers/private/kernel/util/TwoKeyAVLTree.h b/headers/private/kernel/util/TwoKeyAVLTree.h
new file mode 100644
index 0000000000..9ab0525968
--- /dev/null
+++ b/headers/private/kernel/util/TwoKeyAVLTree.h
@@ -0,0 +1,513 @@
+/*
+ * Copyright 2003-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _KERNEL_UTIL_TWO_KEY_AVL_TREE_H
+#define _KERNEL_UTIL_TWO_KEY_AVL_TREE_H
+
+
+#include 
+
+
+// #pragma mark - TwoKeyAVLTreeKey
+
+
+template
+class TwoKeyAVLTreeKey {
+public:
+	inline TwoKeyAVLTreeKey(const PrimaryKey& primary,
+		const SecondaryKey& secondary)
+		:
+		primary(primary),
+		secondary(secondary),
+		use_secondary(true)
+	{
+	}
+
+	inline TwoKeyAVLTreeKey(const PrimaryKey* primary)
+		:
+		primary(primary),
+		secondary(NULL),
+		use_secondary(false)
+	{
+	}
+
+	PrimaryKey		primary;
+	SecondaryKey	secondary;
+	bool			use_secondary;
+};
+
+
+// #pragma mark - TwoKeyAVLTreeKeyCompare
+
+
+template
+class TwoKeyAVLTreeKeyCompare {
+private:
+	typedef TwoKeyAVLTreeKey Key;
+
+public:
+	inline TwoKeyAVLTreeKeyCompare(const PrimaryKeyCompare& primary,
+								   const SecondaryKeyCompare& secondary)
+		:
+		fPrimaryKeyCompare(primary),
+		fSecondaryKeyCompare(secondary)
+	{
+	}
+
+	inline int operator()(const Key& a, const Key& b) const
+	{
+		int result = fPrimaryKeyCompare(a.primary, b.primary);
+		if (result == 0 && a.use_secondary && b.use_secondary)
+			result = fSecondaryKeyCompare(a.secondary, b.secondary);
+		return result;
+	}
+
+private:
+	PrimaryKeyCompare	fPrimaryKeyCompare;
+	SecondaryKeyCompare	fSecondaryKeyCompare;
+};
+
+
+// #pragma mark - TwoKeyAVLTreeGetKey
+
+
+template
+class TwoKeyAVLTreeGetKey {
+private:
+	typedef TwoKeyAVLTreeKey Key;
+
+public:
+	TwoKeyAVLTreeGetKey(const GetPrimaryKey& getPrimary,
+		const GetSecondaryKey& getSecondary)
+		:
+		fGetPrimaryKey(getPrimary),
+		fGetSecondaryKey(getSecondary)
+	{
+	}
+
+	inline Key operator()(const Value& a) const
+	{
+		return Key(fGetPrimaryKey(a), fGetSecondaryKey(a));
+	}
+
+private:
+	GetPrimaryKey	fGetPrimaryKey;
+	GetSecondaryKey	fGetSecondaryKey;
+};
+
+
+// #pragma mark - TwoKeyAVLTreeStandardCompare
+
+
+template
+class TwoKeyAVLTreeStandardCompare {
+public:
+	inline int operator()(const Value& a, const Value& b) const
+	{
+		if (a < b)
+			return -1;
+		else if (a > b)
+			return 1;
+		return 0;
+	}
+};
+
+
+// #pragma mark - TwoKeyAVLTreeStandardGetKey
+
+
+template
+class TwoKeyAVLTreeStandardGetKey {
+public:
+	inline const Key& operator()(const Value& a) const
+	{
+		return a;
+	}
+
+	inline Key& operator()(Value& a) const
+	{
+		return a;
+	}
+};
+
+
+// #pragma mark - TwoKeyAVLTreeNodeStrategy
+
+
+template 
+class TwoKeyAVLTreeNodeStrategy {
+public:
+	typedef TwoKeyAVLTreeKey Key;
+
+	TwoKeyAVLTreeNodeStrategy(
+		const PrimaryKeyCompare& primaryKeyCompare = PrimaryKeyCompare(),
+		const SecondaryKeyCompare& secondaryKeyCompare = SecondaryKeyCompare(),
+		const GetPrimaryKey& getPrimaryKey = GetPrimaryKey(),
+		const GetSecondaryKey& getSecondaryKey = GetSecondaryKey())
+		:
+		fPrimaryKeyCompare(primaryKeyCompare),
+		fSecondaryKeyCompare(secondaryKeyCompare),
+		fGetPrimaryKey(getPrimaryKey),
+		fGetSecondaryKey(getSecondaryKey)
+	{
+	}
+
+	struct Node : AVLTreeNode {
+		Node(const Value& value)
+			:
+			AVLTreeNode(),
+			value(value)
+		{
+		}
+
+		Value	value;
+	};
+
+	inline Node* Allocate(const Key& key, const Value& value) const
+	{
+		return new(nothrow) Node(value);
+	}
+
+	inline void Free(Node* node) const
+	{
+		delete node;
+	}
+
+	// internal use (not part of the strategy)
+	inline Key GetValueKey(const Value& value) const
+	{
+		return Key(fGetPrimaryKey(value), fGetSecondaryKey(value));
+	}
+
+	inline Key GetKey(Node* node) const
+	{
+		return GetValueKey(node->value);
+	}
+
+	inline Value& GetValue(Node* node) const
+	{
+		return node->value;
+	}
+
+	inline AVLTreeNode* GetAVLTreeNode(Node* node) const
+	{
+		return node;
+	}
+
+	inline Node* GetNode(AVLTreeNode* node) const
+	{
+		return static_cast(node);
+	}
+
+	inline int CompareKeyNode(const Key& a, const Node* b) const
+	{
+		return _CompareKeys(a, GetKey(const_cast(b)));
+	}
+
+	inline int CompareNodes(const Node* a, const Node* b) const
+	{
+		return _CompareKeys(GetKey(const_cast(a)),
+			GetKey(const_cast(b)));
+	}
+
+private:
+	inline int _CompareKeys(const Key& a, const Key& b) const
+	{
+		int result = fPrimaryKeyCompare(a.primary, b.primary);
+		if (result == 0 && a.use_secondary && b.use_secondary)
+			result = fSecondaryKeyCompare(a.secondary, b.secondary);
+		return result;
+	}
+
+	PrimaryKeyCompare	fPrimaryKeyCompare;
+	SecondaryKeyCompare	fSecondaryKeyCompare;
+	GetPrimaryKey		fGetPrimaryKey;
+	GetSecondaryKey		fGetSecondaryKey;
+};
+
+
+// for convenience
+#define TWO_KEY_AVL_TREE_TEMPLATE_LIST template
+#define TWO_KEY_AVL_TREE_CLASS_NAME TwoKeyAVLTree
+
+
+// #pragma mark - TwoKeyAVLTree
+
+
+template,
+	typename GetSecondaryKey
+		= TwoKeyAVLTreeStandardGetKey >
+class TwoKeyAVLTree {
+public:
+			typedef TwoKeyAVLTreeKey Key;
+			typedef TwoKeyAVLTreeNodeStrategy NodeStrategy;
+			typedef AVLTreeMap TreeMap;
+
+			typedef typename TreeMap::Iterator	TreeMapIterator;
+			typedef typename NodeStrategy::Node Node;
+
+			class Iterator;
+
+public:
+								TwoKeyAVLTree();
+								TwoKeyAVLTree(
+									const PrimaryKeyCompare& primaryCompare,
+									const GetPrimaryKey& getPrimary,
+									const SecondaryKeyCompare& secondaryCompare,
+									const GetSecondaryKey& getSecondary);
+								~TwoKeyAVLTree();
+
+	inline	int					CountItems() const	{ return fTreeMap.Count(); }
+
+			Value*				FindFirst(const PrimaryKey& key,
+									Iterator* iterator = NULL);
+			Value*				FindLast(const PrimaryKey& key,
+									Iterator* iterator = NULL);
+	inline	Value*				Find(const PrimaryKey& primaryKey,
+									const SecondaryKey& secondaryKey,
+									Iterator* iterator = NULL);
+
+	inline	void				GetIterator(Iterator* iterator);
+
+	inline	status_t			Insert(const Value& value,
+									Iterator* iterator = NULL);
+	inline	status_t			Remove(const PrimaryKey& primaryKey,
+									const SecondaryKey& secondaryKey);
+
+private:
+			TreeMap				fTreeMap;
+			PrimaryKeyCompare	fPrimaryKeyCompare;
+			GetPrimaryKey		fGetPrimaryKey;
+};
+
+
+// #pragma mark - Iterator
+
+
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+class TWO_KEY_AVL_TREE_CLASS_NAME::Iterator {
+public:
+	typedef typename TWO_KEY_AVL_TREE_CLASS_NAME::TreeMapIterator
+		TreeMapIterator;
+
+	inline Iterator()
+		:
+		fIterator()
+	{
+	}
+
+	inline ~Iterator()
+	{
+	}
+
+	inline Value* Current()
+	{
+		return fIterator.CurrentValuePointer();
+	}
+
+	inline Value* Next()
+	{
+		fIterator.Next();
+		return Current();
+	}
+
+	inline Value* Previous()
+	{
+		fIterator.Previous();
+		return Current();
+	}
+
+	inline void Remove()
+	{
+		fIterator.Remove();
+	}
+
+private:
+	friend class TWO_KEY_AVL_TREE_CLASS_NAME;
+
+	Iterator(const Iterator& other)
+		:
+		fIterator(other.fIterator)
+	{
+	}
+
+	Iterator& operator=(const Iterator& other)
+	{
+		fIterator = other.fIterator;
+	}
+
+	Iterator(const TreeMapIterator& iterator)
+		:
+		fIterator()
+	{
+	}
+
+	inline void _SetTo(const TreeMapIterator& iterator)
+	{
+		fIterator = iterator;
+	}
+
+private:
+	TWO_KEY_AVL_TREE_CLASS_NAME::TreeMapIterator fIterator;
+};
+
+
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+TWO_KEY_AVL_TREE_CLASS_NAME::TwoKeyAVLTree()
+	:
+	fTreeMap(NodeStrategy(PrimaryKeyCompare(), SecondaryKeyCompare(),
+		GetPrimaryKey(), GetSecondaryKey())),
+	fPrimaryKeyCompare(PrimaryKeyCompare()),
+	fGetPrimaryKey(GetPrimaryKey())
+{
+}
+
+
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+TWO_KEY_AVL_TREE_CLASS_NAME::TwoKeyAVLTree(
+	const PrimaryKeyCompare& primaryCompare, const GetPrimaryKey& getPrimary,
+	const SecondaryKeyCompare& secondaryCompare,
+	const GetSecondaryKey& getSecondary)
+	:
+	fTreeMap(NodeStrategy(primaryCompare, secondaryCompare, getPrimary,
+		getSecondary)),
+	fPrimaryKeyCompare(primaryCompare),
+	fGetPrimaryKey(getPrimary)
+{
+}
+
+
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+TWO_KEY_AVL_TREE_CLASS_NAME::~TwoKeyAVLTree()
+{
+}
+
+
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+Value*
+TWO_KEY_AVL_TREE_CLASS_NAME::FindFirst(const PrimaryKey& key,
+	Iterator* iterator)
+{
+	const NodeStrategy& strategy = fTreeMap.GetNodeStrategy();
+	Node* node = fTreeMap.RootNode();
+
+	while (node) {
+		int cmp = fPrimaryKeyCompare(key, fGetPrimaryKey(
+			strategy.GetValue(node)));
+		if (cmp == 0) {
+			// found a matching node, now get the left-most node with that key
+			while (node->left && fPrimaryKeyCompare(key,
+				   	fGetPrimaryKey(strategy.GetValue(
+						strategy.GetNode(node->left)))) == 0) {
+				node = strategy.GetNode(node->left);
+			}
+			if (iterator)
+				iterator->_SetTo(fTreeMap.GetIterator(node));
+			return &strategy.GetValue(node);
+		}
+
+		if (cmp < 0)
+			node = strategy.GetNode(node->left);
+		else
+			node = strategy.GetNode(node->right);
+	}
+	return NULL;
+}
+
+
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+Value*
+TWO_KEY_AVL_TREE_CLASS_NAME::FindLast(const PrimaryKey& key, Iterator* iterator)
+{
+	const NodeStrategy& strategy = fTreeMap.GetNodeStrategy();
+	Node* node = fTreeMap.RootNode();
+
+	while (node) {
+		int cmp = fPrimaryKeyCompare(key, fGetPrimaryKey(
+			strategy.GetValue(node)));
+		if (cmp == 0) {
+			// found a matching node, now get the right-most node with that key
+			while (node->right && fPrimaryKeyCompare(key,
+				   	fGetPrimaryKey(strategy.GetValue(
+						strategy.GetNode(node->right)))) == 0) {
+				node = strategy.GetNode(node->right);
+			}
+			if (iterator)
+				iterator->_SetTo(fTreeMap.GetIterator(node));
+			return &strategy.GetValue(node);
+		}
+
+		if (cmp < 0)
+			node = strategy.GetNode(node->left);
+		else
+			node = strategy.GetNode(node->right);
+	}
+	return NULL;
+}
+
+
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+Value*
+TWO_KEY_AVL_TREE_CLASS_NAME::Find(const PrimaryKey& primaryKey,
+	const SecondaryKey& secondaryKey, Iterator* iterator)
+{
+	TreeMapIterator it = fTreeMap.Find(Key(primaryKey, secondaryKey));
+	if (iterator)
+		iterator->_SetTo(it);
+	return it.CurrentValuePointer();
+}
+
+
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+void
+TWO_KEY_AVL_TREE_CLASS_NAME::GetIterator(Iterator* iterator)
+{
+	TreeMapIterator it = fTreeMap.GetIterator();
+	it.Next();
+		// Our iterator needs to point to the first entry already.
+	iterator->_SetTo(it);
+}
+
+
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+status_t
+TWO_KEY_AVL_TREE_CLASS_NAME::Insert(const Value& value, Iterator* iterator)
+{
+	NodeStrategy& strategy
+		= const_cast(fTreeMap.GetNodeStrategy());
+
+	TreeMapIterator it;
+	status_t status = fTreeMap.Insert(strategy.GetValueKey(value), value, &it);
+	if (status != B_OK || !iterator)
+		return status;
+
+	iterator->_SetTo(it);
+	return B_OK;
+}
+
+
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+status_t
+TWO_KEY_AVL_TREE_CLASS_NAME::Remove(const PrimaryKey& primaryKey,
+	const SecondaryKey& secondaryKey)
+{
+	return fTreeMap.Remove(Key(primaryKey, secondaryKey));
+}
+
+
+#endif	// _KERNEL_UTIL_TWO_KEY_AVL_TREE_H

From 67f11c47a76f21dab107649cf072ab919e0dd1ba Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 5 Jul 2011 22:49:07 +0200
Subject: [PATCH 0225/1170] Add a global node listener mechanism

---
 .../kernel/file_systems/packagefs/Jamfile     |   1 +
 .../file_systems/packagefs/NodeListener.cpp   |  39 +++++
 .../file_systems/packagefs/NodeListener.h     | 115 ++++++++++++++
 .../kernel/file_systems/packagefs/Volume.cpp  | 148 ++++++++++++++++--
 .../kernel/file_systems/packagefs/Volume.h    |  13 +-
 5 files changed, 306 insertions(+), 10 deletions(-)
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/NodeListener.cpp
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/NodeListener.h

diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile
index 9dade89c75..34f2d68ee5 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Jamfile
+++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile
@@ -18,6 +18,7 @@ HAIKU_PACKAGE_FS_SOURCES =
 	GlobalFactory.cpp
 	kernel_interface.cpp
 	Node.cpp
+	NodeListener.cpp
 	Package.cpp
 	PackageDirectory.cpp
 	PackageDomain.cpp
diff --git a/src/add-ons/kernel/file_systems/packagefs/NodeListener.cpp b/src/add-ons/kernel/file_systems/packagefs/NodeListener.cpp
new file mode 100644
index 0000000000..bd5b826a16
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/NodeListener.cpp
@@ -0,0 +1,39 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "NodeListener.h"
+
+
+NodeListener::NodeListener()
+	:
+	fPrevious(this),
+	fNext(this),
+	fNode(NOT_LISTENING_NODE)
+{
+}
+
+
+NodeListener::~NodeListener()
+{
+}
+
+
+void
+NodeListener::NodeAdded(Node* node)
+{
+}
+
+
+void
+NodeListener::NodeRemoved(Node* node)
+{
+}
+
+
+void
+NodeListener::NodeChanged(Node* node, uint32 statFields)
+{
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/NodeListener.h b/src/add-ons/kernel/file_systems/packagefs/NodeListener.h
new file mode 100644
index 0000000000..5c21c95d12
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/NodeListener.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef NODE_LISTENER_H
+#define NODE_LISTENER_H
+
+
+#include 
+#include 
+
+
+class Node;
+
+
+#define NOT_LISTENING_NODE	((Node*)~(addr_t)0)
+
+
+class NodeListener {
+public:
+								NodeListener();
+	virtual						~NodeListener();
+
+	virtual	void				NodeAdded(Node* node);
+	virtual	void				NodeRemoved(Node* node);
+	virtual	void				NodeChanged(Node* node, uint32 statFields);
+
+			void				StartedListening(Node* node)
+									{ fNode = node; }
+			void				StoppedListening()
+									{ fNode = NOT_LISTENING_NODE; }
+			bool				IsListening() const
+									{ return fNode != NOT_LISTENING_NODE; }
+			Node*				ListenedNode() const
+									{ return fNode; }
+
+	inline	void				AddNodeListener(NodeListener* listener);
+	inline	NodeListener*		RemoveNodeListener();
+
+			NodeListener*		PreviousNodeListener() const
+									{ return fPrevious; }
+			NodeListener*		NextNodeListener() const
+									{ return fNext; }
+
+			NodeListener*&		NodeListenerHashLink()
+									{ return fHashLink; }
+
+private:
+			NodeListener*		fHashLink;
+			NodeListener*		fPrevious;
+			NodeListener*		fNext;
+			Node*				fNode;
+};
+
+
+inline void
+NodeListener::AddNodeListener(NodeListener* listener)
+{
+	listener->fPrevious = this;
+	listener->fNext = fNext;
+
+	fNext->fPrevious = listener;
+	fNext = listener;
+}
+
+
+inline NodeListener*
+NodeListener::RemoveNodeListener()
+{
+	if (fNext == this)
+		return NULL;
+
+	NodeListener* next = fNext;
+
+	fPrevious->fNext = next;
+	next->fPrevious = fPrevious;
+
+	fPrevious = fNext = this;
+
+	return next;
+}
+
+
+
+struct NodeListenerHashDefinition {
+	typedef Node*			KeyType;
+	typedef	NodeListener	ValueType;
+
+	size_t HashKey(Node* key) const
+	{
+		return (size_t)key;
+	}
+
+	size_t Hash(const NodeListener* value) const
+	{
+		return HashKey(value->ListenedNode());
+	}
+
+	bool Compare(Node* key, const NodeListener* value) const
+	{
+		return key == value->ListenedNode();
+	}
+
+	NodeListener*& GetLink(NodeListener* value) const
+	{
+		return value->NodeListenerHashLink();
+	}
+};
+
+
+typedef DoublyLinkedList NodeListenerList;
+typedef BOpenHashTable NodeListenerHashTable;
+
+
+#endif	// NODE_LISTENER_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index ba772f23cb..2a3cf330da 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -52,6 +52,10 @@ using BPackageKit::BHPKG::BPrivate::PackageReaderImpl;
 // node ID of the root directory
 static const ino_t kRootDirectoryID = 1;
 
+static const uint32 kAllStatFields = B_STAT_MODE | B_STAT_UID | B_STAT_GID
+	| B_STAT_SIZE | B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
+	| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME;
+
 // shine-through directories
 const char* const kSystemShineThroughDirectories[] = {
 	"packages", NULL
@@ -482,11 +486,16 @@ Volume::~Volume()
 status_t
 Volume::Mount(const char* parameterString)
 {
-	// init the node table
+	// init the hash tables
 	status_t error = fNodes.Init();
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
+	error = fNodeListeners.Init();
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	// get the mount parameters
 	const char* packages = NULL;
 	const char* volumeName = NULL;
 	const char* mountType = NULL;
@@ -605,6 +614,42 @@ Volume::Unmount()
 }
 
 
+void
+Volume::AddNodeListener(NodeListener* listener, Node* node)
+{
+	ASSERT(!listener->IsListening());
+
+	listener->StartedListening(node);
+
+	if (NodeListener* list = fNodeListeners.Lookup(node))
+		list->AddNodeListener(listener);
+	else
+		fNodeListeners.Insert(listener);
+}
+
+
+void
+Volume::RemoveNodeListener(NodeListener* listener)
+{
+	ASSERT(listener->IsListening());
+
+	Node* node = listener->ListenedNode();
+
+	if (NodeListener* next = listener->RemoveNodeListener()) {
+		// list not empty yet -- if we removed the head, add a new head to the
+		// hash table
+		NodeListener* list = fNodeListeners.Lookup(node);
+		if (list == listener) {
+			fNodeListeners.Remove(listener);
+			fNodeListeners.Insert(next);
+		}
+	} else
+		fNodeListeners.Remove(listener);
+
+	listener->StoppedListening();
+}
+
+
 status_t
 Volume::GetVNode(ino_t nodeID, Node*& _node)
 {
@@ -662,6 +707,7 @@ Volume::PackageLinkNodeAdded(Node* node)
 	_AddPackageLinksNode(node);
 
 	notify_entry_created(ID(), node->Parent()->ID(), node->Name(), node->ID());
+	_NotifyNodeAdded(node);
 }
 
 
@@ -671,6 +717,7 @@ Volume::PackageLinkNodeRemoved(Node* node)
 	_RemovePackageLinksNode(node);
 
 	notify_entry_removed(ID(), node->Parent()->ID(), node->Name(), node->ID());
+	_NotifyNodeRemoved(node);
 }
 
 
@@ -678,6 +725,7 @@ void
 Volume::PackageLinkNodeChanged(Node* node, uint32 statFields)
 {
 	notify_stat_changed(ID(), node->ID(), statFields);
+	_NotifyNodeChanged(node, statFields);
 }
 
 
@@ -1069,6 +1117,11 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
 		RETURN_ERROR(error);
 	}
 
+	if (newNode)
+		_NotifyNodeAdded(node);
+	else
+		_NotifyNodeChanged(node, kAllStatFields);
+
 	if (notify) {
 		if (newNode) {
 			notify_entry_created(ID(), directory->ID(), node->Name(),
@@ -1078,10 +1131,7 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
 			// Send stat changed notification for directories and entry
 			// removed + created notifications for files and symlinks.
 			if (S_ISDIR(packageNode->Mode())) {
-				notify_stat_changed(ID(), node->ID(),
-					B_STAT_MODE | B_STAT_UID | B_STAT_GID | B_STAT_SIZE
-						| B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
-						| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME);
+				notify_stat_changed(ID(), node->ID(), kAllStatFields);
 				// TODO: Actually the attributes might change, too!
 			} else {
 				notify_entry_removed(ID(), directory->ID(), node->Name(),
@@ -1133,6 +1183,11 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
 		}
 	}
 
+	if (nodeRemoved)
+		_NotifyNodeRemoved(node);
+	else
+		_NotifyNodeChanged(node, kAllStatFields);
+
 	if (!notify)
 		return;
 
@@ -1144,10 +1199,7 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
 		// Send stat changed notification for directories and entry
 		// removed + created notifications for files and symlinks.
 		if (S_ISDIR(packageNode->Mode())) {
-			notify_stat_changed(ID(), node->ID(),
-				B_STAT_MODE | B_STAT_UID | B_STAT_GID | B_STAT_SIZE
-					| B_STAT_ACCESS_TIME | B_STAT_MODIFICATION_TIME
-					| B_STAT_CREATION_TIME | B_STAT_CHANGE_TIME);
+			notify_stat_changed(ID(), node->ID(), kAllStatFields);
 			// TODO: Actually the attributes might change, too!
 		} else {
 			notify_entry_removed(ID(), directory->ID(), node->Name(),
@@ -1556,3 +1608,81 @@ Volume::_SystemVolumeIfNotSelf() const
 		return systemVolume == this ? NULL : systemVolume;
 	return NULL;
 }
+
+
+void
+Volume::_NotifyNodeAdded(Node* node)
+{
+	Node* key = node;
+
+	for (int i = 0; i < 2; i++) {
+		if (NodeListener* listener = fNodeListeners.Lookup(key)) {
+			NodeListener* last = listener->PreviousNodeListener();
+
+			while (true) {
+				NodeListener* next = listener->NextNodeListener();
+
+				listener->NodeAdded(node);
+
+				if (listener == last)
+					break;
+
+				listener = next;
+			}
+		}
+
+		key = NULL;
+	}
+}
+
+
+void
+Volume::_NotifyNodeRemoved(Node* node)
+{
+	Node* key = node;
+
+	for (int i = 0; i < 2; i++) {
+		if (NodeListener* listener = fNodeListeners.Lookup(key)) {
+			NodeListener* last = listener->PreviousNodeListener();
+
+			while (true) {
+				NodeListener* next = listener->NextNodeListener();
+
+				listener->NodeRemoved(node);
+
+				if (listener == last)
+					break;
+
+				listener = next;
+			}
+		}
+
+		key = NULL;
+	}
+}
+
+
+void
+Volume::_NotifyNodeChanged(Node* node, uint32 statFields)
+{
+	Node* key = node;
+
+	for (int i = 0; i < 2; i++) {
+		if (NodeListener* listener = fNodeListeners.Lookup(key)) {
+			NodeListener* last = listener->PreviousNodeListener();
+
+			while (true) {
+				NodeListener* next = listener->NextNodeListener();
+
+				listener->NodeChanged(node, statFields);
+
+				if (listener == last)
+					break;
+
+				listener = next;
+			}
+		}
+
+		key = NULL;
+	}
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index c293aab9ed..6dc1fd4c23 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -15,12 +15,12 @@
 #include 
 
 #include "Node.h"
+#include "NodeListener.h"
 #include "PackageDomain.h"
 #include "PackageLinksListener.h"
 
 
 class Directory;
-class Node;
 class PackageFSRoot;
 class UnpackingNode;
 
@@ -66,6 +66,11 @@ public:
 			Node*				FindNode(ino_t nodeID) const
 									{ return fNodes.Lookup(nodeID); }
 
+			// node listeners -- volume must be write-locked
+			void				AddNodeListener(NodeListener* listener,
+									Node* node);
+			void				RemoveNodeListener(NodeListener* listener);
+
 			// VFS wrappers
 			status_t			GetVNode(ino_t nodeID, Node*& _node);
 			status_t			PutVNode(ino_t nodeID);
@@ -162,6 +167,11 @@ private:
 
 	inline	Volume*				_SystemVolumeIfNotSelf() const;
 
+			void				_NotifyNodeAdded(Node* node);
+			void				_NotifyNodeRemoved(Node* node);
+			void				_NotifyNodeChanged(Node* node,
+									uint32 statFields);
+
 private:
 	mutable	rw_lock				fLock;
 			fs_volume*			fFSVolume;
@@ -177,6 +187,7 @@ private:
 			} fMountPoint;
 
 			NodeIDHashTable		fNodes;
+			NodeListenerHashTable fNodeListeners;
 
 			JobList				fJobQueue;
 			mutex				fJobQueueLock;

From 804a92da7afe1a970f88ac11f0fc374635fc56f7 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 5 Jul 2011 22:55:24 +0200
Subject: [PATCH 0226/1170] Add Index base class and index table in Volume

---
 .../kernel/file_systems/packagefs/Index.cpp   | 205 ++++++++++++++++++
 .../kernel/file_systems/packagefs/Index.h     | 128 +++++++++++
 .../kernel/file_systems/packagefs/IndexImpl.h |  28 +++
 .../kernel/file_systems/packagefs/Jamfile     |   1 +
 .../kernel/file_systems/packagefs/Volume.cpp  |  12 +
 .../kernel/file_systems/packagefs/Volume.h    |   5 +
 6 files changed, 379 insertions(+)
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/Index.cpp
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/Index.h
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/IndexImpl.h

diff --git a/src/add-ons/kernel/file_systems/packagefs/Index.cpp b/src/add-ons/kernel/file_systems/packagefs/Index.cpp
new file mode 100644
index 0000000000..88cc9fcb2b
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/Index.cpp
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "Index.h"
+
+#include "DebugSupport.h"
+#include "Node.h"
+#include "IndexImpl.h"
+
+
+// #pragma mark - Index
+
+
+Index::Index()
+	:
+	fVolume(NULL),
+	fName(NULL),
+	fType(0),
+	fKeyLength(0),
+	fFixedKeyLength(true)
+{
+}
+
+
+Index::~Index()
+{
+	free(fName);
+}
+
+
+status_t
+Index::Init(Volume* volume, const char* name, uint32 type, bool fixedKeyLength,
+	size_t keyLength)
+{
+	fName = strdup(name);
+	if (fName == NULL)
+		return B_NO_MEMORY;
+
+	fVolume = volume;
+	fType = type;
+	fKeyLength = keyLength;
+	fFixedKeyLength = fixedKeyLength;
+
+	return B_OK;
+}
+
+
+bool
+Index::GetIterator(IndexIterator* iterator)
+{
+	bool result = false;
+	if (iterator) {
+		AbstractIndexIterator* actualIterator = InternalGetIterator();
+		if (actualIterator) {
+			iterator->SetIterator(actualIterator);
+			result = true;
+		}
+	}
+	return result;
+}
+
+
+bool
+Index::Find(const void* key, size_t length, IndexIterator* iterator)
+{
+	bool result = false;
+	if (key && iterator) {
+		AbstractIndexIterator* actualIterator = InternalFind(key, length);
+		if (actualIterator) {
+			iterator->SetIterator(actualIterator);
+			result = true;
+		}
+	}
+	return result;
+}
+
+
+void
+Index::Dump()
+{
+	D(
+		PRINT(("Index: `%s', type: %lx\n", Name(), Type()));
+		for (IndexIterator it(this); it.Current(); it.Next()) {
+			Node* node = it.Current();
+			PRINT(("  node: `%s', dir: %lld\n", node->GetName(),
+				node->Parent()->ID()));
+		}
+	)
+}
+
+
+// #pragma mark - IndexIterator
+
+
+IndexIterator::IndexIterator()
+	:
+	fIterator(NULL)
+{
+}
+
+
+IndexIterator::IndexIterator(Index* index)
+	:
+	fIterator(NULL)
+{
+	if (index)
+		index->GetIterator(this);
+}
+
+
+IndexIterator::~IndexIterator()
+{
+	SetIterator(NULL);
+}
+
+
+Node*
+IndexIterator::Current()
+{
+	return fIterator != NULL ? fIterator->Current() : NULL;
+}
+
+
+Node*
+IndexIterator::Current(void* buffer, size_t* _keyLength)
+{
+	return fIterator != NULL ? fIterator->Current(buffer, _keyLength) : NULL;
+}
+
+
+Node*
+IndexIterator::Previous()
+{
+	return fIterator != NULL ? fIterator->Previous() : NULL;
+}
+
+
+Node*
+IndexIterator::Next()
+{
+	return fIterator != NULL ? fIterator->Next() : NULL;
+}
+
+
+Node*
+IndexIterator::Next(void* buffer, size_t* _keyLength)
+{
+	Node* node = NULL;
+	if (fIterator != NULL && fIterator->Next())
+		node = Current(buffer, _keyLength);
+	return node;
+}
+
+
+status_t
+IndexIterator::Suspend()
+{
+	return fIterator != NULL ? fIterator->Suspend() : B_BAD_VALUE;
+}
+
+
+status_t
+IndexIterator::Resume()
+{
+	return fIterator != NULL ? fIterator->Resume() : B_BAD_VALUE;
+}
+
+
+void
+IndexIterator::SetIterator(AbstractIndexIterator* iterator)
+{
+	delete fIterator;
+	fIterator = iterator;
+}
+
+
+// #pragma mark - AbstractIndexIterator
+
+
+AbstractIndexIterator::AbstractIndexIterator()
+{
+}
+
+
+AbstractIndexIterator::~AbstractIndexIterator()
+{
+}
+
+
+status_t
+AbstractIndexIterator::Suspend()
+{
+	return B_OK;
+}
+
+
+status_t
+AbstractIndexIterator::Resume()
+{
+	return B_OK;
+}
+
diff --git a/src/add-ons/kernel/file_systems/packagefs/Index.h b/src/add-ons/kernel/file_systems/packagefs/Index.h
new file mode 100644
index 0000000000..cd3c69315e
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/Index.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef INDEX_H
+#define INDEX_H
+
+
+#include 
+
+#include 
+
+#include 
+#include 
+
+
+class AbstractIndexIterator;
+class IndexIterator;
+class Node;
+class Volume;
+
+
+static const size_t kMaxIndexKeyLength = 256;
+
+
+class Index {
+public:
+								Index();
+	virtual						~Index();
+
+			status_t			Init(Volume* volume, const char* name,
+									uint32 type, bool fixedKeyLength,
+									size_t keyLength = 0);
+
+			Volume*				GetVolume() const		{ return fVolume; }
+
+			const char*			Name() const			{ return fName; }
+			uint32				Type() const			{ return fType; }
+			bool				HasFixedKeyLength() const
+									{ return fFixedKeyLength; }
+			size_t				KeyLength() const		{ return fKeyLength; }
+
+	virtual	int32				CountEntries() const = 0;
+
+			bool				GetIterator(IndexIterator* iterator);
+			bool				Find(const void* key, size_t length,
+									IndexIterator* iterator);
+
+			Index*&				IndexHashLink()
+									{ return fHashLink; }
+
+			// debugging
+			void				Dump();
+
+protected:
+	virtual	AbstractIndexIterator* InternalGetIterator() = 0;
+	virtual	AbstractIndexIterator* InternalFind(const void* key,
+									size_t length) = 0;
+
+protected:
+			Index*				fHashLink;
+			Volume*				fVolume;
+			char*				fName;
+			uint32				fType;
+			size_t				fKeyLength;
+			bool				fFixedKeyLength;
+};
+
+
+class IndexIterator {
+public:
+								IndexIterator();
+								IndexIterator(Index* index);
+								~IndexIterator();
+
+			Node*				Current();
+			Node*				Current(void* buffer, size_t* _keyLength);
+			Node*				Previous();
+			Node*				Next();
+			Node*				Next(void* buffer, size_t* _keyLength);
+
+			status_t			Suspend();
+			status_t			Resume();
+
+private:
+			void				SetIterator(AbstractIndexIterator* iterator);
+
+private:
+			friend class Index;
+
+private:
+			AbstractIndexIterator* fIterator;
+};
+
+
+// #pragma mark - IndexHashDefinition
+
+
+struct IndexHashDefinition {
+	typedef const char*	KeyType;
+	typedef	Index		ValueType;
+
+	size_t HashKey(const char* key) const
+	{
+		return key != NULL ? hash_hash_string(key) : 0;
+	}
+
+	size_t Hash(const Index* value) const
+	{
+		return HashKey(value->Name());
+	}
+
+	bool Compare(const char* key, const Index* value) const
+	{
+		return strcmp(value->Name(), key) == 0;
+	}
+
+	Index*& GetLink(Index* value) const
+	{
+		return value->IndexHashLink();
+	}
+};
+
+
+typedef BOpenHashTable IndexHashTable;
+
+
+#endif	// INDEX_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
new file mode 100644
index 0000000000..3dae8e6277
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef INDEX_IMPL_H
+#define INDEX_IMPL_H
+
+
+#include "Index.h"
+#include "Node.h"
+
+
+class AbstractIndexIterator {
+public:
+								AbstractIndexIterator();
+	virtual						~AbstractIndexIterator();
+
+	virtual Node*				Current() = 0;
+	virtual Node*				Current(void* buffer, size_t* _keyLength) = 0;
+	virtual Node*				Previous() = 0;
+	virtual Node*				Next() = 0;
+
+	virtual	status_t			Suspend();
+	virtual	status_t			Resume();
+};
+
+
+#endif	// INDEX_IMPL_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile
index 34f2d68ee5..0f00d36f7c 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Jamfile
+++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile
@@ -16,6 +16,7 @@ HAIKU_PACKAGE_FS_SOURCES =
 	Directory.cpp
 	EmptyAttributeDirectoryCookie.cpp
 	GlobalFactory.cpp
+	Index.cpp
 	kernel_interface.cpp
 	Node.cpp
 	NodeListener.cpp
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 2a3cf330da..bea3475acb 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -460,6 +460,14 @@ Volume::~Volume()
 	while (PackageDomain* packageDomain = fPackageDomains.Head())
 		_RemovePackageDomain(packageDomain);
 
+	// delete all indices
+	Index* index = fIndices.Clear(true);
+	while (index != NULL) {
+		Index* next = index->IndexHashLink();
+		delete index;
+		index = next;
+	}
+
 	// remove all nodes from the ID hash table
 	Node* node = fNodes.Clear(true);
 	while (node != NULL) {
@@ -495,6 +503,10 @@ Volume::Mount(const char* parameterString)
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
+	error = fIndices.Init();
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
 	// get the mount parameters
 	const char* packages = NULL;
 	const char* volumeName = NULL;
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index 6dc1fd4c23..438b134ecf 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -14,6 +14,7 @@
 #include 
 #include 
 
+#include "Index.h"
 #include "Node.h"
 #include "NodeListener.h"
 #include "PackageDomain.h"
@@ -71,6 +72,9 @@ public:
 									Node* node);
 			void				RemoveNodeListener(NodeListener* listener);
 
+			Index*				FindIndex(const char* name) const
+									{ return fIndices.Lookup(name); }
+
 			// VFS wrappers
 			status_t			GetVNode(ino_t nodeID, Node*& _node);
 			status_t			PutVNode(ino_t nodeID);
@@ -188,6 +192,7 @@ private:
 
 			NodeIDHashTable		fNodes;
 			NodeListenerHashTable fNodeListeners;
+			IndexHashTable		fIndices;
 
 			JobList				fJobQueue;
 			mutex				fJobQueueLock;

From 3897e7298eabe1bfe7faf8f12c9f865863938938 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 5 Jul 2011 22:57:29 +0200
Subject: [PATCH 0227/1170] Add NameIndex class and create instance in Volume

---
 .../kernel/file_systems/packagefs/Jamfile     |   1 +
 .../file_systems/packagefs/NameIndex.cpp      | 370 ++++++++++++++++++
 .../kernel/file_systems/packagefs/NameIndex.h |  47 +++
 .../kernel/file_systems/packagefs/Volume.cpp  |  14 +
 4 files changed, 432 insertions(+)
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/NameIndex.h

diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile
index 0f00d36f7c..e361a074c8 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Jamfile
+++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile
@@ -18,6 +18,7 @@ HAIKU_PACKAGE_FS_SOURCES =
 	GlobalFactory.cpp
 	Index.cpp
 	kernel_interface.cpp
+	NameIndex.cpp
 	Node.cpp
 	NodeListener.cpp
 	Package.cpp
diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
new file mode 100644
index 0000000000..fd160ef5a4
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
@@ -0,0 +1,370 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include 
+
+#include 
+
+#include "DebugSupport.h"
+#include "IndexImpl.h"
+#include "NameIndex.h"
+#include "Node.h"
+#include "Volume.h"
+
+
+// #pragma mark - NameIndexPrimaryKey
+
+
+class NameIndexPrimaryKey {
+public:
+	NameIndexPrimaryKey(const Node* entry, const char* name = NULL)
+		:
+		entry(entry),
+		name(name ? name : entry->Name())
+		{
+		}
+
+	NameIndexPrimaryKey(const char* name)
+		:
+		entry(NULL),
+		name(name)
+	{
+	}
+
+	const Node*	entry;
+	const char*	name;
+};
+
+
+// #pragma mark - NameIndexGetPrimaryKey
+
+
+class NameIndexGetPrimaryKey {
+public:
+	inline NameIndexPrimaryKey operator()(const Node* a)
+	{
+		return NameIndexPrimaryKey(a);
+	}
+
+	inline NameIndexPrimaryKey operator()(const Node* a) const
+	{
+		return NameIndexPrimaryKey(a);
+	}
+};
+
+
+// #pragma mark - NameIndexPrimaryKeyCompare
+
+
+class NameIndexPrimaryKeyCompare
+{
+public:
+	inline int operator()(const NameIndexPrimaryKey &a,
+		const NameIndexPrimaryKey &b) const
+	{
+		if (a.entry != NULL && a.entry == b.entry)
+			return 0;
+		return strcmp(a.name, b.name) != 0;
+	}
+};
+
+
+// #pragma mark - EntryTree
+
+
+typedef TwoKeyAVLTree _EntryTree;
+
+class NameIndex::EntryTree : public _EntryTree {
+};
+
+
+// #pragma mark -  NameIndexIterator
+
+
+class NameIndexIterator : public AbstractIndexIterator,
+	public NodeListener {
+public:
+								NameIndexIterator();
+	virtual						~NameIndexIterator();
+
+	virtual	Node*				Current();
+	virtual	Node*				Current(void* buffer, size_t* _keyLength);
+	virtual	Node*				Previous();
+	virtual	Node*				Next();
+
+	virtual	status_t			Suspend();
+	virtual	status_t			Resume();
+
+			bool				SetTo(NameIndex* index, const char* name,
+									bool ignoreValue = false);
+
+	virtual void				NodeRemoved(Node* node);
+
+private:
+			friend class NameIndex;
+
+			typedef AbstractIndexIterator BaseClass;
+
+private:
+			NameIndex*			fIndex;
+			NameIndex::EntryTree::Iterator fIterator;
+			bool				fSuspended;
+			bool				fIsNext;
+};
+
+
+// #pragma mark - NameIndex
+
+
+NameIndex::NameIndex()
+	:
+	Index(),
+	fEntries(NULL)
+{
+}
+
+
+NameIndex::~NameIndex()
+{
+	if (fVolume != NULL)
+		fVolume->RemoveNodeListener(this);
+
+	delete fEntries;
+	// Actually we would need to maintain a list of iterators and unset the
+	// still existing iterators here. But since the name index is deleted
+	// when the volume is unmounted, there shouldn't be any iterators left
+	// anymore.
+}
+
+
+status_t
+NameIndex::Init(Volume* volume)
+{
+	status_t error = Index::Init(volume, "name", B_STRING_TYPE, false);
+	if (error != B_OK)
+		return error;
+
+	fEntries = new(std::nothrow) EntryTree;
+	if (fEntries == NULL)
+		return B_NO_MEMORY;
+
+	fVolume = volume;
+	fVolume->AddNodeListener(this, NULL);
+
+	return B_OK;
+}
+
+
+int32
+NameIndex::CountEntries() const
+{
+	return fEntries->CountItems();
+}
+
+
+void
+NameIndex::NodeAdded(Node* node)
+{
+	fEntries->Insert(node);
+
+	// udpate live queries
+	_UpdateLiveQueries(node, NULL, node->Name());
+}
+
+
+void
+NameIndex::NodeRemoved(Node* node)
+{
+	fEntries->Remove(node, node);
+
+	// udpate live queries
+	_UpdateLiveQueries(node, node->Name(), NULL);
+}
+
+
+void
+NameIndex::NodeChanged(Node* node, uint32 statFields)
+{
+	// nothing to do -- the name remains the same
+}
+
+
+AbstractIndexIterator*
+NameIndex::InternalGetIterator()
+{
+	NameIndexIterator* iterator = new(std::nothrow) NameIndexIterator;
+	if (iterator != NULL) {
+		if (!iterator->SetTo(this, NULL, true)) {
+			delete iterator;
+			iterator = NULL;
+		}
+	}
+	return iterator;
+}
+
+
+AbstractIndexIterator*
+NameIndex::InternalFind(const void* _key, size_t length)
+{
+	if (_key == NULL || length == 0)
+		return NULL;
+
+	const char* key = (const char*)_key;
+
+	// if the key is not null-terminated, copy it
+	char clonedKey[kMaxIndexKeyLength];
+	if (key[length - 1] != '\0') {
+		if (length >= kMaxIndexKeyLength)
+			length = kMaxIndexKeyLength - 1;
+
+		memcpy(clonedKey, key, length);
+		clonedKey[length] = '\0';
+		length++;
+		key = clonedKey;
+	}
+
+	NameIndexIterator* iterator = new(std::nothrow) NameIndexIterator;
+	if (iterator != NULL) {
+		if (!iterator->SetTo(this, (const char*)key)) {
+			delete iterator;
+			iterator = NULL;
+		}
+	}
+	return iterator;
+}
+
+
+void
+NameIndex::_UpdateLiveQueries(Node* entry, const char* oldName,
+	const char* newName)
+{
+	fVolume->UpdateLiveQueries(entry, Name(), Type(),
+		oldName, oldName ? strlen(oldName) : 0,
+		newName, newName ? strlen(newName) : 0);
+}
+
+
+// #pragma mark - NameIndexIterator
+
+
+NameIndexIterator::NameIndexIterator()
+	:
+	AbstractIndexIterator(),
+	fIndex(NULL),
+	fIterator(),
+	fSuspended(false),
+	fIsNext(false)
+{
+}
+
+
+NameIndexIterator::~NameIndexIterator()
+{
+	SetTo(NULL, NULL);
+}
+
+
+Node*
+NameIndexIterator::Current()
+{
+	return fIndex != NULL
+		&& fIterator.Current() != NULL ? *fIterator.Current() : NULL;
+}
+
+
+Node*
+NameIndexIterator::Current(void* buffer, size_t* _keyLength)
+{
+	Node* entry = Current();
+	if (entry != NULL) {
+		strlcpy((char*)buffer, entry->Name(), kMaxIndexKeyLength);
+		*_keyLength = strlen(entry->Name());
+	}
+	return entry;
+}
+
+
+Node*
+NameIndexIterator::Previous()
+{
+	if (fSuspended)
+		return NULL;
+	if (!(fIterator.Current() != NULL && fIsNext))
+		fIterator.Previous();
+	fIsNext = false;
+	return fIndex != NULL
+		&& fIterator.Current() != NULL ? *fIterator.Current() : NULL;
+}
+
+
+Node*
+NameIndexIterator::Next()
+{
+	if (fSuspended)
+		return NULL;
+	if (!(fIterator.Current() != NULL && fIsNext))
+		fIterator.Next();
+	fIsNext = false;
+	return fIndex != NULL
+		&& fIterator.Current() != NULL ? *fIterator.Current() : NULL;
+}
+
+
+status_t
+NameIndexIterator::Suspend()
+{
+	status_t error = !fSuspended ? B_OK : B_BAD_VALUE;
+	if (error == B_OK) {
+		if (fIterator.Current() != NULL)
+			fIndex->GetVolume()->AddNodeListener(this, *fIterator.Current());
+
+		fSuspended = true;
+	}
+	return error;
+}
+
+
+status_t
+NameIndexIterator::Resume()
+{
+	status_t error = fSuspended ? B_OK : B_BAD_VALUE;
+	if (error == B_OK) {
+		if (fIterator.Current() != NULL)
+			fIndex->GetVolume()->RemoveNodeListener(this);
+
+		fSuspended = false;
+	}
+	return error;
+}
+
+
+bool
+NameIndexIterator::SetTo(NameIndex* index, const char* name, bool ignoreValue)
+{
+	Resume();
+
+	fIndex = index;
+	fSuspended = false;
+	fIsNext = false;
+	if (fIndex != NULL) {
+		if (ignoreValue) {
+			fIndex->fEntries->GetIterator(&fIterator);
+			return fIterator.Current() != NULL;
+		}
+		return fIndex->fEntries->FindFirst(name, &fIterator);
+	}
+	return false;
+}
+
+
+void
+NameIndexIterator::NodeRemoved(Node* node)
+{
+	Resume();
+	fIsNext = Next();
+	Suspend();
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.h b/src/add-ons/kernel/file_systems/packagefs/NameIndex.h
new file mode 100644
index 0000000000..3fceabedfb
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef NAME_INDEX_H
+#define NAME_INDEX_H
+
+
+#include "Index.h"
+#include "NodeListener.h"
+
+
+class NameIndexIterator;
+
+
+class NameIndex : public Index, private NodeListener {
+public:
+								NameIndex();
+	virtual						~NameIndex();
+
+			status_t			Init(Volume* volume);
+
+	virtual	int32				CountEntries() const;
+
+private:
+	virtual	void				NodeAdded(Node* node);
+	virtual	void				NodeRemoved(Node* node);
+	virtual	void				NodeChanged(Node* node, uint32 statFields);
+
+protected:
+	virtual	AbstractIndexIterator* InternalGetIterator();
+	virtual	AbstractIndexIterator* InternalFind(const void* key,
+									size_t length);
+
+private:
+			class EntryTree;
+			friend class NameIndexIterator;
+
+			void				_UpdateLiveQueries(Node* entry,
+									const char* oldName, const char* newName);
+
+private:
+			EntryTree*			fEntries;
+};
+
+
+#endif	// NAME_INDEX_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index bea3475acb..ccc99ee8ef 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -32,6 +32,7 @@
 
 #include "DebugSupport.h"
 #include "kernel_interface.h"
+#include "NameIndex.h"
 #include "PackageDirectory.h"
 #include "PackageFile.h"
 #include "PackageFSRoot.h"
@@ -507,6 +508,19 @@ Volume::Mount(const char* parameterString)
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
+	// create the name index
+	NameIndex* index = new(std::nothrow) NameIndex;
+	if (index == NULL)
+		RETURN_ERROR(B_NO_MEMORY);
+
+	error = index->Init(this);
+	if (error != B_OK) {
+		delete index;
+		RETURN_ERROR(error);
+	}
+
+	fIndices.Insert(index);
+
 	// get the mount parameters
 	const char* packages = NULL;
 	const char* volumeName = NULL;

From a3f976768e5b4e7678827775c817fd1f38950304 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 5 Jul 2011 22:58:58 +0200
Subject: [PATCH 0228/1170] Add Query class and query management in Volume

---
 .../kernel/file_systems/packagefs/Jamfile     |   3 +-
 .../kernel/file_systems/packagefs/Query.cpp   | 282 ++++++++++++++++++
 .../kernel/file_systems/packagefs/Query.h     |  60 ++++
 .../kernel/file_systems/packagefs/Volume.cpp  |  27 ++
 .../kernel/file_systems/packagefs/Volume.h    |  10 +
 5 files changed, 381 insertions(+), 1 deletion(-)
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/Query.cpp
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/Query.h

diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile
index e361a074c8..5c7584a97e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Jamfile
+++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile
@@ -3,7 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel file_systems packagefs ;
 
 UseLibraryHeaders zlib ;
 UsePrivateKernelHeaders ;
-UsePrivateHeaders shared ;
+UsePrivateHeaders shared storage ;
 
 
 HAIKU_PACKAGE_FS_SOURCES =
@@ -21,6 +21,7 @@ HAIKU_PACKAGE_FS_SOURCES =
 	NameIndex.cpp
 	Node.cpp
 	NodeListener.cpp
+	Query.cpp
 	Package.cpp
 	PackageDirectory.cpp
 	PackageDomain.cpp
diff --git a/src/add-ons/kernel/file_systems/packagefs/Query.cpp b/src/add-ons/kernel/file_systems/packagefs/Query.cpp
new file mode 100644
index 0000000000..0c9078944e
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/Query.cpp
@@ -0,0 +1,282 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "Query.h"
+
+#include 
+
+#include "AttributeCookie.h"
+#include "Directory.h"
+#include "Index.h"
+#include "Node.h"
+#include "Volume.h"
+
+
+// #pragma mark - QueryPolicy
+
+
+struct Query::QueryPolicy {
+	typedef Query Context;
+	typedef ::Node Entry;
+	typedef ::Node Node;
+
+	struct Index {
+		Query*		query;
+		::Index*	index;
+
+		Index(Context* context)
+			:
+			query(context)
+		{
+		}
+	};
+
+	struct IndexIterator : ::IndexIterator {
+		::Index*			index;
+
+		IndexIterator(::Index* index)
+			:
+			index(index)
+		{
+		}
+	};
+
+	static const int32 kMaxFileNameLength = B_FILE_NAME_LENGTH;
+
+	// Entry interface
+
+	static ino_t EntryGetParentID(Entry* entry)
+	{
+		return entry->Parent()->ID();
+	}
+
+	static Node* EntryGetNode(Entry* entry)
+	{
+		return entry;
+	}
+
+	static ino_t EntryGetNodeID(Entry* entry)
+	{
+		return entry->ID();
+	}
+
+	static ssize_t EntryGetName(Entry* entry, void* buffer, size_t bufferSize)
+	{
+		const char* name = entry->Name();
+		size_t nameLength = strlen(name);
+		if (nameLength >= bufferSize)
+			return B_BUFFER_OVERFLOW;
+
+		memcpy(buffer, name, nameLength + 1);
+		return nameLength + 1;
+	}
+
+	static const char* EntryGetNameNoCopy(Entry* entry, void* buffer,
+		size_t bufferSize)
+	{
+		return entry->Name();
+	}
+
+	// Index interface
+
+	static status_t IndexSetTo(Index& index, const char* attribute)
+	{
+		index.index = index.query->fVolume->FindIndex(attribute);
+		return index.index != NULL ? B_OK : B_ENTRY_NOT_FOUND;
+	}
+
+	static void IndexUnset(Index& index)
+	{
+		index.index = NULL;
+	}
+
+	static int32 IndexGetWeightedScore(Index& index, int32 score)
+	{
+		// should be inversely proportional to the index size; max input score
+		// is 2048
+		static const int32 maxFactor = 1024 * 1024;
+		return score * (maxFactor
+			/ std::min(maxFactor,
+				std::max((int32)1, index.index->CountEntries())));
+	}
+
+	static type_code IndexGetType(Index& index)
+	{
+		return index.index->Type();
+	}
+
+	static int32 IndexGetKeySize(Index& index)
+	{
+		return index.index->KeyLength();
+	}
+
+	static IndexIterator* IndexCreateIterator(Index& index)
+	{
+		IndexIterator* iterator = new(std::nothrow) IndexIterator(index.index);
+		if (iterator == NULL)
+			return NULL;
+
+		if (!index.index->GetIterator(iterator)) {
+			delete iterator;
+			return NULL;
+		}
+
+		return iterator;
+	}
+
+	// IndexIterator interface
+
+	static void IndexIteratorDelete(IndexIterator* indexIterator)
+	{
+		delete indexIterator;
+	}
+
+	static status_t IndexIteratorFind(IndexIterator* indexIterator,
+		const void* value, size_t size)
+	{
+		if (!indexIterator->index->Find(value, size, indexIterator))
+			return B_ENTRY_NOT_FOUND;
+
+		return B_OK;
+	}
+
+	static status_t IndexIteratorGetNextEntry(IndexIterator* indexIterator,
+		void* value, size_t* _valueLength, size_t bufferSize, Entry** _entry)
+	{
+		Node* node = indexIterator->Next(value, _valueLength);
+		if (node == NULL)
+			return B_ENTRY_NOT_FOUND;
+
+		*_entry = node;
+		return B_OK;
+	}
+
+	// Node interface
+
+	static const off_t NodeGetSize(Node* node)
+	{
+		return node->FileSize();
+	}
+
+	static bigtime_t NodeGetLastModifiedTime(Node* node)
+	{
+		timespec time = node->ModifiedTime();
+		return (bigtime_t)time.tv_sec * 1000000 + time.tv_nsec / 1000;
+	}
+
+	static status_t NodeGetAttribute(Node* node, const char* attribute,
+		void* buffer, size_t* _size, int32* _type)
+	{
+		// TODO: Creating a cookie is quite a bit of overhead.
+		AttributeCookie* cookie;
+		status_t error = node->OpenAttribute(attribute, O_RDONLY, cookie);
+		if (error != B_OK)
+			return error;
+
+		error = cookie->ReadAttribute(0, buffer, _size);
+
+		cookie->Close();
+		delete cookie;
+
+		return error;
+	}
+
+	static Entry* NodeGetFirstReferrer(Node* node)
+	{
+		return node;
+	}
+
+	static Entry* NodeGetNextReferrer(Node* node, Entry* entry)
+	{
+		return NULL;
+	}
+
+	// Volume interface
+
+	static dev_t ContextGetVolumeID(Context* context)
+	{
+		return context->fVolume->ID();
+	}
+};
+
+
+// #pragma mark - Query
+
+
+Query::Query(Volume* volume)
+	:
+	fVolume(volume),
+	fImpl(NULL)
+{
+}
+
+
+Query::~Query()
+{
+	if (fImpl != NULL) {
+		if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
+			fVolume->RemoveQuery(this);
+
+		delete fImpl;
+	}
+}
+
+
+/*static*/ status_t
+Query::Create(Volume* volume, const char* queryString, uint32 flags,
+	port_id port, uint32 token, Query*& _query)
+{
+	Query* query = new(std::nothrow) Query(volume);
+	if (query == NULL)
+		return B_NO_MEMORY;
+
+	status_t error = query->_Init(queryString, flags, port, token);
+	if (error != B_OK) {
+		delete query;
+		return error;
+	}
+
+	_query = query;
+	return B_OK;
+}
+
+
+status_t
+Query::Rewind()
+{
+	return fImpl->Rewind();
+}
+
+
+status_t
+Query::GetNextEntry(struct dirent* entry, size_t size)
+{
+	return fImpl->GetNextEntry(entry, size);
+}
+
+
+void
+Query::LiveUpdate(Node* node, const char* attribute, int32 type,
+	const void* oldKey, size_t oldLength, const void* newKey, size_t newLength)
+{
+	fImpl->LiveUpdate(node, node, attribute, type, (const uint8*)oldKey,
+		oldLength, (const uint8*)newKey, newLength);
+}
+
+
+status_t
+Query::_Init(const char* queryString, uint32 flags, port_id port, uint32 token)
+{
+	status_t error = QueryImpl::Create(this, queryString, flags, port, token,
+		fImpl);
+	if (error != B_OK)
+		return error;
+
+	if ((fImpl->Flags() & B_LIVE_QUERY) != 0)
+		fVolume->AddQuery(this);
+
+	return B_OK;
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/Query.h b/src/add-ons/kernel/file_systems/packagefs/Query.h
new file mode 100644
index 0000000000..0cd7c93744
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/Query.h
@@ -0,0 +1,60 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef QUERY_H
+#define QUERY_H
+
+
+#include 
+
+#include 
+
+
+struct dirent;
+
+namespace QueryParser {
+	template class Query;
+};
+
+class Node;
+class Volume;
+
+
+class Query : public DoublyLinkedListLinkImpl {
+public:
+							~Query();
+
+	static	status_t		Create(Volume* volume, const char* queryString,
+								uint32 flags, port_id port, uint32 token,
+								Query*& _query);
+
+			status_t		Rewind();
+			status_t		GetNextEntry(struct dirent* entry, size_t size);
+
+			void			LiveUpdate(Node* node,
+								const char* attribute, int32 type,
+								const void* oldKey, size_t oldLength,
+								const void* newKey, size_t newLength);
+
+private:
+			struct QueryPolicy;
+			friend struct QueryPolicy;
+			typedef QueryParser::Query QueryImpl;
+
+private:
+							Query(Volume* volume);
+
+			status_t		_Init(const char* queryString, uint32 flags,
+								port_id port, uint32 token);
+
+private:
+			Volume*			fVolume;
+			QueryImpl*		fImpl;
+};
+
+
+typedef DoublyLinkedList QueryList;
+
+
+#endif	// QUERY_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index ccc99ee8ef..166ef61618 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -676,6 +676,33 @@ Volume::RemoveNodeListener(NodeListener* listener)
 }
 
 
+void
+Volume::AddQuery(Query* query)
+{
+	fQueries.Add(query);
+}
+
+
+void
+Volume::RemoveQuery(Query* query)
+{
+	fQueries.Remove(query);
+}
+
+
+void
+Volume::UpdateLiveQueries(Node* node, const char* attribute, int32 type,
+	const void* oldKey, size_t oldLength, const void* newKey,
+	size_t newLength)
+{
+	for (QueryList::Iterator it = fQueries.GetIterator();
+			Query* query = it.Next();) {
+		query->LiveUpdate(node, attribute, type, oldKey, oldLength, newKey,
+			newLength);
+	}
+}
+
+
 status_t
 Volume::GetVNode(ino_t nodeID, Node*& _node)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index 438b134ecf..8986913791 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -19,6 +19,7 @@
 #include "NodeListener.h"
 #include "PackageDomain.h"
 #include "PackageLinksListener.h"
+#include "Query.h"
 
 
 class Directory;
@@ -72,6 +73,14 @@ public:
 									Node* node);
 			void				RemoveNodeListener(NodeListener* listener);
 
+			// query support -- volume must be write-locked
+			void				AddQuery(Query* query);
+			void				RemoveQuery(Query* query);
+			void				UpdateLiveQueries(Node* node,
+									const char* attribute, int32 type,
+									const void* oldKey, size_t oldLength,
+									const void* newKey, size_t newLength);
+
 			Index*				FindIndex(const char* name) const
 									{ return fIndices.Lookup(name); }
 
@@ -192,6 +201,7 @@ private:
 
 			NodeIDHashTable		fNodes;
 			NodeListenerHashTable fNodeListeners;
+			QueryList			fQueries;
 			IndexHashTable		fIndices;
 
 			JobList				fJobQueue;

From b8dae0fe7be1feb1cb982f6fcbae3fe7bc29cd10 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 5 Jul 2011 22:59:48 +0200
Subject: [PATCH 0229/1170] Implement query FS hooks, add empty index FS hooks

---
 .../packagefs/kernel_interface.cpp            | 182 +++++++++++++++++-
 1 file changed, 178 insertions(+), 4 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
index 5364d78b89..3d2f2539a8 100644
--- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
@@ -22,6 +22,7 @@
 #include "DebugSupport.h"
 #include "Directory.h"
 #include "GlobalFactory.h"
+#include "Query.h"
 #include "PackageFSRoot.h"
 #include "Utils.h"
 #include "Volume.h"
@@ -137,7 +138,8 @@ packagefs_read_fs_info(fs_volume* fsVolume, struct fs_info* info)
 
 	FUNCTION("volume: %p, info: %p\n", volume, info);
 
-	info->flags = B_FS_IS_READONLY;
+	info->flags = B_FS_IS_READONLY | B_FS_HAS_MIME | B_FS_HAS_ATTR
+		| B_FS_HAS_QUERY | B_FS_SUPPORTS_NODE_MONITORING;
 	info->block_size = 4096;
 	info->io_size = kOptimalIOSize;
 	info->total_blocks = info->free_blocks = 1;
@@ -843,6 +845,162 @@ packagefs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode,
 }
 
 
+// #pragma mark - index directory & index operations
+
+status_t
+packagefs_open_index_dir(fs_volume* fsVolume, void** _cookie)
+{
+	// TODO:...
+	return B_NOT_SUPPORTED;
+}
+
+
+status_t
+packagefs_close_index_dir(fs_volume* fsVolume, void* cookie)
+{
+	// TODO:...
+	return B_NOT_SUPPORTED;
+}
+
+
+status_t
+packagefs_free_index_dir_cookie(fs_volume* fsVolume, void* cookie)
+{
+	// TODO:...
+	return B_NOT_SUPPORTED;
+}
+
+
+status_t
+packagefs_read_index_dir(fs_volume* fsVolume, void* cookie, struct dirent* buffer,
+	size_t bufferSize, uint32* _num)
+{
+	// TODO:...
+	return B_NOT_SUPPORTED;
+}
+
+
+status_t
+packagefs_rewind_index_dir(fs_volume* fsVolume, void* cookie)
+{
+	// TODO:...
+	return B_NOT_SUPPORTED;
+}
+
+
+status_t
+packagefs_create_index(fs_volume* fsVolume, const char* name, uint32 type,
+	uint32 flags)
+{
+	// TODO:...
+	return B_NOT_SUPPORTED;
+}
+
+
+status_t
+packagefs_remove_index(fs_volume* fsVolume, const char* name)
+{
+	// TODO:...
+	return B_NOT_SUPPORTED;
+}
+
+
+status_t
+packagefs_read_index_stat(fs_volume* fsVolume, const char* name,
+	struct stat* stat)
+{
+	// TODO:...
+	return B_NOT_SUPPORTED;
+}
+
+
+// #pragma mark - query operations
+
+
+status_t
+packagefs_open_query(fs_volume* fsVolume, const char* queryString, uint32 flags,
+	port_id port, uint32 token, void** _cookie)
+{
+	Volume* volume = (Volume*)fsVolume->private_volume;
+
+	FUNCTION("volume: %p, query: \"%s\", flags: %#" B_PRIx32 ", port: %"
+		B_PRId32 ", token: %" B_PRIu32 "\n", volume, queryString, flags, port,
+		token);
+
+	VolumeWriteLocker volumeWriteLocker(volume);
+
+	Query* query;
+	status_t error = Query::Create(volume, queryString, flags, port, token,
+		query);
+	if (error != B_OK)
+		return error;
+
+	*_cookie = query;
+	return B_OK;
+}
+
+
+status_t
+packagefs_close_query(fs_volume* fsVolume, void* cookie)
+{
+	FUNCTION_START();
+	return B_OK;
+}
+
+
+status_t
+packagefs_free_query_cookie(fs_volume* fsVolume, void* cookie)
+{
+	Volume* volume = (Volume*)fsVolume->private_volume;
+	Query* query = (Query*)cookie;
+
+	FUNCTION("volume: %p, query: %p\n", volume, query);
+
+	VolumeWriteLocker volumeWriteLocker(volume);
+
+	delete query;
+
+	return B_OK;
+}
+
+
+status_t
+packagefs_read_query(fs_volume* fsVolume, void* cookie, struct dirent* buffer,
+	size_t bufferSize, uint32* _num)
+{
+	Volume* volume = (Volume*)fsVolume->private_volume;
+	Query* query = (Query*)cookie;
+
+	FUNCTION("volume: %p, query: %p\n", volume, query);
+
+	VolumeWriteLocker volumeWriteLocker(volume);
+
+	status_t error = query->GetNextEntry(buffer, bufferSize);
+	if (error == B_OK)
+		*_num = 1;
+	else if (error == B_ENTRY_NOT_FOUND)
+		*_num = 0;
+	else
+		return error;
+
+	return B_OK;
+}
+
+
+status_t
+packagefs_rewind_query(fs_volume* fsVolume, void* cookie)
+{
+	Volume* volume = (Volume*)fsVolume->private_volume;
+	Query* query = (Query*)cookie;
+
+	FUNCTION("volume: %p, query: %p\n", volume, query);
+
+	VolumeWriteLocker volumeWriteLocker(volume);
+
+	return query->Rewind();
+}
+
+
 // #pragma mark - Module Interface
 
 
@@ -916,10 +1074,26 @@ fs_volume_ops gPackageFSVolumeOps = {
 	NULL,	// write_fs_info,
 	NULL,	// sync,
 
-	&packagefs_get_vnode
+	&packagefs_get_vnode,
+
+	// index directory
+	&packagefs_open_index_dir,
+	&packagefs_close_index_dir,
+	&packagefs_free_index_dir_cookie,
+	&packagefs_read_index_dir,
+	&packagefs_rewind_index_dir,
+
+	&packagefs_create_index,
+	&packagefs_remove_index,
+	&packagefs_read_index_stat,
+
+	// query operations
+	&packagefs_open_query,
+	&packagefs_close_query,
+	&packagefs_free_query_cookie,
+	&packagefs_read_query,
+	&packagefs_rewind_query,
 
-	// TODO: index operations
-	// TODO: query operations
 	// TODO: FS layer operations
 };
 

From 216ba45933836b446b7faf6880d6210dcf6305c3 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 5 Jul 2011 23:00:02 +0200
Subject: [PATCH 0230/1170] Automatic whitespace cleanup

---
 src/bin/query.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/bin/query.cpp b/src/bin/query.cpp
index 7191014c6b..d7e553bde2 100644
--- a/src/bin/query.cpp
+++ b/src/bin/query.cpp
@@ -115,7 +115,7 @@ main(int argc, char **argv)
 {
 	// Make sure we have the minimum number of arguments.
 	if (argc < 2)
-		usage();	
+		usage();
 
 	// Which volume do we make the query on?
 	// Default to the current volume.
@@ -169,7 +169,7 @@ main(int argc, char **argv)
 			fprintf(stderr, "%s: volume containing %s is not query-enabled\n", kProgramName, volumePath);
 		else
 			perform_query(volume, argv[optind]);
-	} else {	
+	} else {
 		// Okay, we want to query all the disks -- so iterate over
 		// them, one by one, running the query.
 		BVolumeRoster volumeRoster;

From d612248dcf6c31901ed9961db65171caeafe3729 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 6 Jul 2011 14:58:08 +0200
Subject: [PATCH 0231/1170] Cleanup

---
 .../file_systems/packagefs/NameIndex.cpp      | 58 +++++++++----------
 1 file changed, 29 insertions(+), 29 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
index fd160ef5a4..1cf534f17b 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
@@ -4,13 +4,14 @@
  */
 
 
+#include "NameIndex.h"
+
 #include 
 
 #include 
 
 #include "DebugSupport.h"
 #include "IndexImpl.h"
-#include "NameIndex.h"
 #include "Node.h"
 #include "Volume.h"
 
@@ -24,8 +25,8 @@ public:
 		:
 		entry(entry),
 		name(name ? name : entry->Name())
-		{
-		}
+	{
+	}
 
 	NameIndexPrimaryKey(const char* name)
 		:
@@ -59,8 +60,7 @@ public:
 // #pragma mark - NameIndexPrimaryKeyCompare
 
 
-class NameIndexPrimaryKeyCompare
-{
+class NameIndexPrimaryKeyCompare {
 public:
 	inline int operator()(const NameIndexPrimaryKey &a,
 		const NameIndexPrimaryKey &b) const
@@ -171,7 +171,7 @@ NameIndex::NodeAdded(Node* node)
 {
 	fEntries->Insert(node);
 
-	// udpate live queries
+	// update live queries
 	_UpdateLiveQueries(node, NULL, node->Name());
 }
 
@@ -181,7 +181,7 @@ NameIndex::NodeRemoved(Node* node)
 {
 	fEntries->Remove(node, node);
 
-	// udpate live queries
+	// update live queries
 	_UpdateLiveQueries(node, node->Name(), NULL);
 }
 
@@ -317,28 +317,28 @@ NameIndexIterator::Next()
 status_t
 NameIndexIterator::Suspend()
 {
-	status_t error = !fSuspended ? B_OK : B_BAD_VALUE;
-	if (error == B_OK) {
-		if (fIterator.Current() != NULL)
-			fIndex->GetVolume()->AddNodeListener(this, *fIterator.Current());
+	if (fSuspended)
+		return B_BAD_VALUE;
 
-		fSuspended = true;
-	}
-	return error;
+	if (fIterator.Current() != NULL)
+		fIndex->GetVolume()->AddNodeListener(this, *fIterator.Current());
+
+	fSuspended = true;
+	return B_OK;
 }
 
 
 status_t
 NameIndexIterator::Resume()
 {
-	status_t error = fSuspended ? B_OK : B_BAD_VALUE;
-	if (error == B_OK) {
-		if (fIterator.Current() != NULL)
-			fIndex->GetVolume()->RemoveNodeListener(this);
+	if (!fSuspended)
+		return B_BAD_VALUE;
 
-		fSuspended = false;
-	}
-	return error;
+	if (fIterator.Current() != NULL)
+		fIndex->GetVolume()->RemoveNodeListener(this);
+
+	fSuspended = false;
+	return B_OK;
 }
 
 
@@ -350,14 +350,14 @@ NameIndexIterator::SetTo(NameIndex* index, const char* name, bool ignoreValue)
 	fIndex = index;
 	fSuspended = false;
 	fIsNext = false;
-	if (fIndex != NULL) {
-		if (ignoreValue) {
-			fIndex->fEntries->GetIterator(&fIterator);
-			return fIterator.Current() != NULL;
-		}
-		return fIndex->fEntries->FindFirst(name, &fIterator);
+	if (fIndex == NULL)
+		return false;
+
+	if (ignoreValue) {
+		fIndex->fEntries->GetIterator(&fIterator);
+		return fIterator.Current() != NULL;
 	}
-	return false;
+	return fIndex->fEntries->FindFirst(name, &fIterator);
 }
 
 
@@ -365,6 +365,6 @@ void
 NameIndexIterator::NodeRemoved(Node* node)
 {
 	Resume();
-	fIsNext = Next();
+	fIsNext = Next() != NULL;
 	Suspend();
 }

From 20b22dfc3d24ba812ceeaff56c701bdc26d49ba3 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 07:46:22 +0200
Subject: [PATCH 0232/1170] AVLTree: Add Previous()/Next()

---
 headers/private/kernel/util/AVLTree.h | 27 +++++++++++++++++++++++++++
 1 file changed, 27 insertions(+)

diff --git a/headers/private/kernel/util/AVLTree.h b/headers/private/kernel/util/AVLTree.h
index eb8964e627..76d6b255eb 100644
--- a/headers/private/kernel/util/AVLTree.h
+++ b/headers/private/kernel/util/AVLTree.h
@@ -44,6 +44,9 @@ public:
 
 			Value*				RootNode() const;
 
+			Value*				Previous(Value* value) const;
+			Value*				Next(Value* value) const;
+
 	inline	Iterator			GetIterator();
 	inline	ConstIterator		GetIterator() const;
 
@@ -228,6 +231,30 @@ AVLTree::RootNode() const
 }
 
 
+template
+inline typename AVLTree::Value*
+AVLTree::Previous(Value* value) const
+{
+	if (value == NULL)
+		return NULL;
+
+	AVLTreeNode* node = fTree.Previous(_GetAVLTreeNode(value));
+	return node != NULL ? _GetValue(node) : NULL;
+}
+
+
+template
+inline typename AVLTree::Value*
+AVLTree::Next(Value* value) const
+{
+	if (value == NULL)
+		return NULL;
+
+	AVLTreeNode* node = fTree.Next(_GetAVLTreeNode(value));
+	return node != NULL ? _GetValue(node) : NULL;
+}
+
+
 template
 inline typename AVLTree::Iterator
 AVLTree::GetIterator()

From 0c19263c85c5bdc6742227dc8311e0d83f476ec5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 07:48:09 +0200
Subject: [PATCH 0233/1170] AVLTreeMap/TwoKeyAVLTree: More access to nodes

both:
* Add Previous()/Next().
* Add Insert() version that returns a Node* instead of an Iterator.
* Add Remove() version that takes a Node* instead of a key.

TwoKeyAVLTree:
* Add GetIterator() version that takes an additional Node*, i.e.
  initializing an iterator to point to the node.
* Add Iterator::CurrentNode().
---
 headers/private/kernel/util/AVLTreeMap.h    | 78 +++++++++++++++++++++
 headers/private/kernel/util/TwoKeyAVLTree.h | 57 ++++++++++++++-
 2 files changed, 134 insertions(+), 1 deletion(-)

diff --git a/headers/private/kernel/util/AVLTreeMap.h b/headers/private/kernel/util/AVLTreeMap.h
index a6a978572b..0ff6c090d9 100644
--- a/headers/private/kernel/util/AVLTreeMap.h
+++ b/headers/private/kernel/util/AVLTreeMap.h
@@ -65,6 +65,9 @@ public:
 
 			Node*				RootNode() const;
 
+			Node*				Previous(Node* node) const;
+			Node*				Next(Node* node) const;
+
 	inline	Iterator			GetIterator();
 	inline	ConstIterator		GetIterator() const;
 
@@ -76,7 +79,10 @@ public:
 
 			status_t			Insert(const Key& key, const Value& value,
 									Iterator* iterator);
+			status_t			Insert(const Key& key, const Value& value,
+									Node** _node = NULL);
 			status_t			Remove(const Key& key);
+			status_t			Remove(Node* node);
 
 			const NodeStrategy&	GetNodeStrategy() const	{ return fStrategy; }
 
@@ -185,6 +191,13 @@ public:
 		return NULL;
 	}
 
+	inline Node* CurrentNode()
+	{
+		if (AVLTreeNode* node = fTreeIterator.Current())
+			return fParent->_GetNode(node);
+		return NULL;
+	}
+
 	inline bool HasNext() const
 	{
 		return fTreeIterator.HasNext();
@@ -270,6 +283,32 @@ _AVL_TREE_MAP_CLASS_NAME::RootNode() const
 }
 
 
+// Previous
+_AVL_TREE_MAP_TEMPLATE_LIST
+inline typename _AVL_TREE_MAP_CLASS_NAME::Node*
+_AVL_TREE_MAP_CLASS_NAME::Previous(Node* node) const
+{
+	if (node == NULL)
+		return NULL;
+
+	AVLTreeNode* treeNode = fTree.Previous(_GetAVLTreeNode(node));
+	return treeNode != NULL ? _GetNode(treeNode) : NULL;
+}
+
+
+// Next
+_AVL_TREE_MAP_TEMPLATE_LIST
+inline typename _AVL_TREE_MAP_CLASS_NAME::Node*
+_AVL_TREE_MAP_CLASS_NAME::Next(Node* node) const
+{
+	if (node == NULL)
+		return NULL;
+
+	AVLTreeNode* treeNode = fTree.Next(_GetAVLTreeNode(node));
+	return treeNode != NULL ? _GetNode(treeNode) : NULL;
+}
+
+
 // GetIterator
 _AVL_TREE_MAP_TEMPLATE_LIST
 inline typename _AVL_TREE_MAP_CLASS_NAME::Iterator
@@ -354,6 +393,32 @@ _AVL_TREE_MAP_CLASS_NAME::Insert(const Key& key, const Value& value,
 }
 
 
+// Insert
+_AVL_TREE_MAP_TEMPLATE_LIST
+status_t
+_AVL_TREE_MAP_CLASS_NAME::Insert(const Key& key, const Value& value,
+	Node** _node)
+{
+	// allocate a node
+	Node* userNode = _Allocate(key, value);
+	if (!userNode)
+		return B_NO_MEMORY;
+
+	// insert node
+	AVLTreeNode* node = _GetAVLTreeNode(userNode);
+	status_t error = fTree.Insert(node);
+	if (error != B_OK) {
+		_Free(userNode);
+		return error;
+	}
+
+	if (_node != NULL)
+		*_node = userNode;
+
+	return B_OK;
+}
+
+
 // Remove
 _AVL_TREE_MAP_TEMPLATE_LIST
 status_t
@@ -368,6 +433,19 @@ _AVL_TREE_MAP_CLASS_NAME::Remove(const Key& key)
 }
 
 
+// Remove
+_AVL_TREE_MAP_TEMPLATE_LIST
+status_t
+_AVL_TREE_MAP_CLASS_NAME::Remove(Node* node)
+{
+	if (!fTree.Remove(node))
+		return B_ENTRY_NOT_FOUND;
+
+	_Free(node);
+	return B_OK;
+}
+
+
 // CompareKeyNode
 _AVL_TREE_MAP_TEMPLATE_LIST
 int
diff --git a/headers/private/kernel/util/TwoKeyAVLTree.h b/headers/private/kernel/util/TwoKeyAVLTree.h
index 9ab0525968..5286ac864a 100644
--- a/headers/private/kernel/util/TwoKeyAVLTree.h
+++ b/headers/private/kernel/util/TwoKeyAVLTree.h
@@ -274,6 +274,9 @@ public:
 
 	inline	int					CountItems() const	{ return fTreeMap.Count(); }
 
+			Node*				Previous(Node* node) const;
+			Node*				Next(Node* node) const;
+
 			Value*				FindFirst(const PrimaryKey& key,
 									Iterator* iterator = NULL);
 			Value*				FindLast(const PrimaryKey& key,
@@ -283,11 +286,15 @@ public:
 									Iterator* iterator = NULL);
 
 	inline	void				GetIterator(Iterator* iterator);
+	inline	void				GetIterator(Node* node, Iterator* iterator);
 
 	inline	status_t			Insert(const Value& value,
-									Iterator* iterator = NULL);
+									Iterator* iterator);
+	inline	status_t			Insert(const Value& value,
+									Node** _node = NULL);
 	inline	status_t			Remove(const PrimaryKey& primaryKey,
 									const SecondaryKey& secondaryKey);
+	inline	status_t			Remove(Node* node);
 
 private:
 			TreeMap				fTreeMap;
@@ -320,6 +327,11 @@ public:
 		return fIterator.CurrentValuePointer();
 	}
 
+	inline Node* CurrentNode()
+	{
+		return fIterator.CurrentNode();
+	}
+
 	inline Value* Next()
 	{
 		fIterator.Next();
@@ -398,6 +410,22 @@ TWO_KEY_AVL_TREE_CLASS_NAME::~TwoKeyAVLTree()
 }
 
 
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+typename TWO_KEY_AVL_TREE_CLASS_NAME::Node*
+TWO_KEY_AVL_TREE_CLASS_NAME::Previous(Node* node) const
+{
+	return fTreeMap.Previous(node);
+}
+
+
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+typename TWO_KEY_AVL_TREE_CLASS_NAME::Node*
+TWO_KEY_AVL_TREE_CLASS_NAME::Next(Node* node) const
+{
+	return fTreeMap.Next(node);
+}
+
+
 TWO_KEY_AVL_TREE_TEMPLATE_LIST
 Value*
 TWO_KEY_AVL_TREE_CLASS_NAME::FindFirst(const PrimaryKey& key,
@@ -484,6 +512,14 @@ TWO_KEY_AVL_TREE_CLASS_NAME::GetIterator(Iterator* iterator)
 }
 
 
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+void
+TWO_KEY_AVL_TREE_CLASS_NAME::GetIterator(Node* node, Iterator* iterator)
+{
+	iterator->_SetTo(fTreeMap.GetIterator(node));
+}
+
+
 TWO_KEY_AVL_TREE_TEMPLATE_LIST
 status_t
 TWO_KEY_AVL_TREE_CLASS_NAME::Insert(const Value& value, Iterator* iterator)
@@ -501,6 +537,17 @@ TWO_KEY_AVL_TREE_CLASS_NAME::Insert(const Value& value, Iterator* iterator)
 }
 
 
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+status_t
+TWO_KEY_AVL_TREE_CLASS_NAME::Insert(const Value& value, Node** _node)
+{
+	NodeStrategy& strategy
+		= const_cast(fTreeMap.GetNodeStrategy());
+
+	return fTreeMap.Insert(strategy.GetValueKey(value), value, _node);
+}
+
+
 TWO_KEY_AVL_TREE_TEMPLATE_LIST
 status_t
 TWO_KEY_AVL_TREE_CLASS_NAME::Remove(const PrimaryKey& primaryKey,
@@ -510,4 +557,12 @@ TWO_KEY_AVL_TREE_CLASS_NAME::Remove(const PrimaryKey& primaryKey,
 }
 
 
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+status_t
+TWO_KEY_AVL_TREE_CLASS_NAME::Remove(Node* node)
+{
+	return fTreeMap.Remove(node);
+}
+
+
 #endif	// _KERNEL_UTIL_TWO_KEY_AVL_TREE_H

From 9811f22cabcc8708113e833ddde6748d9435f66a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 07:59:09 +0200
Subject: [PATCH 0234/1170] QueryParser: Explicitly suspend/resume iterators

Extended policy by IndexIteratorSuspend() and IndexIteratorResume()
methods that are invoked for the index iterator by Query::GetNextEntry()
after entering respectively before exiting.
---
 headers/private/file_systems/QueryParser.h    | 77 +++++++++++--------
 .../kernel/file_systems/packagefs/Query.cpp   | 10 +++
 2 files changed, 57 insertions(+), 30 deletions(-)

diff --git a/headers/private/file_systems/QueryParser.h b/headers/private/file_systems/QueryParser.h
index 05d82ca7e2..774d7857a8 100644
--- a/headers/private/file_systems/QueryParser.h
+++ b/headers/private/file_systems/QueryParser.h
@@ -150,7 +150,7 @@ public:
 								Query*& _query);
 
 			status_t		Rewind();
-			status_t		GetNextEntry(struct dirent* , size_t size);
+	inline	status_t		GetNextEntry(struct dirent* dirent, size_t size);
 
 			void			LiveUpdate(Entry* entry, Node* node,
 								const char* attribute, int32 type,
@@ -168,6 +168,7 @@ public:
 								{ return fFlags; }
 
 private:
+			status_t		_GetNextEntry(struct dirent* dirent, size_t size);
 			void			_SendEntryNotification(Entry* entry,
 								status_t (*notify)(port_id, int32, dev_t, ino_t,
 									const char*, ino_t));
@@ -1755,38 +1756,15 @@ template
 status_t
 Query::GetNextEntry(struct dirent* dirent, size_t size)
 {
-	// If we don't have an equation to use yet/anymore, get a new one
-	// from the stack
-	while (true) {
-		if (fIterator == NULL) {
-			if (!fStack.Pop(&fCurrent)
-				|| fCurrent == NULL)
-				return B_ENTRY_NOT_FOUND;
+	if (fIterator != NULL)
+		QueryPolicy::IndexIteratorResume(fIterator);
 
-			status_t status = fCurrent->PrepareQuery(fContext, fIndex,
-				&fIterator, fFlags & B_QUERY_NON_INDEXED);
-			if (status == B_ENTRY_NOT_FOUND) {
-				// try next equation
-				continue;
-			}
+	status_t error = _GetNextEntry(dirent, size);
 
-			if (status != B_OK)
-				return status;
-		}
-		if (fCurrent == NULL)
-			QUERY_RETURN_ERROR(B_ERROR);
+	if (fIterator != NULL)
+		QueryPolicy::IndexIteratorSuspend(fIterator);
 
-		status_t status = fCurrent->GetNextMatching(fContext, fIterator, dirent,
-			size);
-		if (status != B_OK) {
-			QueryPolicy::IndexIteratorDelete(fIterator);
-			fIterator = NULL;
-			fCurrent = NULL;
-		} else {
-			// only return if we have another entry
-			return B_OK;
-		}
-	}
+	return error;
 }
 
 
@@ -1897,6 +1875,45 @@ Query::LiveUpdateRenameMove(Entry* entry, Node* node,
 }
 
 
+template
+status_t
+Query::_GetNextEntry(struct dirent* dirent, size_t size)
+{
+	// If we don't have an equation to use yet/anymore, get a new one
+	// from the stack
+	while (true) {
+		if (fIterator == NULL) {
+			if (!fStack.Pop(&fCurrent)
+				|| fCurrent == NULL)
+				return B_ENTRY_NOT_FOUND;
+
+			status_t status = fCurrent->PrepareQuery(fContext, fIndex,
+				&fIterator, fFlags & B_QUERY_NON_INDEXED);
+			if (status == B_ENTRY_NOT_FOUND) {
+				// try next equation
+				continue;
+			}
+
+			if (status != B_OK)
+				return status;
+		}
+		if (fCurrent == NULL)
+			QUERY_RETURN_ERROR(B_ERROR);
+
+		status_t status = fCurrent->GetNextMatching(fContext, fIterator, dirent,
+			size);
+		if (status != B_OK) {
+			QueryPolicy::IndexIteratorDelete(fIterator);
+			fIterator = NULL;
+			fCurrent = NULL;
+		} else {
+			// only return if we have another entry
+			return B_OK;
+		}
+	}
+}
+
+
 template
 void
 Query::_SendEntryNotification(Entry* entry,
diff --git a/src/add-ons/kernel/file_systems/packagefs/Query.cpp b/src/add-ons/kernel/file_systems/packagefs/Query.cpp
index 0c9078944e..05424e1087 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Query.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Query.cpp
@@ -154,6 +154,16 @@ struct Query::QueryPolicy {
 		return B_OK;
 	}
 
+	static void IndexIteratorSuspend(IndexIterator* indexIterator)
+	{
+		indexIterator->Suspend();
+	}
+
+	static void IndexIteratorResume(IndexIterator* indexIterator)
+	{
+		indexIterator->Resume();
+	}
+
 	// Node interface
 
 	static const off_t NodeGetSize(Node* node)

From 747578cd93d7220c99fd704d442477dab2e360b4 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 08:01:44 +0200
Subject: [PATCH 0235/1170] Fix NameIndexPrimaryKeyCompare

It was actually returning whether the names where not equal.
---
 src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
index 1cf534f17b..d2b69c5774 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
@@ -67,7 +67,7 @@ public:
 	{
 		if (a.entry != NULL && a.entry == b.entry)
 			return 0;
-		return strcmp(a.name, b.name) != 0;
+		return strcmp(a.name, b.name);
 	}
 };
 

From 32ad4ceefb2f3f933396654817a4d2f361716cc8 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 08:06:16 +0200
Subject: [PATCH 0236/1170] Simplify [Abstract]IndexIterator interface

* Remove Current() and Previous() and add a HasNext() instead.
* Reimplement NameIndexIterator. It directly works with tree nodes
  instead of using an iterator, now.
---
 .../kernel/file_systems/packagefs/Index.cpp   | 27 +----
 .../kernel/file_systems/packagefs/Index.h     |  4 +-
 .../kernel/file_systems/packagefs/IndexImpl.h |  6 +-
 .../file_systems/packagefs/NameIndex.cpp      | 99 +++++++++----------
 4 files changed, 53 insertions(+), 83 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Index.cpp b/src/add-ons/kernel/file_systems/packagefs/Index.cpp
index 88cc9fcb2b..b0ccfb747e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Index.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Index.cpp
@@ -117,41 +117,24 @@ IndexIterator::~IndexIterator()
 }
 
 
-Node*
-IndexIterator::Current()
+bool
+IndexIterator::HasNext() const
 {
-	return fIterator != NULL ? fIterator->Current() : NULL;
-}
-
-
-Node*
-IndexIterator::Current(void* buffer, size_t* _keyLength)
-{
-	return fIterator != NULL ? fIterator->Current(buffer, _keyLength) : NULL;
-}
-
-
-Node*
-IndexIterator::Previous()
-{
-	return fIterator != NULL ? fIterator->Previous() : NULL;
+	return fIterator != NULL && fIterator->HasNext();
 }
 
 
 Node*
 IndexIterator::Next()
 {
-	return fIterator != NULL ? fIterator->Next() : NULL;
+	return fIterator != NULL ? fIterator->Next(NULL, NULL) : NULL;
 }
 
 
 Node*
 IndexIterator::Next(void* buffer, size_t* _keyLength)
 {
-	Node* node = NULL;
-	if (fIterator != NULL && fIterator->Next())
-		node = Current(buffer, _keyLength);
-	return node;
+	return fIterator != NULL ? fIterator->Next(buffer, _keyLength) : NULL;
 }
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Index.h b/src/add-ons/kernel/file_systems/packagefs/Index.h
index cd3c69315e..204d95b372 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Index.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Index.h
@@ -73,9 +73,7 @@ public:
 								IndexIterator(Index* index);
 								~IndexIterator();
 
-			Node*				Current();
-			Node*				Current(void* buffer, size_t* _keyLength);
-			Node*				Previous();
+			bool				HasNext() const;
 			Node*				Next();
 			Node*				Next(void* buffer, size_t* _keyLength);
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
index 3dae8e6277..1805d9fb86 100644
--- a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
+++ b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
@@ -15,10 +15,8 @@ public:
 								AbstractIndexIterator();
 	virtual						~AbstractIndexIterator();
 
-	virtual Node*				Current() = 0;
-	virtual Node*				Current(void* buffer, size_t* _keyLength) = 0;
-	virtual Node*				Previous() = 0;
-	virtual Node*				Next() = 0;
+	virtual	bool				HasNext() const = 0;
+	virtual Node*				Next(void* buffer, size_t* _keyLength) = 0;
 
 	virtual	status_t			Suspend();
 	virtual	status_t			Resume();
diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
index d2b69c5774..ebc8a767ec 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
@@ -91,10 +91,8 @@ public:
 								NameIndexIterator();
 	virtual						~NameIndexIterator();
 
-	virtual	Node*				Current();
-	virtual	Node*				Current(void* buffer, size_t* _keyLength);
-	virtual	Node*				Previous();
-	virtual	Node*				Next();
+	virtual	bool				HasNext() const;
+	virtual	Node*				Next(void* buffer, size_t* _keyLength);
 
 	virtual	status_t			Suspend();
 	virtual	status_t			Resume();
@@ -107,13 +105,15 @@ public:
 private:
 			friend class NameIndex;
 
-			typedef AbstractIndexIterator BaseClass;
+			typedef NameIndex::EntryTree EntryTree;
+
+private:
+	inline	Node*				_ToNode() const;
 
 private:
 			NameIndex*			fIndex;
-			NameIndex::EntryTree::Iterator fIterator;
+			EntryTree::Node*	fNextTreeNode;
 			bool				fSuspended;
-			bool				fIsNext;
 };
 
 
@@ -255,9 +255,8 @@ NameIndexIterator::NameIndexIterator()
 	:
 	AbstractIndexIterator(),
 	fIndex(NULL),
-	fIterator(),
-	fSuspended(false),
-	fIsNext(false)
+	fNextTreeNode(NULL),
+	fSuspended(false)
 {
 }
 
@@ -268,60 +267,41 @@ NameIndexIterator::~NameIndexIterator()
 }
 
 
-Node*
-NameIndexIterator::Current()
+bool
+NameIndexIterator::HasNext() const
 {
-	return fIndex != NULL
-		&& fIterator.Current() != NULL ? *fIterator.Current() : NULL;
+	return fNextTreeNode != NULL;
 }
 
 
 Node*
-NameIndexIterator::Current(void* buffer, size_t* _keyLength)
+NameIndexIterator::Next(void* buffer, size_t* _keyLength)
 {
-	Node* entry = Current();
+	if (fSuspended || fNextTreeNode == NULL)
+		return NULL;
+
+	Node* entry = _ToNode();
 	if (entry != NULL) {
-		strlcpy((char*)buffer, entry->Name(), kMaxIndexKeyLength);
-		*_keyLength = strlen(entry->Name());
+		if (buffer != NULL) {
+			strlcpy((char*)buffer, entry->Name(), kMaxIndexKeyLength);
+			*_keyLength = strlen(entry->Name());
+		}
+
+		fNextTreeNode = fIndex->fEntries->Next(fNextTreeNode);
 	}
+
 	return entry;
 }
 
 
-Node*
-NameIndexIterator::Previous()
-{
-	if (fSuspended)
-		return NULL;
-	if (!(fIterator.Current() != NULL && fIsNext))
-		fIterator.Previous();
-	fIsNext = false;
-	return fIndex != NULL
-		&& fIterator.Current() != NULL ? *fIterator.Current() : NULL;
-}
-
-
-Node*
-NameIndexIterator::Next()
-{
-	if (fSuspended)
-		return NULL;
-	if (!(fIterator.Current() != NULL && fIsNext))
-		fIterator.Next();
-	fIsNext = false;
-	return fIndex != NULL
-		&& fIterator.Current() != NULL ? *fIterator.Current() : NULL;
-}
-
-
 status_t
 NameIndexIterator::Suspend()
 {
 	if (fSuspended)
 		return B_BAD_VALUE;
 
-	if (fIterator.Current() != NULL)
-		fIndex->GetVolume()->AddNodeListener(this, *fIterator.Current());
+	if (fNextTreeNode != NULL)
+		fIndex->GetVolume()->AddNodeListener(this, _ToNode());
 
 	fSuspended = true;
 	return B_OK;
@@ -334,7 +314,7 @@ NameIndexIterator::Resume()
 	if (!fSuspended)
 		return B_BAD_VALUE;
 
-	if (fIterator.Current() != NULL)
+	if (fNextTreeNode != NULL)
 		fIndex->GetVolume()->RemoveNodeListener(this);
 
 	fSuspended = false;
@@ -349,15 +329,19 @@ NameIndexIterator::SetTo(NameIndex* index, const char* name, bool ignoreValue)
 
 	fIndex = index;
 	fSuspended = false;
-	fIsNext = false;
+	fNextTreeNode = NULL;
+
 	if (fIndex == NULL)
 		return false;
 
-	if (ignoreValue) {
-		fIndex->fEntries->GetIterator(&fIterator);
-		return fIterator.Current() != NULL;
-	}
-	return fIndex->fEntries->FindFirst(name, &fIterator);
+	EntryTree::Iterator iterator;
+	if (ignoreValue)
+		fIndex->fEntries->GetIterator(&iterator);
+	else if (fIndex->fEntries->FindFirst(name, &iterator) == NULL)
+		return false;
+
+	fNextTreeNode = iterator.CurrentNode();
+	return fNextTreeNode != NULL;
 }
 
 
@@ -365,6 +349,13 @@ void
 NameIndexIterator::NodeRemoved(Node* node)
 {
 	Resume();
-	fIsNext = Next() != NULL;
+	Next(NULL, NULL);
 	Suspend();
 }
+
+
+Node*
+NameIndexIterator::_ToNode() const
+{
+	return EntryTree::NodeStrategy().GetValue(fNextTreeNode);
+}

From 49d2f608d49b268db9136c8acbd328842bfee891 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 08:10:15 +0200
Subject: [PATCH 0237/1170] Name::Index(): Fix initialization order

Add the node listener directly after calling the base class Init().
Otherwise, on error, the we could try to remove the listener although it
wasn't added in the first place.
---
 src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp | 5 ++---
 1 file changed, 2 insertions(+), 3 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
index ebc8a767ec..6172195e6d 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
@@ -148,13 +148,12 @@ NameIndex::Init(Volume* volume)
 	if (error != B_OK)
 		return error;
 
+	fVolume->AddNodeListener(this, NULL);
+
 	fEntries = new(std::nothrow) EntryTree;
 	if (fEntries == NULL)
 		return B_NO_MEMORY;
 
-	fVolume = volume;
-	fVolume->AddNodeListener(this, NULL);
-
 	return B_OK;
 }
 

From fb88975a7b9c3a7a3ef2bf9025ae83c73e859a2c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 08:12:28 +0200
Subject: [PATCH 0238/1170] ~NameIndex(): Make more robust

Remove the listener only, if it was registered.
---
 src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
index 6172195e6d..c142215c2c 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
@@ -130,7 +130,7 @@ NameIndex::NameIndex()
 
 NameIndex::~NameIndex()
 {
-	if (fVolume != NULL)
+	if (IsListening())
 		fVolume->RemoveNodeListener(this);
 
 	delete fEntries;

From 9b2a17084229a86d31dc4537132f5eb33c405f4d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 08:30:21 +0200
Subject: [PATCH 0239/1170] PackageLinkSymlink: Init fLinkPath in constructor

---
 .../kernel/file_systems/packagefs/PackageLinkSymlink.cpp   | 7 +++++--
 1 file changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
index 9ae5b07863..1d0e7a31e9 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
@@ -21,6 +21,8 @@ static const char* const kSystemLinkPath = "../..";
 static const char* const kCommonLinkPath = "../../../common";
 static const char* const kHomeLinkPath = "../../../home/config";
 
+static const char* const kUnknownLinkTarget = "?";
+
 
 static const char*
 link_path_for_mount_type(MountType type)
@@ -44,7 +46,8 @@ link_path_for_mount_type(MountType type)
 
 PackageLinkSymlink::PackageLinkSymlink(Package* package)
 	:
-	Node(0)
+	Node(0),
+	fLinkPath(kUnknownLinkTarget)
 {
 	Update(package, NULL);
 }
@@ -62,7 +65,7 @@ PackageLinkSymlink::Update(Package* package, PackageLinksListener* listener)
 		fLinkPath = link_path_for_mount_type(
 			package->Domain()->Volume()->MountType());
 	} else
-		fLinkPath = "?";
+		fLinkPath = kUnknownLinkTarget;
 
 	get_real_time(fModifiedTime);
 

From 773005292a36c2a1f7cd1eed4fe3a7ca8fc95559 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 08:38:02 +0200
Subject: [PATCH 0240/1170] NodeListener::NodeChanged(): Provide old value

* Add interface OldNodeAttributes an instance of which is passed to
  NodeListener::NodeChanged() to provide the old attribute values
  (currently only modification time and file size).
* Also extend PackageLinksListener::PackageLinkNodeChanged() with a
  OldNodeAttributes parameter.
* Add OldNodeAttributes implementations for PackageLinkSymlink (inner
  class OldAttributes) and UnpackingNode (OldUnpackageNodeAttributes).
---
 .../kernel/file_systems/packagefs/Jamfile     |  1 +
 .../file_systems/packagefs/NameIndex.cpp      |  3 +-
 .../kernel/file_systems/packagefs/NameIndex.h |  3 +-
 .../file_systems/packagefs/NodeListener.cpp   | 14 +++++++-
 .../file_systems/packagefs/NodeListener.h     | 14 +++++++-
 .../packagefs/OldUnpackingNodeAttributes.cpp  | 35 +++++++++++++++++++
 .../packagefs/OldUnpackingNodeAttributes.h    | 28 +++++++++++++++
 .../packagefs/PackageLinkSymlink.cpp          | 34 ++++++++++++++++--
 .../packagefs/PackageLinkSymlink.h            |  3 ++
 .../packagefs/PackageLinksListener.h          |  4 ++-
 .../kernel/file_systems/packagefs/Volume.cpp  | 27 +++++++++-----
 .../kernel/file_systems/packagefs/Volume.h    |  6 ++--
 12 files changed, 154 insertions(+), 18 deletions(-)
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.cpp
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.h

diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile
index 5c7584a97e..f07377cf06 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Jamfile
+++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile
@@ -21,6 +21,7 @@ HAIKU_PACKAGE_FS_SOURCES =
 	NameIndex.cpp
 	Node.cpp
 	NodeListener.cpp
+	OldUnpackingNodeAttributes.cpp
 	Query.cpp
 	Package.cpp
 	PackageDirectory.cpp
diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
index c142215c2c..601f965c3e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
@@ -186,7 +186,8 @@ NameIndex::NodeRemoved(Node* node)
 
 
 void
-NameIndex::NodeChanged(Node* node, uint32 statFields)
+NameIndex::NodeChanged(Node* node, uint32 statFields,
+	const OldNodeAttributes& oldAttributes)
 {
 	// nothing to do -- the name remains the same
 }
diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.h b/src/add-ons/kernel/file_systems/packagefs/NameIndex.h
index 3fceabedfb..7e8ed7bfc6 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.h
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.h
@@ -25,7 +25,8 @@ public:
 private:
 	virtual	void				NodeAdded(Node* node);
 	virtual	void				NodeRemoved(Node* node);
-	virtual	void				NodeChanged(Node* node, uint32 statFields);
+	virtual	void				NodeChanged(Node* node, uint32 statFields,
+									const OldNodeAttributes& oldAttributes);
 
 protected:
 	virtual	AbstractIndexIterator* InternalGetIterator();
diff --git a/src/add-ons/kernel/file_systems/packagefs/NodeListener.cpp b/src/add-ons/kernel/file_systems/packagefs/NodeListener.cpp
index bd5b826a16..ae77b4c1dc 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NodeListener.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NodeListener.cpp
@@ -7,6 +7,17 @@
 #include "NodeListener.h"
 
 
+// #pragma mark - OldNodeAttributes
+
+
+OldNodeAttributes::~OldNodeAttributes()
+{
+}
+
+
+// #pragma mark - NodeListener
+
+
 NodeListener::NodeListener()
 	:
 	fPrevious(this),
@@ -34,6 +45,7 @@ NodeListener::NodeRemoved(Node* node)
 
 
 void
-NodeListener::NodeChanged(Node* node, uint32 statFields)
+NodeListener::NodeChanged(Node* node, uint32 statFields,
+	const OldNodeAttributes& oldAttributes)
 {
 }
diff --git a/src/add-ons/kernel/file_systems/packagefs/NodeListener.h b/src/add-ons/kernel/file_systems/packagefs/NodeListener.h
index 5c21c95d12..35ab10e19a 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NodeListener.h
+++ b/src/add-ons/kernel/file_systems/packagefs/NodeListener.h
@@ -6,6 +6,8 @@
 #define NODE_LISTENER_H
 
 
+#include 
+
 #include 
 #include 
 
@@ -16,6 +18,15 @@ class Node;
 #define NOT_LISTENING_NODE	((Node*)~(addr_t)0)
 
 
+class OldNodeAttributes {
+public:
+	virtual						~OldNodeAttributes();
+
+	virtual	timespec			ModifiedTime() const = 0;
+	virtual	off_t				FileSize() const = 0;
+};
+
+
 class NodeListener {
 public:
 								NodeListener();
@@ -23,7 +34,8 @@ public:
 
 	virtual	void				NodeAdded(Node* node);
 	virtual	void				NodeRemoved(Node* node);
-	virtual	void				NodeChanged(Node* node, uint32 statFields);
+	virtual	void				NodeChanged(Node* node, uint32 statFields,
+									const OldNodeAttributes& oldAttributes);
 
 			void				StartedListening(Node* node)
 									{ fNode = node; }
diff --git a/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.cpp b/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.cpp
new file mode 100644
index 0000000000..f4508edb41
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.cpp
@@ -0,0 +1,35 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "OldUnpackingNodeAttributes.h"
+
+#include "PackageNode.h"
+
+
+OldUnpackingNodeAttributes::OldUnpackingNodeAttributes(
+	PackageNode* packageNode)
+	:
+	fPackageNode(packageNode)
+{
+}
+
+
+timespec
+OldUnpackingNodeAttributes::ModifiedTime() const
+{
+	if (fPackageNode != NULL)
+		return fPackageNode->ModifiedTime();
+
+	timespec time = { 0, 0 };
+	return time;
+}
+
+
+off_t
+OldUnpackingNodeAttributes::FileSize() const
+{
+	return fPackageNode != NULL ? fPackageNode->FileSize() : 0;
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.h b/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.h
new file mode 100644
index 0000000000..867ab0741f
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef OLD_UNPACKING_NODE_ATTRIBUTES_H
+#define OLD_UNPACKING_NODE_ATTRIBUTES_H
+
+
+#include "NodeListener.h"
+
+
+class PackageNode;
+
+
+class OldUnpackingNodeAttributes : public OldNodeAttributes {
+public:
+								OldUnpackingNodeAttributes(
+									PackageNode* packageNode);
+
+	virtual	timespec			ModifiedTime() const;
+	virtual	off_t				FileSize() const;
+
+private:
+			PackageNode*		fPackageNode;
+};
+
+
+#endif	// OLD_UNPACKING_NODE_ATTRIBUTES_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
index 1d0e7a31e9..562200e123 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
@@ -12,6 +12,7 @@
 
 #include "EmptyAttributeDirectoryCookie.h"
 #include "DebugSupport.h"
+#include "NodeListener.h"
 #include "PackageLinksListener.h"
 #include "Utils.h"
 #include "Volume.h"
@@ -41,7 +42,34 @@ link_path_for_mount_type(MountType type)
 }
 
 
-// #pragma mark -
+// #pragma mark - OldAttributes
+
+
+struct PackageLinkSymlink::OldAttributes : OldNodeAttributes {
+	OldAttributes(const timespec& modifiedTime, off_t fileSize)
+		:
+		fModifiedTime(modifiedTime),
+		fFileSize(fileSize)
+	{
+	}
+
+	virtual timespec ModifiedTime() const
+	{
+		return fModifiedTime;
+	}
+
+	virtual off_t FileSize() const
+	{
+		return fFileSize;
+	}
+
+private:
+	timespec	fModifiedTime;
+	off_t		fFileSize;
+};
+
+
+// #pragma mark - PackageLinkSymlink
 
 
 PackageLinkSymlink::PackageLinkSymlink(Package* package)
@@ -61,6 +89,8 @@ PackageLinkSymlink::~PackageLinkSymlink()
 void
 PackageLinkSymlink::Update(Package* package, PackageLinksListener* listener)
 {
+	OldAttributes oldAttributes(fModifiedTime, FileSize());
+
 	if (package != NULL) {
 		fLinkPath = link_path_for_mount_type(
 			package->Domain()->Volume()->MountType());
@@ -71,7 +101,7 @@ PackageLinkSymlink::Update(Package* package, PackageLinksListener* listener)
 
 	if (listener != NULL) {
 		listener->PackageLinkNodeChanged(this,
-			B_STAT_SIZE | B_STAT_MODIFICATION_TIME);
+			B_STAT_SIZE | B_STAT_MODIFICATION_TIME, oldAttributes);
 	}
 }
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h
index 91e687e71c..cfa64a8c4d 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h
@@ -38,6 +38,9 @@ public:
 	virtual	status_t			OpenAttribute(const char* name, int openMode,
 									AttributeCookie*& _cookie);
 
+private:
+			struct OldAttributes;
+
 private:
 			timespec			fModifiedTime;
 			const char*			fLinkPath;
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.h
index 4d3e7644ed..21f10b6073 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.h
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksListener.h
@@ -10,6 +10,7 @@
 
 
 class Node;
+class OldNodeAttributes;
 
 
 class PackageLinksListener {
@@ -19,7 +20,8 @@ public:
 	virtual	void				PackageLinkNodeAdded(Node* node) = 0;
 	virtual	void				PackageLinkNodeRemoved(Node* node) = 0;
 	virtual	void				PackageLinkNodeChanged(Node* node,
-									uint32 statFields) = 0;
+									uint32 statFields,
+									const OldNodeAttributes& oldAttributes) = 0;
 };
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 166ef61618..96966895c4 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -33,6 +33,7 @@
 #include "DebugSupport.h"
 #include "kernel_interface.h"
 #include "NameIndex.h"
+#include "OldUnpackingNodeAttributes.h"
 #include "PackageDirectory.h"
 #include "PackageFile.h"
 #include "PackageFSRoot.h"
@@ -775,10 +776,11 @@ Volume::PackageLinkNodeRemoved(Node* node)
 
 
 void
-Volume::PackageLinkNodeChanged(Node* node, uint32 statFields)
+Volume::PackageLinkNodeChanged(Node* node, uint32 statFields,
+	const OldNodeAttributes& oldAttributes)
 {
 	notify_stat_changed(ID(), node->ID(), statFields);
-	_NotifyNodeChanged(node, statFields);
+	_NotifyNodeChanged(node, statFields, oldAttributes);
 }
 
 
@@ -1137,6 +1139,7 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
 	bool newNode = false;
 	UnpackingNode* unpackingNode;
 	Node* node = directory->FindChild(packageNode->Name());
+	PackageNode* oldPackageNode = NULL;
 
 	if (node != NULL) {
 		unpackingNode = dynamic_cast(node);
@@ -1149,6 +1152,7 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
 			RETURN_ERROR(error);
 
 		node = unpackingNode->GetNode();
+		oldPackageNode = unpackingNode->GetPackageNode();
 		newNode = true;
 	}
 
@@ -1170,10 +1174,12 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
 		RETURN_ERROR(error);
 	}
 
-	if (newNode)
+	if (newNode) {
 		_NotifyNodeAdded(node);
-	else
-		_NotifyNodeChanged(node, kAllStatFields);
+	} else if (packageNode == unpackingNode->GetPackageNode()) {
+		_NotifyNodeChanged(node, kAllStatFields,
+			OldUnpackingNodeAttributes(oldPackageNode));
+	}
 
 	if (notify) {
 		if (newNode) {
@@ -1238,8 +1244,10 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
 
 	if (nodeRemoved)
 		_NotifyNodeRemoved(node);
-	else
-		_NotifyNodeChanged(node, kAllStatFields);
+	else if (packageNode == headPackageNode) {
+		_NotifyNodeChanged(node, kAllStatFields,
+			OldUnpackingNodeAttributes(headPackageNode));
+	}
 
 	if (!notify)
 		return;
@@ -1716,7 +1724,8 @@ Volume::_NotifyNodeRemoved(Node* node)
 
 
 void
-Volume::_NotifyNodeChanged(Node* node, uint32 statFields)
+Volume::_NotifyNodeChanged(Node* node, uint32 statFields,
+	const OldNodeAttributes& oldAttributes)
 {
 	Node* key = node;
 
@@ -1727,7 +1736,7 @@ Volume::_NotifyNodeChanged(Node* node, uint32 statFields)
 			while (true) {
 				NodeListener* next = listener->NextNodeListener();
 
-				listener->NodeChanged(node, statFields);
+				listener->NodeChanged(node, statFields, oldAttributes);
 
 				if (listener == last)
 					break;
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index 8986913791..532e4b9faa 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -97,7 +97,8 @@ private:
 	virtual	void				PackageLinkNodeAdded(Node* node);
 	virtual	void				PackageLinkNodeRemoved(Node* node);
 	virtual	void				PackageLinkNodeChanged(Node* node,
-									uint32 statFields);
+									uint32 statFields,
+									const OldNodeAttributes& oldAttributes);
 
 private:
 			struct Job;
@@ -183,7 +184,8 @@ private:
 			void				_NotifyNodeAdded(Node* node);
 			void				_NotifyNodeRemoved(Node* node);
 			void				_NotifyNodeChanged(Node* node,
-									uint32 statFields);
+									uint32 statFields,
+									const OldNodeAttributes& oldAttributes);
 
 private:
 	mutable	rw_lock				fLock;

From a3463d19323e5ff7a4f6b8c1313f1dd1978311e4 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 09:20:15 +0200
Subject: [PATCH 0241/1170] Refactor NameIndexIterator into template class

Create template class GenericIndexIterator from NameIndexIterator.
---
 .../kernel/file_systems/packagefs/IndexImpl.h | 157 ++++++++++++++++++
 .../file_systems/packagefs/NameIndex.cpp      | 155 ++---------------
 .../kernel/file_systems/packagefs/NameIndex.h |   7 +-
 3 files changed, 175 insertions(+), 144 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
index 1805d9fb86..c337aee24d 100644
--- a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
+++ b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
@@ -8,6 +8,7 @@
 
 #include "Index.h"
 #include "Node.h"
+#include "NodeListener.h"
 
 
 class AbstractIndexIterator {
@@ -23,4 +24,160 @@ public:
 };
 
 
+template
+class GenericIndexIterator : public AbstractIndexIterator,
+	public NodeListener {
+public:
+			typedef typename Policy::Index		Index;
+			typedef typename Policy::Value		Value;
+			typedef typename Policy::NodeTree	NodeTree;
+			typedef typename NodeTree::Node		TreeNode;
+
+public:
+								GenericIndexIterator();
+	virtual						~GenericIndexIterator();
+
+	virtual	bool				HasNext() const;
+	virtual	Node*				Next(void* buffer, size_t* _keyLength);
+
+	virtual	status_t			Suspend();
+	virtual	status_t			Resume();
+
+			bool				SetTo(Index* index, const Value& name,
+									bool ignoreValue = false);
+
+	virtual void				NodeRemoved(Node* node);
+
+protected:
+	inline	Node*				_ToNode() const;
+
+protected:
+			Index*				fIndex;
+			TreeNode*			fNextTreeNode;
+			bool				fSuspended;
+};
+
+
+template
+GenericIndexIterator::GenericIndexIterator()
+	:
+	AbstractIndexIterator(),
+	fIndex(NULL),
+	fNextTreeNode(NULL),
+	fSuspended(false)
+{
+}
+
+
+template
+GenericIndexIterator::~GenericIndexIterator()
+{
+	SetTo(NULL, NULL);
+}
+
+
+template
+bool
+GenericIndexIterator::HasNext() const
+{
+	return fNextTreeNode != NULL;
+}
+
+
+template
+Node*
+GenericIndexIterator::Next(void* buffer, size_t* _keyLength)
+{
+	if (fSuspended || fNextTreeNode == NULL)
+		return NULL;
+
+	Node* node = _ToNode();
+	if (node != NULL) {
+		if (buffer != NULL) {
+			strlcpy((char*)buffer, node->Name(), kMaxIndexKeyLength);
+			*_keyLength = strlen(node->Name());
+		}
+
+		fNextTreeNode = Policy::GetNodeTree(fIndex)->Next(fNextTreeNode);
+	}
+
+	return node;
+}
+
+
+template
+status_t
+GenericIndexIterator::Suspend()
+{
+	if (fSuspended)
+		return B_BAD_VALUE;
+
+	if (fNextTreeNode != NULL)
+		fIndex->GetVolume()->AddNodeListener(this, _ToNode());
+
+	fSuspended = true;
+	return B_OK;
+}
+
+
+template
+status_t
+GenericIndexIterator::Resume()
+{
+	if (!fSuspended)
+		return B_BAD_VALUE;
+
+	if (fNextTreeNode != NULL)
+		fIndex->GetVolume()->RemoveNodeListener(this);
+
+	fSuspended = false;
+	return B_OK;
+}
+
+
+template
+bool
+GenericIndexIterator::SetTo(Index* index, const Value& value,
+	bool ignoreValue)
+{
+	Resume();
+
+	fIndex = index;
+	fSuspended = false;
+	fNextTreeNode = NULL;
+
+	if (fIndex == NULL)
+		return false;
+
+	typename NodeTree::Iterator iterator;
+	if (ignoreValue)
+		Policy::GetNodeTree(fIndex)->GetIterator(&iterator);
+	else if (Policy::GetNodeTree(fIndex)->FindFirst(value, &iterator) == NULL)
+		return false;
+
+	fNextTreeNode = iterator.CurrentNode();
+	return fNextTreeNode != NULL;
+}
+
+
+template
+void
+GenericIndexIterator::NodeRemoved(Node* node)
+{
+	Resume();
+	Next(NULL, NULL);
+	Suspend();
+}
+
+
+template
+Node*
+GenericIndexIterator::_ToNode() const
+{
+//	return NodeTree::NodeStrategy().GetValue(fNextTreeNode);
+	typename NodeTree::NodeStrategy strategy;
+	return strategy.GetValue(fNextTreeNode);
+}
+
+
 #endif	// INDEX_IMPL_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
index 601f965c3e..9504b69061 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
@@ -82,38 +82,22 @@ class NameIndex::EntryTree : public _EntryTree {
 };
 
 
-// #pragma mark -  NameIndexIterator
+// #pragma mark -  Iterator
 
 
-class NameIndexIterator : public AbstractIndexIterator,
-	public NodeListener {
-public:
-								NameIndexIterator();
-	virtual						~NameIndexIterator();
+struct NameIndex::IteratorPolicy {
+	typedef NameIndex				Index;
+	typedef const char*				Value;
+	typedef NameIndex::EntryTree	NodeTree;
 
-	virtual	bool				HasNext() const;
-	virtual	Node*				Next(void* buffer, size_t* _keyLength);
+	static NodeTree* GetNodeTree(Index* index)
+	{
+		return index->fEntries;
+	}
+};
 
-	virtual	status_t			Suspend();
-	virtual	status_t			Resume();
 
-			bool				SetTo(NameIndex* index, const char* name,
-									bool ignoreValue = false);
-
-	virtual void				NodeRemoved(Node* node);
-
-private:
-			friend class NameIndex;
-
-			typedef NameIndex::EntryTree EntryTree;
-
-private:
-	inline	Node*				_ToNode() const;
-
-private:
-			NameIndex*			fIndex;
-			EntryTree::Node*	fNextTreeNode;
-			bool				fSuspended;
+struct NameIndex::Iterator : public GenericIndexIterator {
 };
 
 
@@ -196,7 +180,7 @@ NameIndex::NodeChanged(Node* node, uint32 statFields,
 AbstractIndexIterator*
 NameIndex::InternalGetIterator()
 {
-	NameIndexIterator* iterator = new(std::nothrow) NameIndexIterator;
+	Iterator* iterator = new(std::nothrow) Iterator;
 	if (iterator != NULL) {
 		if (!iterator->SetTo(this, NULL, true)) {
 			delete iterator;
@@ -227,7 +211,7 @@ NameIndex::InternalFind(const void* _key, size_t length)
 		key = clonedKey;
 	}
 
-	NameIndexIterator* iterator = new(std::nothrow) NameIndexIterator;
+	Iterator* iterator = new(std::nothrow) Iterator;
 	if (iterator != NULL) {
 		if (!iterator->SetTo(this, (const char*)key)) {
 			delete iterator;
@@ -246,116 +230,3 @@ NameIndex::_UpdateLiveQueries(Node* entry, const char* oldName,
 		oldName, oldName ? strlen(oldName) : 0,
 		newName, newName ? strlen(newName) : 0);
 }
-
-
-// #pragma mark - NameIndexIterator
-
-
-NameIndexIterator::NameIndexIterator()
-	:
-	AbstractIndexIterator(),
-	fIndex(NULL),
-	fNextTreeNode(NULL),
-	fSuspended(false)
-{
-}
-
-
-NameIndexIterator::~NameIndexIterator()
-{
-	SetTo(NULL, NULL);
-}
-
-
-bool
-NameIndexIterator::HasNext() const
-{
-	return fNextTreeNode != NULL;
-}
-
-
-Node*
-NameIndexIterator::Next(void* buffer, size_t* _keyLength)
-{
-	if (fSuspended || fNextTreeNode == NULL)
-		return NULL;
-
-	Node* entry = _ToNode();
-	if (entry != NULL) {
-		if (buffer != NULL) {
-			strlcpy((char*)buffer, entry->Name(), kMaxIndexKeyLength);
-			*_keyLength = strlen(entry->Name());
-		}
-
-		fNextTreeNode = fIndex->fEntries->Next(fNextTreeNode);
-	}
-
-	return entry;
-}
-
-
-status_t
-NameIndexIterator::Suspend()
-{
-	if (fSuspended)
-		return B_BAD_VALUE;
-
-	if (fNextTreeNode != NULL)
-		fIndex->GetVolume()->AddNodeListener(this, _ToNode());
-
-	fSuspended = true;
-	return B_OK;
-}
-
-
-status_t
-NameIndexIterator::Resume()
-{
-	if (!fSuspended)
-		return B_BAD_VALUE;
-
-	if (fNextTreeNode != NULL)
-		fIndex->GetVolume()->RemoveNodeListener(this);
-
-	fSuspended = false;
-	return B_OK;
-}
-
-
-bool
-NameIndexIterator::SetTo(NameIndex* index, const char* name, bool ignoreValue)
-{
-	Resume();
-
-	fIndex = index;
-	fSuspended = false;
-	fNextTreeNode = NULL;
-
-	if (fIndex == NULL)
-		return false;
-
-	EntryTree::Iterator iterator;
-	if (ignoreValue)
-		fIndex->fEntries->GetIterator(&iterator);
-	else if (fIndex->fEntries->FindFirst(name, &iterator) == NULL)
-		return false;
-
-	fNextTreeNode = iterator.CurrentNode();
-	return fNextTreeNode != NULL;
-}
-
-
-void
-NameIndexIterator::NodeRemoved(Node* node)
-{
-	Resume();
-	Next(NULL, NULL);
-	Suspend();
-}
-
-
-Node*
-NameIndexIterator::_ToNode() const
-{
-	return EntryTree::NodeStrategy().GetValue(fNextTreeNode);
-}
diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.h b/src/add-ons/kernel/file_systems/packagefs/NameIndex.h
index 7e8ed7bfc6..76766371e6 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.h
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.h
@@ -10,7 +10,7 @@
 #include "NodeListener.h"
 
 
-class NameIndexIterator;
+template class GenericIndexIterator;
 
 
 class NameIndex : public Index, private NodeListener {
@@ -35,7 +35,10 @@ protected:
 
 private:
 			class EntryTree;
-			friend class NameIndexIterator;
+			struct IteratorPolicy;
+			struct Iterator;
+
+			friend class IteratorPolicy;
 
 			void				_UpdateLiveQueries(Node* entry,
 									const char* oldName, const char* newName);

From 46368f46f38f02c06c1cf7e0f51b189ccab987c1 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 11:26:38 +0200
Subject: [PATCH 0242/1170] Small cleanup

---
 headers/private/file_systems/QueryParser.h | 22 +++++-----------------
 1 file changed, 5 insertions(+), 17 deletions(-)

diff --git a/headers/private/file_systems/QueryParser.h b/headers/private/file_systems/QueryParser.h
index 774d7857a8..dce381927d 100644
--- a/headers/private/file_systems/QueryParser.h
+++ b/headers/private/file_systems/QueryParser.h
@@ -404,10 +404,8 @@ skipWhitespaceReverse(char** expr, char* stop)
 }
 
 
-// compare_integral
 template
-static inline
-int
+static inline int
 compare_integral(const Key &a, const Key &b)
 {
 	if (a < b)
@@ -417,11 +415,10 @@ compare_integral(const Key &a, const Key &b)
 	return 0;
 }
 
-// compare_keys
-static
-int
-compare_keys(const uint8 *key1, size_t length1, const uint8 *key2,
-			 size_t length2, uint32 type)
+
+static inline int
+compareKeys(uint32 type, const uint8* key1, size_t length1, const uint8* key2,
+	size_t length2)
 {
 	switch (type) {
 		case B_INT32_TYPE:
@@ -450,15 +447,6 @@ compare_keys(const uint8 *key1, size_t length1, const uint8 *key2,
 	return -1;
 }
 
-// compareKeys
-static inline
-int
-compareKeys(uint32 type, const uint8 *key1, size_t length1, const uint8 *key2,
-			size_t length2)
-{
-	return compare_keys(key1, length1, key2, length2, type);
-}
-
 
 //	#pragma mark -
 

From a058fbe8a1707e6e3ccaa79002ad29bf18531b71 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 11:27:33 +0200
Subject: [PATCH 0243/1170] TwoKeyAVLTree: Add FindFirstClosest()

---
 headers/private/kernel/util/TwoKeyAVLTree.h | 111 ++++++++++++++++----
 1 file changed, 89 insertions(+), 22 deletions(-)

diff --git a/headers/private/kernel/util/TwoKeyAVLTree.h b/headers/private/kernel/util/TwoKeyAVLTree.h
index 5286ac864a..c3c67c0277 100644
--- a/headers/private/kernel/util/TwoKeyAVLTree.h
+++ b/headers/private/kernel/util/TwoKeyAVLTree.h
@@ -279,6 +279,8 @@ public:
 
 			Value*				FindFirst(const PrimaryKey& key,
 									Iterator* iterator = NULL);
+			Value*				FindFirstClosest(const PrimaryKey& key,
+									bool less, Iterator* iterator = NULL);
 			Value*				FindLast(const PrimaryKey& key,
 									Iterator* iterator = NULL);
 	inline	Value*				Find(const PrimaryKey& primaryKey,
@@ -296,6 +298,10 @@ public:
 									const SecondaryKey& secondaryKey);
 	inline	status_t			Remove(Node* node);
 
+private:
+			Node*				_FindFirst(const PrimaryKey& key,
+									Node** _parent) const;
+
 private:
 			TreeMap				fTreeMap;
 			PrimaryKeyCompare	fPrimaryKeyCompare;
@@ -432,35 +438,58 @@ TWO_KEY_AVL_TREE_CLASS_NAME::FindFirst(const PrimaryKey& key,
 	Iterator* iterator)
 {
 	const NodeStrategy& strategy = fTreeMap.GetNodeStrategy();
-	Node* node = fTreeMap.RootNode();
 
-	while (node) {
-		int cmp = fPrimaryKeyCompare(key, fGetPrimaryKey(
-			strategy.GetValue(node)));
-		if (cmp == 0) {
-			// found a matching node, now get the left-most node with that key
-			while (node->left && fPrimaryKeyCompare(key,
-				   	fGetPrimaryKey(strategy.GetValue(
-						strategy.GetNode(node->left)))) == 0) {
-				node = strategy.GetNode(node->left);
-			}
-			if (iterator)
-				iterator->_SetTo(fTreeMap.GetIterator(node));
-			return &strategy.GetValue(node);
-		}
+	Node* node = _FindFirst(key, NULL);
+	if (node == NULL)
+		return NULL;
 
-		if (cmp < 0)
-			node = strategy.GetNode(node->left);
-		else
-			node = strategy.GetNode(node->right);
-	}
-	return NULL;
+	if (iterator != NULL)
+		iterator->_SetTo(fTreeMap.GetIterator(node));
+
+	return &strategy.GetValue(node);
 }
 
 
 TWO_KEY_AVL_TREE_TEMPLATE_LIST
 Value*
-TWO_KEY_AVL_TREE_CLASS_NAME::FindLast(const PrimaryKey& key, Iterator* iterator)
+TWO_KEY_AVL_TREE_CLASS_NAME::FindFirstClosest(const PrimaryKey& key, bool less,
+	Iterator* iterator)
+{
+	const NodeStrategy& strategy = fTreeMap.GetNodeStrategy();
+
+	Node* parent;
+	Node* node = _FindFirst(key, &parent);
+	if (node == NULL) {
+		// not found -- try to get the closest node
+		if (parent == NULL)
+			return NULL;
+
+		node = parent;
+		int expectedCmp = less ? 1 : -1;
+		int cmp = fPrimaryKeyCompare(key,
+			fGetPrimaryKey(strategy.GetValue(strategy.GetNode(node))));
+
+		if (cmp != expectedCmp) {
+			// The node's value is less although we were asked for a greater
+			// value, or the other way around. We need to iterate to the next
+			// node in the respective direction. If there is no node, we fail.
+			node = less ? Previous(node) : Next(node);
+			if (node == NULL)
+				return NULL;
+		}
+	}
+
+	if (iterator != NULL)
+		iterator->_SetTo(fTreeMap.GetIterator(node));
+
+	return &strategy.GetValue(node);
+}
+
+
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+Value*
+TWO_KEY_AVL_TREE_CLASS_NAME::FindLast(const PrimaryKey& key,
+	Iterator* iterator)
 {
 	const NodeStrategy& strategy = fTreeMap.GetNodeStrategy();
 	Node* node = fTreeMap.RootNode();
@@ -565,4 +594,42 @@ TWO_KEY_AVL_TREE_CLASS_NAME::Remove(Node* node)
 }
 
 
+TWO_KEY_AVL_TREE_TEMPLATE_LIST
+TWO_KEY_AVL_TREE_CLASS_NAME::Node*
+TWO_KEY_AVL_TREE_CLASS_NAME::_FindFirst(const PrimaryKey& key,
+	Node** _parent) const
+{
+	const NodeStrategy& strategy = fTreeMap.GetNodeStrategy();
+	Node* node = fTreeMap.RootNode();
+	Node* parent = NULL;
+
+	while (node) {
+		int cmp = fPrimaryKeyCompare(key, fGetPrimaryKey(
+			strategy.GetValue(node)));
+		if (cmp == 0) {
+			// found a matching node, now get the left-most node with that key
+			while (node->left && fPrimaryKeyCompare(key,
+				   	fGetPrimaryKey(strategy.GetValue(
+						strategy.GetNode(node->left)))) == 0) {
+				node = strategy.GetNode(node->left);
+			}
+
+			return node;
+		}
+
+		parent = node;
+
+		if (cmp < 0)
+			node = strategy.GetNode(node->left);
+		else
+			node = strategy.GetNode(node->right);
+	}
+
+	if (_parent != NULL)
+		*_parent = parent;
+
+	return NULL;
+}
+
+
 #endif	// _KERNEL_UTIL_TWO_KEY_AVL_TREE_H

From 144129434f20eb579fed296518503762fa2ac277 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 11:30:06 +0200
Subject: [PATCH 0244/1170] GenericIndexIterator: Fix NameIndex dependency

Next() was still copying the name. Add a GetNodeValue() method to the
policy that fetches the value instead.
---
 src/add-ons/kernel/file_systems/packagefs/IndexImpl.h   | 6 ++----
 src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp | 6 ++++++
 2 files changed, 8 insertions(+), 4 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
index c337aee24d..cb01f8a7c0 100644
--- a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
+++ b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
@@ -93,10 +93,8 @@ GenericIndexIterator::Next(void* buffer, size_t* _keyLength)
 
 	Node* node = _ToNode();
 	if (node != NULL) {
-		if (buffer != NULL) {
-			strlcpy((char*)buffer, node->Name(), kMaxIndexKeyLength);
-			*_keyLength = strlen(node->Name());
-		}
+		if (buffer != NULL)
+			Policy::GetNodeValue(node, buffer, _keyLength);
 
 		fNextTreeNode = Policy::GetNodeTree(fIndex)->Next(fNextTreeNode);
 	}
diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
index 9504b69061..25bb84cd97 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
@@ -94,6 +94,12 @@ struct NameIndex::IteratorPolicy {
 	{
 		return index->fEntries;
 	}
+
+	static void GetNodeValue(Node* node, void* buffer, size_t* _keyLength)
+	{
+		strlcpy((char*)buffer, node->Name(), kMaxIndexKeyLength);
+		*_keyLength = strlen(node->Name());
+	}
 };
 
 

From 078007398465dad201100c17bb87243c0e7f6340 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 11:34:31 +0200
Subject: [PATCH 0245/1170] GenericIndexIterator::SetTo(): Find fuzzily

Use TwoKeyAVLTree::FindFirstClosest() instead of FindFirst(), so, if the
value isn't in the index, we find the closest greater value. That's the
semantics Index::InternalFind() is expected to have.
---
 src/add-ons/kernel/file_systems/packagefs/IndexImpl.h | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
index cb01f8a7c0..7bd84b4fe7 100644
--- a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
+++ b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
@@ -148,10 +148,12 @@ GenericIndexIterator::SetTo(Index* index, const Value& value,
 		return false;
 
 	typename NodeTree::Iterator iterator;
-	if (ignoreValue)
+	if (ignoreValue) {
 		Policy::GetNodeTree(fIndex)->GetIterator(&iterator);
-	else if (Policy::GetNodeTree(fIndex)->FindFirst(value, &iterator) == NULL)
+	} else if (Policy::GetNodeTree(fIndex)->FindFirstClosest(value, false,
+			&iterator) == NULL) {
 		return false;
+	}
 
 	fNextTreeNode = iterator.CurrentNode();
 	return fNextTreeNode != NULL;

From 0209c404dc03c2a2df4f29f54c6957aa4b11370c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 11:37:22 +0200
Subject: [PATCH 0246/1170] Add comment

---
 src/add-ons/kernel/file_systems/packagefs/Index.h | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Index.h b/src/add-ons/kernel/file_systems/packagefs/Index.h
index 204d95b372..53be4c3215 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Index.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Index.h
@@ -45,6 +45,8 @@ public:
 			bool				GetIterator(IndexIterator* iterator);
 			bool				Find(const void* key, size_t length,
 									IndexIterator* iterator);
+									// sets the iterator to the first value
+									// >= key
 
 			Index*&				IndexHashLink()
 									{ return fHashLink; }
@@ -56,6 +58,8 @@ protected:
 	virtual	AbstractIndexIterator* InternalGetIterator() = 0;
 	virtual	AbstractIndexIterator* InternalFind(const void* key,
 									size_t length) = 0;
+									// returns an iterator pointing to the first
+									// value >= key
 
 protected:
 			Index*				fHashLink;

From d56e19fb9e8beaa316c8aea36a087bcdb48190c5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 11:39:49 +0200
Subject: [PATCH 0247/1170] GenericIndexIterator: Add node change helpers

Add NodeChangeBegin()/NodeChangeEnd() methods that can be used by the
index when the respective node attribute has changed. They make sure
that the iterator doesn't move with the node, should it be inserted into
the index at a different position.
---
 .../kernel/file_systems/packagefs/IndexImpl.h | 44 +++++++++++++++++++
 1 file changed, 44 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
index 7bd84b4fe7..9714c16c2e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
+++ b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
@@ -46,6 +46,9 @@ public:
 			bool				SetTo(Index* index, const Value& name,
 									bool ignoreValue = false);
 
+	inline	void				NodeChangeBegin(Node* node);
+	inline	void				NodeChangeEnd(Node* node);
+
 	virtual void				NodeRemoved(Node* node);
 
 protected:
@@ -160,6 +163,47 @@ GenericIndexIterator::SetTo(Index* index, const Value& value,
 }
 
 
+/*!	Moves the iterator temporarily off the current node.
+	Called when the node the iterator currently points to has been modified and
+	the index is about to remove it from and reinsert it into the tree. After
+	having done that NodeChangeEnd() must be called.
+*/
+template
+void
+GenericIndexIterator::NodeChangeBegin(Node* node)
+{
+	fNextTreeNode = Policy::GetNodeTree(fIndex)->Previous(fNextTreeNode);
+}
+
+
+/*!	Brackets a NodeChangeBegin() call.
+*/
+template
+void
+GenericIndexIterator::NodeChangeEnd(Node* node)
+{
+	if (fNextTreeNode != NULL) {
+		fNextTreeNode = Policy::GetNodeTree(fIndex)->Next(fNextTreeNode);
+	} else {
+		typename NodeTree::Iterator iterator;
+		Policy::GetNodeTree(fIndex)->GetIterator(&iterator);
+		fNextTreeNode = iterator.CurrentNode();
+	}
+
+	// If the node is no longer the one we originally pointed to, re-register
+	// the node listener.
+	if (fNextTreeNode == NULL) {
+		fIndex->GetVolume()->RemoveNodeListener(this);
+	} else {
+		Node* newNode = _ToNode();
+		if (newNode != node) {
+			fIndex->GetVolume()->RemoveNodeListener(this);
+			fIndex->GetVolume()->AddNodeListener(this, newNode);
+		}
+	}
+}
+
+
 template
 void
 GenericIndexIterator::NodeRemoved(Node* node)

From d35565bed0f5c64aa02e5e69b5ffa3ae7bd484e8 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 11:42:31 +0200
Subject: [PATCH 0248/1170] Add size index support

* Add class SizeIndex.
* Create and add an instance of it in Volume mount.
---
 .../kernel/file_systems/packagefs/Jamfile     |   1 +
 .../file_systems/packagefs/SizeIndex.cpp      | 288 ++++++++++++++++++
 .../kernel/file_systems/packagefs/SizeIndex.h |  51 ++++
 .../kernel/file_systems/packagefs/Volume.cpp  |  34 ++-
 4 files changed, 366 insertions(+), 8 deletions(-)
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/SizeIndex.h

diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile
index f07377cf06..676e35f790 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Jamfile
+++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile
@@ -38,6 +38,7 @@ HAIKU_PACKAGE_FS_SOURCES =
 	PackageSymlink.cpp
 	Resolvable.cpp
 	ResolvableFamily.cpp
+	SizeIndex.cpp
 	UnpackingAttributeCookie.cpp
 	UnpackingAttributeDirectoryCookie.cpp
 	UnpackingDirectory.cpp
diff --git a/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp
new file mode 100644
index 0000000000..a8c7860c0e
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp
@@ -0,0 +1,288 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "SizeIndex.h"
+
+#include 
+
+#include 
+
+#include 
+#include 
+
+#include "DebugSupport.h"
+#include "IndexImpl.h"
+#include "Node.h"
+#include "Volume.h"
+
+
+// #pragma mark - SizeIndexPrimaryKey
+
+
+class SizeIndexPrimaryKey {
+public:
+	SizeIndexPrimaryKey(Node* node, off_t size)
+		:
+		node(node),
+		size(size)
+	{
+	}
+
+	SizeIndexPrimaryKey(Node* node)
+		:
+		node(node),
+		size(node->FileSize())
+	{
+	}
+
+	SizeIndexPrimaryKey(off_t size)
+		:
+		node(NULL),
+		size(size)
+	{
+	}
+
+	Node*	node;
+	off_t	size;
+};
+
+
+// #pragma mark - SizeIndexGetPrimaryKey
+
+
+class SizeIndexGetPrimaryKey {
+public:
+	inline SizeIndexPrimaryKey operator()(Node* a)
+	{
+		return SizeIndexPrimaryKey(a);
+	}
+
+	inline SizeIndexPrimaryKey operator()(Node* a) const
+	{
+		return SizeIndexPrimaryKey(a);
+	}
+};
+
+
+// #pragma mark - SizeIndexPrimaryKeyCompare
+
+
+class SizeIndexPrimaryKeyCompare {
+public:
+	inline int operator()(const SizeIndexPrimaryKey &a,
+		const SizeIndexPrimaryKey &b) const
+	{
+		if (a.node != NULL && a.node == b.node)
+			return 0;
+		if (a.size < b.size)
+			return -1;
+		if (a.size > b.size)
+			return 1;
+		return 0;
+	}
+};
+
+
+// #pragma mark - NodeTree
+
+
+typedef TwoKeyAVLTree _NodeTree;
+class SizeIndex::NodeTree : public _NodeTree {};
+
+
+// #pragma mark - IteratorList
+
+
+class SizeIndex::IteratorList : public SinglyLinkedList {};
+
+
+// #pragma mark - Iterator
+
+
+struct SizeIndex::IteratorPolicy {
+	typedef SizeIndex				Index;
+	typedef off_t					Value;
+	typedef SizeIndex::NodeTree		NodeTree;
+
+	static NodeTree* GetNodeTree(Index* index)
+	{
+		return index->fNodes;
+	}
+
+	static void GetNodeValue(Node* node, void* buffer, size_t* _keyLength)
+	{
+		*(off_t*)buffer = node->FileSize();
+		*_keyLength = sizeof(off_t);
+	}
+};
+
+
+class SizeIndex::Iterator : public GenericIndexIterator,
+	public SinglyLinkedListLinkImpl {
+public:
+	virtual	void				NodeChanged(Node* node, uint32 statFields,
+									const OldNodeAttributes& oldAttributes);
+};
+
+
+// #pragma mark - SizeIndex
+
+
+SizeIndex::SizeIndex()
+	:
+	Index(),
+	fNodes(NULL),
+	fIteratorsToUpdate(NULL)
+{
+}
+
+
+SizeIndex::~SizeIndex()
+{
+	if (IsListening())
+		fVolume->RemoveNodeListener(this);
+
+	ASSERT(fIteratorsToUpdate->IsEmpty());
+
+	delete fIteratorsToUpdate;
+	delete fNodes;
+}
+
+
+status_t
+SizeIndex::Init(Volume* volume)
+{
+	status_t error = Index::Init(volume, "size", B_INT64_TYPE, true,
+		sizeof(off_t));
+	if (error != B_OK)
+		return error;
+
+	fVolume->AddNodeListener(this, NULL);
+
+	fNodes = new(std::nothrow) NodeTree;
+	fIteratorsToUpdate = new(std::nothrow) IteratorList;
+	if (fNodes == NULL || fIteratorsToUpdate == NULL)
+		return B_NO_MEMORY;
+
+	return B_OK;
+}
+
+
+int32
+SizeIndex::CountEntries() const
+{
+	return fNodes->CountItems();
+}
+
+
+void
+SizeIndex::NodeAdded(Node* node)
+{
+	fNodes->Insert(node);
+}
+
+
+void
+SizeIndex::NodeRemoved(Node* node)
+{
+	fNodes->Remove(node, node);
+}
+
+
+void
+SizeIndex::NodeChanged(Node* node, uint32 statFields,
+	const OldNodeAttributes& oldAttributes)
+{
+	IteratorList iterators;
+	iterators.MoveFrom(fIteratorsToUpdate);
+
+	off_t oldSize = oldAttributes.FileSize();
+	off_t newSize = node->FileSize();
+	if (newSize == oldSize)
+		return;
+
+	NodeTree::Iterator nodeIterator;
+	Node** foundNode = fNodes->Find(SizeIndexPrimaryKey(node, oldSize), node,
+		&nodeIterator);
+
+	if (foundNode == NULL || *foundNode != node)
+		return;
+
+	// move the iterators that point to the node to the previous node
+	for (IteratorList::Iterator it = iterators.GetIterator();
+			Iterator* iterator = it.Next();) {
+		iterator->NodeChangeBegin(node);
+	}
+
+	// remove and re-insert the node
+	nodeIterator.Remove();
+	if (fNodes->Insert(node) != B_OK) {
+		fIteratorsToUpdate->MakeEmpty();
+		return;
+	}
+
+	// Move the iterators to the next node again. If the node hasn't changed
+	// its place, they will point to it again, otherwise to the node originally
+	// succeeding it.
+	for (IteratorList::Iterator it = iterators.GetIterator();
+			Iterator* iterator = it.Next();) {
+		iterator->NodeChangeEnd(node);
+	}
+
+	// update live queries
+	fVolume->UpdateLiveQueries(node, Name(), Type(),
+		(const uint8*)&oldSize, sizeof(oldSize), (const uint8*)&newSize,
+		sizeof(newSize));
+}
+
+
+AbstractIndexIterator*
+SizeIndex::InternalGetIterator()
+{
+	Iterator* iterator = new(std::nothrow) Iterator;
+	if (iterator != NULL) {
+		if (!iterator->SetTo(this, 0, true)) {
+			delete iterator;
+			iterator = NULL;
+		}
+	}
+	return iterator;
+}
+
+
+AbstractIndexIterator*
+SizeIndex::InternalFind(const void* key, size_t length)
+{
+	if (!key || length != sizeof(off_t))
+		return NULL;
+	Iterator* iterator = new(std::nothrow) Iterator;
+	if (iterator != NULL) {
+		if (!iterator->SetTo(this, *(const off_t*)key)) {
+			delete iterator;
+			iterator = NULL;
+		}
+	}
+	return iterator;
+}
+
+
+void
+SizeIndex::_AddIteratorToUpdate(Iterator* iterator)
+{
+	fIteratorsToUpdate->Add(iterator);
+}
+
+
+// #pragma mark - Iterator
+
+
+void
+SizeIndex::Iterator::NodeChanged(Node* node, uint32 statFields,
+	const OldNodeAttributes& oldAttributes)
+{
+	fIndex->_AddIteratorToUpdate(this);
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/SizeIndex.h b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.h
new file mode 100644
index 0000000000..3c8cb438f5
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef SIZE_INDEX_H
+#define SIZE_INDEX_H
+
+
+#include "Index.h"
+#include "NodeListener.h"
+
+
+class SizeIndex : public Index, private NodeListener {
+public:
+								SizeIndex();
+	virtual						~SizeIndex();
+
+			status_t			Init(Volume* volume);
+
+	virtual	int32				CountEntries() const;
+
+private:
+	virtual	void				NodeAdded(Node* node);
+	virtual	void				NodeRemoved(Node* node);
+	virtual	void				NodeChanged(Node* node, uint32 statFields,
+									const OldNodeAttributes& oldAttributes);
+
+protected:
+	virtual	AbstractIndexIterator* InternalGetIterator();
+	virtual	AbstractIndexIterator* InternalFind(const void* key,
+									size_t length);
+
+private:
+			struct IteratorPolicy;
+			class Iterator;
+			class IteratorList;
+			class NodeTree;
+			friend class Iterator;
+			friend struct IteratorPolicy;
+
+private:
+			void				_AddIteratorToUpdate(Iterator* iterator);
+// 			void				_RemoveIterator(Iterator* iterator);
+
+private:
+			NodeTree*			fNodes;
+			IteratorList*		fIteratorsToUpdate;
+};
+
+
+#endif	// SIZE_INDEX_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 96966895c4..b386265b0f 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -41,6 +41,7 @@
 #include "PackageLinksDirectory.h"
 #include "PackageSymlink.h"
 #include "Resolvable.h"
+#include "SizeIndex.h"
 #include "UnpackingLeafNode.h"
 #include "UnpackingDirectory.h"
 #include "Version.h"
@@ -510,17 +511,34 @@ Volume::Mount(const char* parameterString)
 		RETURN_ERROR(error);
 
 	// create the name index
-	NameIndex* index = new(std::nothrow) NameIndex;
-	if (index == NULL)
-		RETURN_ERROR(B_NO_MEMORY);
+	{
+		NameIndex* index = new(std::nothrow) NameIndex;
+		if (index == NULL)
+			RETURN_ERROR(B_NO_MEMORY);
 
-	error = index->Init(this);
-	if (error != B_OK) {
-		delete index;
-		RETURN_ERROR(error);
+		error = index->Init(this);
+		if (error != B_OK) {
+			delete index;
+			RETURN_ERROR(error);
+		}
+
+		fIndices.Insert(index);
 	}
 
-	fIndices.Insert(index);
+	// create the size index
+	{
+		SizeIndex* index = new(std::nothrow) SizeIndex;
+		if (index == NULL)
+			RETURN_ERROR(B_NO_MEMORY);
+
+		error = index->Init(this);
+		if (error != B_OK) {
+			delete index;
+			RETURN_ERROR(error);
+		}
+
+		fIndices.Insert(index);
+	}
 
 	// get the mount parameters
 	const char* packages = NULL;

From 8c8e925a0a897fb727e97c9a931a3138de5cf29b Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 13:02:07 +0200
Subject: [PATCH 0249/1170] QueryParser: The last_modified index is time_t

* Changed value type from B_INT64_TYPE to B_INT32_TYPE.
* Changed QueryPolicy::NodeGetLastModifiedTime() return value from
  bigtime_t to time_t.
---
 headers/private/file_systems/QueryParser.h          | 4 ++--
 src/add-ons/kernel/file_systems/packagefs/Query.cpp | 5 ++---
 2 files changed, 4 insertions(+), 5 deletions(-)

diff --git a/headers/private/file_systems/QueryParser.h b/headers/private/file_systems/QueryParser.h
index dce381927d..e2d6222189 100644
--- a/headers/private/file_systems/QueryParser.h
+++ b/headers/private/file_systems/QueryParser.h
@@ -1055,8 +1055,8 @@ Equation::Match(Entry* entry, Node* node,
 		value.Int64 = QueryPolicy::NodeGetSize(node);
 		type = B_INT64_TYPE;
 	} else if (!strcmp(fAttribute, "last_modified")) {
-		value.Int64 = QueryPolicy::NodeGetLastModifiedTime(node);
-		type = B_INT64_TYPE;
+		value.Int32 = QueryPolicy::NodeGetLastModifiedTime(node);
+		type = B_INT32_TYPE;
 	} else {
 		// then for attributes
 		if (QueryPolicy::NodeGetAttribute(node, fAttribute, buffer, &size,
diff --git a/src/add-ons/kernel/file_systems/packagefs/Query.cpp b/src/add-ons/kernel/file_systems/packagefs/Query.cpp
index 05424e1087..4c51041e58 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Query.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Query.cpp
@@ -171,10 +171,9 @@ struct Query::QueryPolicy {
 		return node->FileSize();
 	}
 
-	static bigtime_t NodeGetLastModifiedTime(Node* node)
+	static time_t NodeGetLastModifiedTime(Node* node)
 	{
-		timespec time = node->ModifiedTime();
-		return (bigtime_t)time.tv_sec * 1000000 + time.tv_nsec / 1000;
+		return node->ModifiedTime().tv_sec;
 	}
 
 	static status_t NodeGetAttribute(Node* node, const char* attribute,

From a5d15ca28bd045817e8b9af4c11dfe1f818ec73c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 13:02:33 +0200
Subject: [PATCH 0250/1170] Removed left-over commented code

---
 src/add-ons/kernel/file_systems/packagefs/SizeIndex.h | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/SizeIndex.h b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.h
index 3c8cb438f5..68f352bef1 100644
--- a/src/add-ons/kernel/file_systems/packagefs/SizeIndex.h
+++ b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.h
@@ -40,7 +40,6 @@ private:
 
 private:
 			void				_AddIteratorToUpdate(Iterator* iterator);
-// 			void				_RemoveIterator(Iterator* iterator);
 
 private:
 			NodeTree*			fNodes;

From 0c63c7738a1b281eb4232cc7f7a323436b09b63b Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 13:03:30 +0200
Subject: [PATCH 0251/1170] Add last modified index support

* Add class LastModifiedIndex.
* Create and add an instance of it in Volume::Mount().
---
 .../kernel/file_systems/packagefs/Jamfile     |   1 +
 .../packagefs/LastModifiedIndex.cpp           | 290 ++++++++++++++++++
 .../packagefs/LastModifiedIndex.h             |  50 +++
 .../kernel/file_systems/packagefs/Volume.cpp  |  16 +
 4 files changed, 357 insertions(+)
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.h

diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile
index 676e35f790..119c77b67f 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Jamfile
+++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile
@@ -18,6 +18,7 @@ HAIKU_PACKAGE_FS_SOURCES =
 	GlobalFactory.cpp
 	Index.cpp
 	kernel_interface.cpp
+	LastModifiedIndex.cpp
 	NameIndex.cpp
 	Node.cpp
 	NodeListener.cpp
diff --git a/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp
new file mode 100644
index 0000000000..0ce010f316
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp
@@ -0,0 +1,290 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "LastModifiedIndex.h"
+
+#include 
+
+#include 
+
+#include 
+#include 
+
+#include "DebugSupport.h"
+#include "IndexImpl.h"
+#include "Node.h"
+#include "Volume.h"
+
+
+// #pragma mark - LastModifiedIndexPrimaryKey
+
+
+class LastModifiedIndexPrimaryKey {
+public:
+	LastModifiedIndexPrimaryKey(Node* node, time_t modified)
+		:
+		node(node),
+		modified(modified)
+	{
+	}
+
+	LastModifiedIndexPrimaryKey(Node* node)
+		:
+		node(node),
+		modified(node->ModifiedTime().tv_sec)
+	{
+	}
+
+	LastModifiedIndexPrimaryKey(time_t modified)
+		:
+		node(NULL),
+		modified(modified)
+	{
+	}
+
+	Node*	node;
+	time_t	modified;
+};
+
+
+// #pragma mark - LastModifiedIndexGetPrimaryKey
+
+
+class LastModifiedIndexGetPrimaryKey {
+public:
+	inline LastModifiedIndexPrimaryKey operator()(Node* a)
+	{
+		return LastModifiedIndexPrimaryKey(a);
+	}
+
+	inline LastModifiedIndexPrimaryKey operator()(Node* a) const
+	{
+		return LastModifiedIndexPrimaryKey(a);
+	}
+};
+
+
+// #pragma mark - LastModifiedIndexPrimaryKeyCompare
+
+
+class LastModifiedIndexPrimaryKeyCompare {
+public:
+	inline int operator()(const LastModifiedIndexPrimaryKey &a,
+		const LastModifiedIndexPrimaryKey &b) const
+	{
+		if (a.node != NULL && a.node == b.node)
+			return 0;
+		if (a.modified < b.modified)
+			return -1;
+		if (a.modified > b.modified)
+			return 1;
+		return 0;
+	}
+};
+
+
+// #pragma mark - NodeTree
+
+
+typedef TwoKeyAVLTree
+	_NodeTree;
+class LastModifiedIndex::NodeTree : public _NodeTree {};
+
+
+// #pragma mark - IteratorList
+
+
+class LastModifiedIndex::IteratorList : public SinglyLinkedList {};
+
+
+// #pragma mark - Iterator
+
+
+struct LastModifiedIndex::IteratorPolicy {
+	typedef LastModifiedIndex			Index;
+	typedef time_t						Value;
+	typedef LastModifiedIndex::NodeTree	NodeTree;
+
+	static NodeTree* GetNodeTree(Index* index)
+	{
+		return index->fNodes;
+	}
+
+	static void GetNodeValue(Node* node, void* buffer, size_t* _keyLength)
+	{
+		*(time_t*)buffer = node->ModifiedTime().tv_sec;
+		*_keyLength = sizeof(time_t);
+	}
+};
+
+
+class LastModifiedIndex::Iterator : public GenericIndexIterator,
+	public SinglyLinkedListLinkImpl {
+public:
+	virtual	void				NodeChanged(Node* node, uint32 statFields,
+									const OldNodeAttributes& oldAttributes);
+};
+
+
+// #pragma mark - LastModifiedIndex
+
+
+LastModifiedIndex::LastModifiedIndex()
+	:
+	Index(),
+	fNodes(NULL),
+	fIteratorsToUpdate(NULL)
+{
+}
+
+
+LastModifiedIndex::~LastModifiedIndex()
+{
+	if (IsListening())
+		fVolume->RemoveNodeListener(this);
+
+	ASSERT(fIteratorsToUpdate->IsEmpty());
+
+	delete fIteratorsToUpdate;
+	delete fNodes;
+}
+
+
+status_t
+LastModifiedIndex::Init(Volume* volume)
+{
+	status_t error = Index::Init(volume, "last_modified", B_INT32_TYPE, true,
+		sizeof(time_t));
+	if (error != B_OK)
+		return error;
+
+	fVolume->AddNodeListener(this, NULL);
+
+	fNodes = new(std::nothrow) NodeTree;
+	fIteratorsToUpdate = new(std::nothrow) IteratorList;
+	if (fNodes == NULL || fIteratorsToUpdate == NULL)
+		return B_NO_MEMORY;
+
+	return B_OK;
+}
+
+
+int32
+LastModifiedIndex::CountEntries() const
+{
+	return fNodes->CountItems();
+}
+
+
+void
+LastModifiedIndex::NodeAdded(Node* node)
+{
+	fNodes->Insert(node);
+}
+
+
+void
+LastModifiedIndex::NodeRemoved(Node* node)
+{
+	fNodes->Remove(node, node);
+}
+
+
+void
+LastModifiedIndex::NodeChanged(Node* node, uint32 statFields,
+	const OldNodeAttributes& oldAttributes)
+{
+	IteratorList iterators;
+	iterators.MoveFrom(fIteratorsToUpdate);
+
+	time_t oldLastModified = oldAttributes.ModifiedTime().tv_sec;
+	time_t newLastModified = node->ModifiedTime().tv_sec;
+	if (newLastModified == oldLastModified)
+		return;
+
+	NodeTree::Iterator nodeIterator;
+	Node** foundNode = fNodes->Find(
+		LastModifiedIndexPrimaryKey(node, oldLastModified), node,
+		&nodeIterator);
+
+	if (foundNode == NULL || *foundNode != node)
+		return;
+
+	// move the iterators that point to the node to the previous node
+	for (IteratorList::Iterator it = iterators.GetIterator();
+			Iterator* iterator = it.Next();) {
+		iterator->NodeChangeBegin(node);
+	}
+
+	// remove and re-insert the node
+	nodeIterator.Remove();
+	if (fNodes->Insert(node) != B_OK) {
+		fIteratorsToUpdate->MakeEmpty();
+		return;
+	}
+
+	// Move the iterators to the next node again. If the node hasn't changed
+	// its place, they will point to it again, otherwise to the node originally
+	// succeeding it.
+	for (IteratorList::Iterator it = iterators.GetIterator();
+			Iterator* iterator = it.Next();) {
+		iterator->NodeChangeEnd(node);
+	}
+
+	// update live queries
+	fVolume->UpdateLiveQueries(node, Name(), Type(),
+		(const uint8*)&oldLastModified, sizeof(oldLastModified),
+		(const uint8*)&newLastModified, sizeof(newLastModified));
+}
+
+
+AbstractIndexIterator*
+LastModifiedIndex::InternalGetIterator()
+{
+	Iterator* iterator = new(std::nothrow) Iterator;
+	if (iterator != NULL) {
+		if (!iterator->SetTo(this, 0, true)) {
+			delete iterator;
+			iterator = NULL;
+		}
+	}
+	return iterator;
+}
+
+
+AbstractIndexIterator*
+LastModifiedIndex::InternalFind(const void* key, size_t length)
+{
+	if (!key || length != sizeof(time_t))
+		return NULL;
+	Iterator* iterator = new(std::nothrow) Iterator;
+	if (iterator != NULL) {
+		if (!iterator->SetTo(this, *(const time_t*)key)) {
+			delete iterator;
+			iterator = NULL;
+		}
+	}
+	return iterator;
+}
+
+
+void
+LastModifiedIndex::_AddIteratorToUpdate(Iterator* iterator)
+{
+	fIteratorsToUpdate->Add(iterator);
+}
+
+
+// #pragma mark - Iterator
+
+
+void
+LastModifiedIndex::Iterator::NodeChanged(Node* node, uint32 statFields,
+	const OldNodeAttributes& oldAttributes)
+{
+	fIndex->_AddIteratorToUpdate(this);
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.h b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.h
new file mode 100644
index 0000000000..5b64241a8c
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.h
@@ -0,0 +1,50 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef LAST_MODIFIED_INDEX_H
+#define LAST_MODIFIED_INDEX_H
+
+
+#include "Index.h"
+#include "NodeListener.h"
+
+
+class LastModifiedIndex : public Index, private NodeListener {
+public:
+								LastModifiedIndex();
+	virtual						~LastModifiedIndex();
+
+	status_t					Init(Volume* volume);
+
+	virtual	int32				CountEntries() const;
+
+private:
+	virtual	void				NodeAdded(Node* node);
+	virtual	void				NodeRemoved(Node* node);
+	virtual	void				NodeChanged(Node* node, uint32 statFields,
+									const OldNodeAttributes& oldAttributes);
+
+protected:
+	virtual	AbstractIndexIterator* InternalGetIterator();
+	virtual	AbstractIndexIterator* InternalFind(const void* key,
+									size_t length);
+
+private:
+			struct IteratorPolicy;
+			class Iterator;
+			class IteratorList;
+			class NodeTree;
+			friend class Iterator;
+			friend struct IteratorPolicy;
+
+private:
+			void				_AddIteratorToUpdate(Iterator* iterator);
+
+private:
+			NodeTree*			fNodes;
+			IteratorList*		fIteratorsToUpdate;
+};
+
+
+#endif	// LAST_MODIFIED_INDEX_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index b386265b0f..04d993404d 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -32,6 +32,7 @@
 
 #include "DebugSupport.h"
 #include "kernel_interface.h"
+#include "LastModifiedIndex.h"
 #include "NameIndex.h"
 #include "OldUnpackingNodeAttributes.h"
 #include "PackageDirectory.h"
@@ -540,6 +541,21 @@ Volume::Mount(const char* parameterString)
 		fIndices.Insert(index);
 	}
 
+	// create the last modified index
+	{
+		LastModifiedIndex* index = new(std::nothrow) LastModifiedIndex;
+		if (index == NULL)
+			RETURN_ERROR(B_NO_MEMORY);
+
+		error = index->Init(this);
+		if (error != B_OK) {
+			delete index;
+			RETURN_ERROR(error);
+		}
+
+		fIndices.Insert(index);
+	}
+
 	// get the mount parameters
 	const char* packages = NULL;
 	const char* volumeName = NULL;

From 28559a4e2403ac6be2899b7c6faad0cff855db82 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 15:27:30 +0200
Subject: [PATCH 0252/1170] Build fix

---
 headers/private/kernel/util/TwoKeyAVLTree.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/headers/private/kernel/util/TwoKeyAVLTree.h b/headers/private/kernel/util/TwoKeyAVLTree.h
index c3c67c0277..2c2ecd05c2 100644
--- a/headers/private/kernel/util/TwoKeyAVLTree.h
+++ b/headers/private/kernel/util/TwoKeyAVLTree.h
@@ -595,7 +595,7 @@ TWO_KEY_AVL_TREE_CLASS_NAME::Remove(Node* node)
 
 
 TWO_KEY_AVL_TREE_TEMPLATE_LIST
-TWO_KEY_AVL_TREE_CLASS_NAME::Node*
+typename TWO_KEY_AVL_TREE_CLASS_NAME::Node*
 TWO_KEY_AVL_TREE_CLASS_NAME::_FindFirst(const PrimaryKey& key,
 	Node** _parent) const
 {

From 3877a7f4a001e7a9fad0215a5694a1cc7ec0e397 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 15:31:12 +0200
Subject: [PATCH 0253/1170] AVLTreeMap fixes

* AVLTreeMap::_GetKey(): Change return type from const Key& to Key, so
  the strategy can do that as well and doesn't have have a Key object in
  the node.
* Fix the Auto strategy: It was using the undefined _GetKey() instead
  of GetKey().
---
 headers/private/kernel/util/AVLTreeMap.h | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/headers/private/kernel/util/AVLTreeMap.h b/headers/private/kernel/util/AVLTreeMap.h
index 0ff6c090d9..2405bb79b8 100644
--- a/headers/private/kernel/util/AVLTreeMap.h
+++ b/headers/private/kernel/util/AVLTreeMap.h
@@ -98,7 +98,7 @@ protected:
 	// strategy shortcuts
 	inline	Node*				_Allocate(const Key& key, const Value& value);
 	inline	void				_Free(Node* node);
-	inline	const Key&			_GetKey(Node* node) const;
+	inline	Key					_GetKey(Node* node) const;
 	inline	Value&				_GetValue(Node* node) const;
 	inline	AVLTreeNode*		_GetAVLTreeNode(const Node* node) const;
 	inline	Node*				_GetNode(const AVLTreeNode* node) const;
@@ -486,7 +486,7 @@ _AVL_TREE_MAP_CLASS_NAME::_Free(Node* node)
 
 // _GetKey
 _AVL_TREE_MAP_TEMPLATE_LIST
-inline const Key&
+inline Key
 _AVL_TREE_MAP_CLASS_NAME::_GetKey(Node* node) const
 {
 	return fStrategy.GetKey(node);
@@ -644,12 +644,12 @@ public:
 
 	inline int CompareKeyNode(const Key& a, const Node* b) const
 	{
-		return fCompare(a, _GetKey(b));
+		return fCompare(a, GetKey(b));
 	}
 
 	inline int CompareNodes(const Node* a, const Node* b) const
 	{
-		return fCompare(_GetKey(a), _GetKey(b));
+		return fCompare(GetKey(a), GetKey(b));
 	}
 
 private:

From 01f7f92aef0dada1afd9c57366e3358c309dd825 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 15:33:05 +0200
Subject: [PATCH 0254/1170] Move helper function out of QueryParser.h

They live in the new QueryParserUtils.{h,cpp} now.
---
 headers/private/file_systems/QueryParser.h    | 325 +-----------------
 .../private/file_systems/QueryParserUtils.h   |  61 ++++
 .../kernel/file_systems/packagefs/Jamfile     |  12 +-
 .../file_systems/shared/QueryParserUtils.cpp  | 317 +++++++++++++++++
 4 files changed, 392 insertions(+), 323 deletions(-)
 create mode 100644 headers/private/file_systems/QueryParserUtils.h
 create mode 100644 src/add-ons/kernel/file_systems/shared/QueryParserUtils.cpp

diff --git a/headers/private/file_systems/QueryParser.h b/headers/private/file_systems/QueryParser.h
index e2d6222189..fcb1ded513 100644
--- a/headers/private/file_systems/QueryParser.h
+++ b/headers/private/file_systems/QueryParser.h
@@ -4,8 +4,8 @@
  * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
  * This file may be used under the terms of the MIT License.
  */
-#ifndef _FILE_SYSTEMS_QUERY_H
-#define _FILE_SYSTEMS_QUERY_H
+#ifndef _FILE_SYSTEMS_QUERY_PARSER_H
+#define _FILE_SYSTEMS_QUERY_PARSER_H
 
 
 /*!	Query parsing and evaluation
@@ -46,6 +46,8 @@
 
 #include 
 
+#include 
+
 
 //#define DEBUG_QUERY
 
@@ -96,20 +98,6 @@ enum ops {
 	OP_LESS_THAN_OR_EQUAL,
 };
 
-enum match {
-	NO_MATCH = 0,
-	MATCH_OK = 1,
-
-	MATCH_BAD_PATTERN = -2,
-	MATCH_INVALID_CHARACTER
-};
-
-// return values from isValidPattern()
-enum {
-	PATTERN_INVALID_ESCAPE = -3,
-	PATTERN_INVALID_RANGE,
-	PATTERN_INVALID_SET
-};
 
 template
 union value {
@@ -385,309 +373,6 @@ private:
 //	#pragma mark -
 
 
-void
-skipWhitespace(char** expr, int32 skip = 0)
-{
-	char* string = (*expr) + skip;
-	while (*string == ' ' || *string == '\t') string++;
-	*expr = string;
-}
-
-
-void
-skipWhitespaceReverse(char** expr, char* stop)
-{
-	char* string = *expr;
-	while (string > stop && (*string == ' ' || *string == '\t'))
-		string--;
-	*expr = string;
-}
-
-
-template
-static inline int
-compare_integral(const Key &a, const Key &b)
-{
-	if (a < b)
-		return -1;
-	else if (a > b)
-		return 1;
-	return 0;
-}
-
-
-static inline int
-compareKeys(uint32 type, const uint8* key1, size_t length1, const uint8* key2,
-	size_t length2)
-{
-	switch (type) {
-		case B_INT32_TYPE:
-			return compare_integral(*(int32*)key1, *(int32*)key2);
-		case B_UINT32_TYPE:
-			return compare_integral(*(uint32*)key1, *(uint32*)key2);
-		case B_INT64_TYPE:
-			return compare_integral(*(int64*)key1, *(int64*)key2);
-		case B_UINT64_TYPE:
-			return compare_integral(*(uint64*)key1, *(uint64*)key2);
-		case B_FLOAT_TYPE:
-			return compare_integral(*(float*)key1, *(float*)key2);
-		case B_DOUBLE_TYPE:
-			return compare_integral(*(double*)key1, *(double*)key2);
-		case B_STRING_TYPE:
-		{
-			int result = strncmp((const char*)key1, (const char*)key2,
-				std::min(length1, length2));
-			if (result == 0) {
-				result = compare_integral(strnlen((const char*)key1, length1),
-					strnlen((const char*)key2, length2));
-			}
-			return result;
-		}
-	}
-	return -1;
-}
-
-
-//	#pragma mark -
-
-
-uint32
-utf8ToUnicode(char** string)
-{
-	uint8* bytes = (uint8*)*string;
-	int32 length;
-	uint8 mask = 0x1f;
-
-	switch (bytes[0] & 0xf0) {
-		case 0xc0:
-		case 0xd0:
-			length = 2;
-			break;
-		case 0xe0:
-			length = 3;
-			break;
-		case 0xf0:
-			mask = 0x0f;
-			length = 4;
-			break;
-		default:
-			// valid 1-byte character
-			// and invalid characters
-			(*string)++;
-			return bytes[0];
-	}
-	uint32 c = bytes[0] & mask;
-	int32 i = 1;
-	for (; i < length && (bytes[i] & 0x80) > 0; i++)
-		c = (c << 6) | (bytes[i] & 0x3f);
-
-	if (i < length) {
-		// invalid character
-		(*string)++;
-		return (uint32)bytes[0];
-	}
-	*string += length;
-	return c;
-}
-
-
-int32
-getFirstPatternSymbol(char* string)
-{
-	char c;
-
-	for (int32 index = 0; (c = *string++); index++) {
-		if (c == '*' || c == '?' || c == '[')
-			return index;
-	}
-	return -1;
-}
-
-
-bool
-isPattern(char* string)
-{
-	return getFirstPatternSymbol(string) >= 0 ? true : false;
-}
-
-
-status_t
-isValidPattern(char* pattern)
-{
-	while (*pattern) {
-		switch (*pattern++) {
-			case '\\':
-				// the escape character must not be at the end of the pattern
-				if (!*pattern++)
-					return PATTERN_INVALID_ESCAPE;
-				break;
-
-			case '[':
-				if (pattern[0] == ']' || !pattern[0])
-					return PATTERN_INVALID_SET;
-
-				while (*pattern != ']') {
-					if (*pattern == '\\' && !*++pattern)
-						return PATTERN_INVALID_ESCAPE;
-
-					if (!*pattern)
-						return PATTERN_INVALID_SET;
-
-					if (pattern[0] == '-' && pattern[1] == '-')
-						return PATTERN_INVALID_RANGE;
-
-					pattern++;
-				}
-				break;
-		}
-	}
-	return B_OK;
-}
-
-
-/*!	Matches the string against the given wildcard pattern.
-	Returns either MATCH_OK, or NO_MATCH when everything went fine, or
-	values < 0 (see enum at the top of Query.cpp) if an error occurs.
-*/
-status_t
-matchString(char* pattern, char* string)
-{
-	while (*pattern) {
-		// end of string == valid end of pattern?
-		if (!string[0]) {
-			while (pattern[0] == '*')
-				pattern++;
-			return !pattern[0] ? MATCH_OK : NO_MATCH;
-		}
-
-		switch (*pattern++) {
-			case '?':
-			{
-				// match exactly one UTF-8 character; we are
-				// not interested in the result
-				utf8ToUnicode(&string);
-				break;
-			}
-
-			case '*':
-			{
-				// compact pattern
-				while (true) {
-					if (pattern[0] == '?') {
-						if (!*++string)
-							return NO_MATCH;
-					} else if (pattern[0] != '*')
-						break;
-
-					pattern++;
-				}
-
-				// if the pattern is done, we have matched the string
-				if (!pattern[0])
-					return MATCH_OK;
-
-				while(true) {
-					// we have removed all occurences of '*' and '?'
-					if (pattern[0] == string[0]
-						|| pattern[0] == '['
-						|| pattern[0] == '\\') {
-						status_t status = matchString(pattern, string);
-						if (status < B_OK || status == MATCH_OK)
-							return status;
-					}
-
-					// we could be nice here and just jump to the next
-					// UTF-8 character - but we wouldn't gain that much
-					// and it'd be slower (since we're checking for
-					// equality before entering the recursion)
-					if (!*++string)
-						return NO_MATCH;
-				}
-				break;
-			}
-
-			case '[':
-			{
-				bool invert = false;
-				if (pattern[0] == '^' || pattern[0] == '!') {
-					invert = true;
-					pattern++;
-				}
-
-				if (!pattern[0] || pattern[0] == ']')
-					return MATCH_BAD_PATTERN;
-
-				uint32 c = utf8ToUnicode(&string);
-				bool matched = false;
-
-				while (pattern[0] != ']') {
-					if (!pattern[0])
-						return MATCH_BAD_PATTERN;
-
-					if (pattern[0] == '\\')
-						pattern++;
-
-					uint32 first = utf8ToUnicode(&pattern);
-
-					// Does this character match, or is this a range?
-					if (first == c) {
-						matched = true;
-						break;
-					} else if (pattern[0] == '-' && pattern[1] != ']'
-							&& pattern[1]) {
-						pattern++;
-
-						if (pattern[0] == '\\') {
-							pattern++;
-							if (!pattern[0])
-								return MATCH_BAD_PATTERN;
-						}
-						uint32 last = utf8ToUnicode(&pattern);
-
-						if (c >= first && c <= last) {
-							matched = true;
-							break;
-						}
-					}
-				}
-
-				if (invert)
-					matched = !matched;
-
-				if (matched) {
-					while (pattern[0] != ']') {
-						if (!pattern[0])
-							return MATCH_BAD_PATTERN;
-						pattern++;
-					}
-					pattern++;
-					break;
-				}
-				return NO_MATCH;
-			}
-
-            case '\\':
-				if (!pattern[0])
-					return MATCH_BAD_PATTERN;
-				// supposed to fall through
-			default:
-				if (pattern[-1] != string[0])
-					return NO_MATCH;
-				string++;
-				break;
-		}
-	}
-
-	if (string[0])
-		return NO_MATCH;
-
-	return MATCH_OK;
-}
-
-
-//	#pragma mark -
-
-
 template
 Equation::Equation(char** expr)
 	:
@@ -1921,4 +1606,4 @@ Query::_SendEntryNotification(Entry* entry,
 }	// namespace QueryParser
 
 
-#endif	// _FILE_SYSTEMS_QUERY_H
+#endif	// _FILE_SYSTEMS_QUERY_PARSER_H
diff --git a/headers/private/file_systems/QueryParserUtils.h b/headers/private/file_systems/QueryParserUtils.h
new file mode 100644
index 0000000000..a12c7d4b9f
--- /dev/null
+++ b/headers/private/file_systems/QueryParserUtils.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2010, Clemens Zeidler 
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * This file may be used under the terms of the MIT License.
+ */
+#ifndef _FILE_SYSTEMS_QUERY_PARSER_UTILS_H
+#define _FILE_SYSTEMS_QUERY_PARSER_UTILS_H
+
+
+#include 
+
+#include 
+
+
+namespace QueryParser {
+
+
+enum match {
+	NO_MATCH = 0,
+	MATCH_OK = 1,
+
+	MATCH_BAD_PATTERN = -2,
+	MATCH_INVALID_CHARACTER
+};
+
+// return values from isValidPattern()
+enum {
+	PATTERN_INVALID_ESCAPE = -3,
+	PATTERN_INVALID_RANGE,
+	PATTERN_INVALID_SET
+};
+
+
+__BEGIN_DECLS
+
+
+void		skipWhitespace(char** expr, int32 skip = 0);
+void		skipWhitespaceReverse(char** expr, char* stop);
+int			compareKeys(uint32 type, const void* key1, size_t length1,
+				const void* key2, size_t length2);
+uint32		utf8ToUnicode(char** string);
+int32		getFirstPatternSymbol(char* string);
+status_t	isValidPattern(char* pattern);
+status_t	matchString(char* pattern, char* string);
+
+
+__END_DECLS
+
+
+static inline bool
+isPattern(char* string)
+{
+	return getFirstPatternSymbol(string) >= 0 ? true : false;
+}
+
+
+}	// namespace QueryParser
+
+
+#endif	// _FILE_SYSTEMS_QUERY_PARSER_UTILS_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile
index 119c77b67f..cc5c5e1d70 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Jamfile
+++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile
@@ -49,6 +49,10 @@ HAIKU_PACKAGE_FS_SOURCES =
 	Volume.cpp
 ;
 
+HAIKU_PACKAGE_FS_SHARED_SOURCES =
+	QueryParserUtils.cpp
+;
+
 HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES =
 	BlockBufferCacheImpl.cpp
 	BufferCache.cpp
@@ -76,12 +80,10 @@ local libSharedSources =
 ;
 
 
-SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
-
-
 KernelAddon packagefs
 	:
 	$(HAIKU_PACKAGE_FS_SOURCES)
+	$(HAIKU_PACKAGE_FS_SHARED_SOURCES)
 	$(HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES)
 	$(libSharedSources)
 
@@ -89,6 +91,10 @@ KernelAddon packagefs
 ;
 
 
+SEARCH on [ FGristFiles $(HAIKU_PACKAGE_FS_SHARED_SOURCES) ]
+	+= [ FDirName $(HAIKU_TOP) src add-ons kernel file_systems shared ] ;
+SEARCH on [ FGristFiles $(HAIKU_PACKAGE_FS_PACKAGE_READER_SOURCES) ]
+	+= [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
 SEARCH on [ FGristFiles $(libSharedSources) ]
 	+= [ FDirName $(HAIKU_TOP) src kits shared ] ;
 
diff --git a/src/add-ons/kernel/file_systems/shared/QueryParserUtils.cpp b/src/add-ons/kernel/file_systems/shared/QueryParserUtils.cpp
new file mode 100644
index 0000000000..b094dc7c0e
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/shared/QueryParserUtils.cpp
@@ -0,0 +1,317 @@
+/*
+ * Copyright 2001-2009, Axel Dörfler, axeld@pinc-software.de.
+ * Copyright 2010, Clemens Zeidler 
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * This file may be used under the terms of the MIT License.
+ */
+
+
+#include 
+
+#include 
+
+#include 
+
+#include 
+
+
+namespace QueryParser {
+
+
+template
+static inline int
+compare_integral(const Key& a, const Key& b)
+{
+	if (a < b)
+		return -1;
+	else if (a > b)
+		return 1;
+	return 0;
+}
+
+
+// #pragma mark -
+
+
+void
+skipWhitespace(char** expr, int32 skip)
+{
+	char* string = (*expr) + skip;
+	while (*string == ' ' || *string == '\t') string++;
+	*expr = string;
+}
+
+
+void
+skipWhitespaceReverse(char** expr, char* stop)
+{
+	char* string = *expr;
+	while (string > stop && (*string == ' ' || *string == '\t'))
+		string--;
+	*expr = string;
+}
+
+
+int
+compareKeys(uint32 type, const void* key1, size_t length1, const void* key2,
+	size_t length2)
+{
+	switch (type) {
+		case B_INT32_TYPE:
+			return compare_integral(*(int32*)key1, *(int32*)key2);
+		case B_UINT32_TYPE:
+			return compare_integral(*(uint32*)key1, *(uint32*)key2);
+		case B_INT64_TYPE:
+			return compare_integral(*(int64*)key1, *(int64*)key2);
+		case B_UINT64_TYPE:
+			return compare_integral(*(uint64*)key1, *(uint64*)key2);
+		case B_FLOAT_TYPE:
+			return compare_integral(*(float*)key1, *(float*)key2);
+		case B_DOUBLE_TYPE:
+			return compare_integral(*(double*)key1, *(double*)key2);
+		case B_STRING_TYPE:
+		{
+			int result = strncmp((const char*)key1, (const char*)key2,
+				std::min(length1, length2));
+			if (result == 0) {
+				result = compare_integral(strnlen((const char*)key1, length1),
+					strnlen((const char*)key2, length2));
+			}
+			return result;
+		}
+	}
+	return -1;
+}
+
+
+//	#pragma mark -
+
+
+uint32
+utf8ToUnicode(char** string)
+{
+	uint8* bytes = (uint8*)*string;
+	int32 length;
+	uint8 mask = 0x1f;
+
+	switch (bytes[0] & 0xf0) {
+		case 0xc0:
+		case 0xd0:
+			length = 2;
+			break;
+		case 0xe0:
+			length = 3;
+			break;
+		case 0xf0:
+			mask = 0x0f;
+			length = 4;
+			break;
+		default:
+			// valid 1-byte character
+			// and invalid characters
+			(*string)++;
+			return bytes[0];
+	}
+	uint32 c = bytes[0] & mask;
+	int32 i = 1;
+	for (; i < length && (bytes[i] & 0x80) > 0; i++)
+		c = (c << 6) | (bytes[i] & 0x3f);
+
+	if (i < length) {
+		// invalid character
+		(*string)++;
+		return (uint32)bytes[0];
+	}
+	*string += length;
+	return c;
+}
+
+
+int32
+getFirstPatternSymbol(char* string)
+{
+	char c;
+
+	for (int32 index = 0; (c = *string++); index++) {
+		if (c == '*' || c == '?' || c == '[')
+			return index;
+	}
+	return -1;
+}
+
+
+status_t
+isValidPattern(char* pattern)
+{
+	while (*pattern) {
+		switch (*pattern++) {
+			case '\\':
+				// the escape character must not be at the end of the pattern
+				if (!*pattern++)
+					return PATTERN_INVALID_ESCAPE;
+				break;
+
+			case '[':
+				if (pattern[0] == ']' || !pattern[0])
+					return PATTERN_INVALID_SET;
+
+				while (*pattern != ']') {
+					if (*pattern == '\\' && !*++pattern)
+						return PATTERN_INVALID_ESCAPE;
+
+					if (!*pattern)
+						return PATTERN_INVALID_SET;
+
+					if (pattern[0] == '-' && pattern[1] == '-')
+						return PATTERN_INVALID_RANGE;
+
+					pattern++;
+				}
+				break;
+		}
+	}
+	return B_OK;
+}
+
+
+/*!	Matches the string against the given wildcard pattern.
+	Returns either MATCH_OK, or NO_MATCH when everything went fine, or
+	values < 0 (see enum at the top of Query.cpp) if an error occurs.
+*/
+status_t
+matchString(char* pattern, char* string)
+{
+	while (*pattern) {
+		// end of string == valid end of pattern?
+		if (!string[0]) {
+			while (pattern[0] == '*')
+				pattern++;
+			return !pattern[0] ? MATCH_OK : NO_MATCH;
+		}
+
+		switch (*pattern++) {
+			case '?':
+			{
+				// match exactly one UTF-8 character; we are
+				// not interested in the result
+				utf8ToUnicode(&string);
+				break;
+			}
+
+			case '*':
+			{
+				// compact pattern
+				while (true) {
+					if (pattern[0] == '?') {
+						if (!*++string)
+							return NO_MATCH;
+					} else if (pattern[0] != '*')
+						break;
+
+					pattern++;
+				}
+
+				// if the pattern is done, we have matched the string
+				if (!pattern[0])
+					return MATCH_OK;
+
+				while(true) {
+					// we have removed all occurences of '*' and '?'
+					if (pattern[0] == string[0]
+						|| pattern[0] == '['
+						|| pattern[0] == '\\') {
+						status_t status = matchString(pattern, string);
+						if (status < B_OK || status == MATCH_OK)
+							return status;
+					}
+
+					// we could be nice here and just jump to the next
+					// UTF-8 character - but we wouldn't gain that much
+					// and it'd be slower (since we're checking for
+					// equality before entering the recursion)
+					if (!*++string)
+						return NO_MATCH;
+				}
+				break;
+			}
+
+			case '[':
+			{
+				bool invert = false;
+				if (pattern[0] == '^' || pattern[0] == '!') {
+					invert = true;
+					pattern++;
+				}
+
+				if (!pattern[0] || pattern[0] == ']')
+					return MATCH_BAD_PATTERN;
+
+				uint32 c = utf8ToUnicode(&string);
+				bool matched = false;
+
+				while (pattern[0] != ']') {
+					if (!pattern[0])
+						return MATCH_BAD_PATTERN;
+
+					if (pattern[0] == '\\')
+						pattern++;
+
+					uint32 first = utf8ToUnicode(&pattern);
+
+					// Does this character match, or is this a range?
+					if (first == c) {
+						matched = true;
+						break;
+					} else if (pattern[0] == '-' && pattern[1] != ']'
+							&& pattern[1]) {
+						pattern++;
+
+						if (pattern[0] == '\\') {
+							pattern++;
+							if (!pattern[0])
+								return MATCH_BAD_PATTERN;
+						}
+						uint32 last = utf8ToUnicode(&pattern);
+
+						if (c >= first && c <= last) {
+							matched = true;
+							break;
+						}
+					}
+				}
+
+				if (invert)
+					matched = !matched;
+
+				if (matched) {
+					while (pattern[0] != ']') {
+						if (!pattern[0])
+							return MATCH_BAD_PATTERN;
+						pattern++;
+					}
+					pattern++;
+					break;
+				}
+				return NO_MATCH;
+			}
+
+            case '\\':
+				if (!pattern[0])
+					return MATCH_BAD_PATTERN;
+				// supposed to fall through
+			default:
+				if (pattern[-1] != string[0])
+					return NO_MATCH;
+				string++;
+				break;
+		}
+	}
+
+	if (string[0])
+		return NO_MATCH;
+
+	return MATCH_OK;
+}
+
+
+}	// namespace QueryParser

From 901749cff25f1019b3442c436799d2c9ec631230 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 7 Jul 2011 15:40:04 +0200
Subject: [PATCH 0255/1170] Remove TwoKeyAVLTree from kernel utils again

It's not ready for shared use yet.
---
 .../kernel/file_systems/packagefs/LastModifiedIndex.cpp     | 2 +-
 src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp     | 3 +--
 src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp     | 2 +-
 .../add-ons/kernel/file_systems/packagefs}/TwoKeyAVLTree.h  | 6 +++---
 4 files changed, 6 insertions(+), 7 deletions(-)
 rename {headers/private/kernel/util => src/add-ons/kernel/file_systems/packagefs}/TwoKeyAVLTree.h (99%)

diff --git a/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp
index 0ce010f316..b7d637c1f8 100644
--- a/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp
@@ -11,11 +11,11 @@
 #include 
 
 #include 
-#include 
 
 #include "DebugSupport.h"
 #include "IndexImpl.h"
 #include "Node.h"
+#include "TwoKeyAVLTree.h"
 #include "Volume.h"
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
index 25bb84cd97..9726b05a90 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
@@ -8,11 +8,10 @@
 
 #include 
 
-#include 
-
 #include "DebugSupport.h"
 #include "IndexImpl.h"
 #include "Node.h"
+#include "TwoKeyAVLTree.h"
 #include "Volume.h"
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp
index a8c7860c0e..18022286fd 100644
--- a/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp
@@ -11,11 +11,11 @@
 #include 
 
 #include 
-#include 
 
 #include "DebugSupport.h"
 #include "IndexImpl.h"
 #include "Node.h"
+#include "TwoKeyAVLTree.h"
 #include "Volume.h"
 
 
diff --git a/headers/private/kernel/util/TwoKeyAVLTree.h b/src/add-ons/kernel/file_systems/packagefs/TwoKeyAVLTree.h
similarity index 99%
rename from headers/private/kernel/util/TwoKeyAVLTree.h
rename to src/add-ons/kernel/file_systems/packagefs/TwoKeyAVLTree.h
index 2c2ecd05c2..ee9d046e17 100644
--- a/headers/private/kernel/util/TwoKeyAVLTree.h
+++ b/src/add-ons/kernel/file_systems/packagefs/TwoKeyAVLTree.h
@@ -2,8 +2,8 @@
  * Copyright 2003-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
  * Distributed under the terms of the MIT License.
  */
-#ifndef _KERNEL_UTIL_TWO_KEY_AVL_TREE_H
-#define _KERNEL_UTIL_TWO_KEY_AVL_TREE_H
+#ifndef TWO_KEY_AVL_TREE_H
+#define TWO_KEY_AVL_TREE_H
 
 
 #include 
@@ -632,4 +632,4 @@ TWO_KEY_AVL_TREE_CLASS_NAME::_FindFirst(const PrimaryKey& key,
 }
 
 
-#endif	// _KERNEL_UTIL_TWO_KEY_AVL_TREE_H
+#endif	// TWO_KEY_AVL_TREE_H

From 3e29244600395a0cea91cfc0a0323016fc0f3253 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 8 Jul 2011 15:37:46 +0200
Subject: [PATCH 0256/1170] Move B_MIME_STRING_TYPE to 

---
 headers/build/os/storage/Mime.h                | 3 +--
 headers/os/storage/Mime.h                      | 3 +--
 headers/os/support/TypeConstants.h             | 1 +
 headers/private/file_systems/QueryParser.h     | 7 -------
 headers/private/fs_shell/fssh_api_wrapper.h    | 3 +++
 headers/private/fs_shell/fssh_type_constants.h | 3 +++
 src/add-ons/kernel/file_systems/bfs/Index.cpp  | 7 -------
 src/add-ons/kernel/file_systems/bfs/Query.cpp  | 5 -----
 8 files changed, 9 insertions(+), 23 deletions(-)

diff --git a/headers/build/os/storage/Mime.h b/headers/build/os/storage/Mime.h
index e79f33acff..109c5384c4 100644
--- a/headers/build/os/storage/Mime.h
+++ b/headers/build/os/storage/Mime.h
@@ -1,4 +1,4 @@
-/* 
+/*
  * Copyright 2004-2006, Haiku Inc. All Rights Reserved.
  * Distributed under the terms of the MIT License.
  */
@@ -31,7 +31,6 @@ status_t create_app_meta_mime(const char *path, int recursive, int synchronous,
 
 status_t get_device_icon(const char *dev, void *icon, int32 size);
 
-static const uint32 B_MIME_STRING_TYPE	= 'MIMS';
 
 enum icon_size {
 	B_LARGE_ICON	= 32,
diff --git a/headers/os/storage/Mime.h b/headers/os/storage/Mime.h
index d7b8f38c0a..bf810aee75 100644
--- a/headers/os/storage/Mime.h
+++ b/headers/os/storage/Mime.h
@@ -10,10 +10,9 @@
 
 #include 
 #include 
+#include 
 
 
-static const uint32 B_MIME_STRING_TYPE = 'MIMS';
-
 enum icon_size {
 	B_LARGE_ICON	= 32,
 	B_MINI_ICON		= 16
diff --git a/headers/os/support/TypeConstants.h b/headers/os/support/TypeConstants.h
index 7b9eb9935a..67cd0de4a6 100644
--- a/headers/os/support/TypeConstants.h
+++ b/headers/os/support/TypeConstants.h
@@ -60,6 +60,7 @@ enum {
 	B_VECTOR_ICON_TYPE				= 'VICN',
 	B_XATTR_TYPE					= 'XATR',
 	B_NETWORK_ADDRESS_TYPE			= 'NWAD',
+	B_MIME_STRING_TYPE				= 'MIMS',
 
 	// deprecated, do not use
 	B_ASCII_TYPE					= 'TEXT'	// use B_STRING_TYPE instead
diff --git a/headers/private/file_systems/QueryParser.h b/headers/private/file_systems/QueryParser.h
index fcb1ded513..beb6f703d6 100644
--- a/headers/private/file_systems/QueryParser.h
+++ b/headers/private/file_systems/QueryParser.h
@@ -111,13 +111,6 @@ union value {
 };
 
 
-// B_MIME_STRING_TYPE is defined in storage/Mime.h, but we
-// don't need the whole file here; the type can't change anyway
-#ifndef _MIME_H
-#	define B_MIME_STRING_TYPE 'MIMS'
-#endif
-
-
 template
 class Query {
 public:
diff --git a/headers/private/fs_shell/fssh_api_wrapper.h b/headers/private/fs_shell/fssh_api_wrapper.h
index fabc9ea33c..18fb61bc4b 100644
--- a/headers/private/fs_shell/fssh_api_wrapper.h
+++ b/headers/private/fs_shell/fssh_api_wrapper.h
@@ -1471,6 +1471,9 @@
 #define B_UINT8_TYPE					FSSH_B_UINT8_TYPE
 #define B_VECTOR_ICON_TYPE				FSSH_B_VECTOR_ICON_TYPE
 #define B_ASCII_TYPE					FSSH_B_ASCII_TYPE
+#define B_XATTR_TYPE					FSSH_B_XATTR_TYPE
+#define B_NETWORK_ADDRESS_TYPE			FSSH_B_NETWORK_ADDRESS_TYPE
+#define B_MIME_STRING_TYPE				FSSH_B_MIME_STRING_TYPE
 
 //----- System-wide MIME types for handling URL's ------------------------------
 
diff --git a/headers/private/fs_shell/fssh_type_constants.h b/headers/private/fs_shell/fssh_type_constants.h
index 6d93de93a4..9b0e13a8c1 100644
--- a/headers/private/fs_shell/fssh_type_constants.h
+++ b/headers/private/fs_shell/fssh_type_constants.h
@@ -55,6 +55,9 @@ enum {
 	FSSH_B_UINT64_TYPE					= 'ULLG',
 	FSSH_B_UINT8_TYPE					= 'UBYT',
 	FSSH_B_VECTOR_ICON_TYPE				= 'VICN',
+	FSSH_B_XATTR_TYPE					= 'XATR',
+	FSSH_B_NETWORK_ADDRESS_TYPE			= 'NWAD',
+	FSSH_B_MIME_STRING_TYPE				= 'MIMS',
 
 	// deprecated, do not use
 	FSSH_B_ASCII_TYPE					= 'TEXT'	// use B_STRING_TYPE instead
diff --git a/src/add-ons/kernel/file_systems/bfs/Index.cpp b/src/add-ons/kernel/file_systems/bfs/Index.cpp
index f86b37328f..abdcb86f60 100644
--- a/src/add-ons/kernel/file_systems/bfs/Index.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/Index.cpp
@@ -14,13 +14,6 @@
 #include "BPlusTree.h"
 
 
-// B_MIME_STRING_TYPE is defined in storage/Mime.h, but we
-// don't need the whole file here; the type can't change anyway
-#ifndef _MIME_H
-#	define B_MIME_STRING_TYPE 'MIMS'
-#endif
-
-
 Index::Index(Volume* volume)
 	:
 	fVolume(volume),
diff --git a/src/add-ons/kernel/file_systems/bfs/Query.cpp b/src/add-ons/kernel/file_systems/bfs/Query.cpp
index 6cb628e78e..d3742ba3cd 100644
--- a/src/add-ons/kernel/file_systems/bfs/Query.cpp
+++ b/src/add-ons/kernel/file_systems/bfs/Query.cpp
@@ -79,11 +79,6 @@ union value {
 	char	String[INODE_FILE_NAME_LENGTH];
 };
 
-// B_MIME_STRING_TYPE is defined in storage/Mime.h, but we
-// don't need the whole file here; the type can't change anyway
-#ifndef _MIME_H
-#	define B_MIME_STRING_TYPE 'MIMS'
-#endif
 
 /*!	Abstract base class for the operator/equation classes.
 */

From a52387c6690ca89344eb5f7df393efc65a9b70d8 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 8 Jul 2011 15:38:14 +0200
Subject: [PATCH 0257/1170] compareKeys(): Also handle B_MIME_STRING_TYPE

---
 src/add-ons/kernel/file_systems/shared/QueryParserUtils.cpp | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/add-ons/kernel/file_systems/shared/QueryParserUtils.cpp b/src/add-ons/kernel/file_systems/shared/QueryParserUtils.cpp
index b094dc7c0e..eb1cb4ec40 100644
--- a/src/add-ons/kernel/file_systems/shared/QueryParserUtils.cpp
+++ b/src/add-ons/kernel/file_systems/shared/QueryParserUtils.cpp
@@ -70,6 +70,7 @@ compareKeys(uint32 type, const void* key1, size_t length1, const void* key2,
 		case B_DOUBLE_TYPE:
 			return compare_integral(*(double*)key1, *(double*)key2);
 		case B_STRING_TYPE:
+		case B_MIME_STRING_TYPE:
 		{
 			int result = strncmp((const char*)key1, (const char*)key2,
 				std::min(length1, length2));

From 278925246f89909a7803dd0b5734f6207a2bdb92 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 8 Jul 2011 15:41:28 +0200
Subject: [PATCH 0258/1170] Remove unused PackageNodeAttribute::fParent

---
 .../file_systems/packagefs/PackageNodeAttribute.cpp       | 5 ++---
 .../kernel/file_systems/packagefs/PackageNodeAttribute.h  | 8 +++-----
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp      | 2 +-
 3 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.cpp
index 8644546c1e..e63b578652 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
  * Distributed under the terms of the MIT License.
  */
 
@@ -10,11 +10,10 @@
 #include 
 
 
-PackageNodeAttribute::PackageNodeAttribute(PackageNode* parent, uint32 type,
+PackageNodeAttribute::PackageNodeAttribute(uint32 type,
 	const BPackageData& data)
 	:
 	fData(data),
-	fParent(parent),
 	fName(NULL),
 	fType(type)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.h b/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.h
index 62dd9c5213..f899a04a0c 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.h
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
  * Distributed under the terms of the MIT License.
  */
 #ifndef PACKAGE_NODE_ATTRIBUTE_H
@@ -19,11 +19,10 @@ class PackageNode;
 class PackageNodeAttribute
 	: public DoublyLinkedListLinkImpl {
 public:
-								PackageNodeAttribute(PackageNode* parent,
-									uint32 type, const BPackageData& data);
+								PackageNodeAttribute(uint32 type,
+									const BPackageData& data);
 								~PackageNodeAttribute();
 
-			PackageNode*		Parent() const	{ return fParent; }
 			const char*			Name() const	{ return fName; }
 			uint32				Type() const	{ return fType; }
 			const BPackageData&	Data() const	{ return fData; }
@@ -33,7 +32,6 @@ public:
 
 protected:
 			BPackageData		fData;
-			PackageNode*		fParent;
 			char*				fName;
 			uint32				fType;
 };
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 04d993404d..3976723d48 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -263,7 +263,7 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
 		PackageNode* node = (PackageNode*)entry->UserToken();
 
 		PackageNodeAttribute* nodeAttribute = new(std::nothrow)
-			PackageNodeAttribute(node, attribute->Type(), attribute->Data());
+			PackageNodeAttribute(attribute->Type(), attribute->Data());
 		if (nodeAttribute == NULL)
 			RETURN_ERROR(B_NO_MEMORY)
 

From 51ee03beadbf26f9485e5dde936e09737e18c466 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 8 Jul 2011 15:42:24 +0200
Subject: [PATCH 0259/1170] QueryPolicy::NodeGetAttribute(): Get the type too

---
 src/add-ons/kernel/file_systems/packagefs/Query.cpp | 8 ++++++++
 1 file changed, 8 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Query.cpp b/src/add-ons/kernel/file_systems/packagefs/Query.cpp
index 4c51041e58..a51bdad153 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Query.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Query.cpp
@@ -187,6 +187,14 @@ struct Query::QueryPolicy {
 
 		error = cookie->ReadAttribute(0, buffer, _size);
 
+		// also get the attribute type
+		if (error == B_OK) {
+			struct stat st;
+			error = cookie->ReadAttributeStat(&st);
+			if (error == B_OK)
+				*_type = st.st_type;
+		}
+
 		cookie->Close();
 		delete cookie;
 

From 4d67e7847b2c58d8c6654f0b67fa27ccd7fdddb1 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 8 Jul 2011 15:46:34 +0200
Subject: [PATCH 0260/1170] More abstraction in GenericIndexIterator

* Move tree node operations to a subpolicy TreePolicy.
* Add a GenericIndexIteratorTreePolicy templatized over the policy,
  implementing the tree policy for the standard indices.
---
 .../kernel/file_systems/packagefs/IndexImpl.h | 91 ++++++++++++-------
 .../packagefs/LastModifiedIndex.cpp           |  7 +-
 .../file_systems/packagefs/NameIndex.cpp      |  7 +-
 .../file_systems/packagefs/SizeIndex.cpp      |  7 +-
 4 files changed, 68 insertions(+), 44 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
index 9714c16c2e..b55b63fefc 100644
--- a/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
+++ b/src/add-ons/kernel/file_systems/packagefs/IndexImpl.h
@@ -31,6 +31,7 @@ public:
 			typedef typename Policy::Index		Index;
 			typedef typename Policy::Value		Value;
 			typedef typename Policy::NodeTree	NodeTree;
+			typedef typename Policy::TreePolicy	TreePolicy;
 			typedef typename NodeTree::Node		TreeNode;
 
 public:
@@ -51,9 +52,6 @@ public:
 
 	virtual void				NodeRemoved(Node* node);
 
-protected:
-	inline	Node*				_ToNode() const;
-
 protected:
 			Index*				fIndex;
 			TreeNode*			fNextTreeNode;
@@ -75,7 +73,7 @@ GenericIndexIterator::GenericIndexIterator()
 template
 GenericIndexIterator::~GenericIndexIterator()
 {
-	SetTo(NULL, NULL);
+	SetTo(NULL, Value());
 }
 
 
@@ -94,15 +92,14 @@ GenericIndexIterator::Next(void* buffer, size_t* _keyLength)
 	if (fSuspended || fNextTreeNode == NULL)
 		return NULL;
 
-	Node* node = _ToNode();
-	if (node != NULL) {
-		if (buffer != NULL)
-			Policy::GetNodeValue(node, buffer, _keyLength);
 
-		fNextTreeNode = Policy::GetNodeTree(fIndex)->Next(fNextTreeNode);
-	}
+	if (buffer != NULL)
+		TreePolicy::GetTreeNodeValue(fNextTreeNode, buffer, _keyLength);
 
-	return node;
+	TreeNode* treeNode = fNextTreeNode;
+	fNextTreeNode = Policy::GetNodeTree(fIndex)->Next(fNextTreeNode);
+
+	return TreePolicy::GetNode(treeNode);
 }
 
 
@@ -113,8 +110,10 @@ GenericIndexIterator::Suspend()
 	if (fSuspended)
 		return B_BAD_VALUE;
 
-	if (fNextTreeNode != NULL)
-		fIndex->GetVolume()->AddNodeListener(this, _ToNode());
+	if (fNextTreeNode != NULL) {
+		fIndex->GetVolume()->AddNodeListener(this,
+			TreePolicy::GetNode(fNextTreeNode));
+	}
 
 	fSuspended = true;
 	return B_OK;
@@ -150,15 +149,11 @@ GenericIndexIterator::SetTo(Index* index, const Value& value,
 	if (fIndex == NULL)
 		return false;
 
-	typename NodeTree::Iterator iterator;
-	if (ignoreValue) {
-		Policy::GetNodeTree(fIndex)->GetIterator(&iterator);
-	} else if (Policy::GetNodeTree(fIndex)->FindFirstClosest(value, false,
-			&iterator) == NULL) {
-		return false;
-	}
+	if (ignoreValue)
+		fNextTreeNode = TreePolicy::GetFirstTreeNode(fIndex);
+	else
+		fNextTreeNode = TreePolicy::FindClosestTreeNode(fIndex, value);
 
-	fNextTreeNode = iterator.CurrentNode();
 	return fNextTreeNode != NULL;
 }
 
@@ -182,20 +177,17 @@ template
 void
 GenericIndexIterator::NodeChangeEnd(Node* node)
 {
-	if (fNextTreeNode != NULL) {
+	if (fNextTreeNode != NULL)
 		fNextTreeNode = Policy::GetNodeTree(fIndex)->Next(fNextTreeNode);
-	} else {
-		typename NodeTree::Iterator iterator;
-		Policy::GetNodeTree(fIndex)->GetIterator(&iterator);
-		fNextTreeNode = iterator.CurrentNode();
-	}
+	else
+		fNextTreeNode = TreePolicy::GetFirstTreeNode(fIndex);
 
 	// If the node is no longer the one we originally pointed to, re-register
 	// the node listener.
 	if (fNextTreeNode == NULL) {
 		fIndex->GetVolume()->RemoveNodeListener(this);
 	} else {
-		Node* newNode = _ToNode();
+		Node* newNode = TreePolicy::GetNode(fNextTreeNode);
 		if (newNode != node) {
 			fIndex->GetVolume()->RemoveNodeListener(this);
 			fIndex->GetVolume()->AddNodeListener(this, newNode);
@@ -215,13 +207,42 @@ GenericIndexIterator::NodeRemoved(Node* node)
 
 
 template
-Node*
-GenericIndexIterator::_ToNode() const
-{
-//	return NodeTree::NodeStrategy().GetValue(fNextTreeNode);
-	typename NodeTree::NodeStrategy strategy;
-	return strategy.GetValue(fNextTreeNode);
-}
+struct GenericIndexIteratorTreePolicy {
+	typedef typename Policy::Index		Index;
+	typedef typename Policy::Value		Value;
+	typedef typename Policy::NodeTree	NodeTree;
+	typedef typename NodeTree::Node		TreeNode;
+
+	static Node* GetNode(TreeNode* treeNode)
+	{
+		typename Policy::NodeTree::NodeStrategy strategy;
+		return strategy.GetValue(treeNode);
+	}
+
+	static TreeNode* GetFirstTreeNode(Index* index)
+	{
+		typename NodeTree::Iterator iterator;
+		Policy::GetNodeTree(index)->GetIterator(&iterator);
+		return iterator.CurrentNode();
+	}
+
+	static TreeNode* FindClosestTreeNode(Index* index, const Value& value)
+	{
+		typename NodeTree::Iterator iterator;
+		if (Policy::GetNodeTree(index)->FindFirstClosest(value, false,
+				&iterator) == NULL) {
+			return NULL;
+		}
+
+		return iterator.CurrentNode();
+	}
+
+	static void GetTreeNodeValue(TreeNode* treeNode, void* buffer,
+		size_t* _keyLength)
+	{
+		Policy::GetNodeValue(GetNode(treeNode), buffer, _keyLength);
+	}
+};
 
 
 #endif	// INDEX_IMPL_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp
index b7d637c1f8..e46b587438 100644
--- a/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp
@@ -105,9 +105,10 @@ class LastModifiedIndex::IteratorList : public SinglyLinkedList {};
 
 
 struct LastModifiedIndex::IteratorPolicy {
-	typedef LastModifiedIndex			Index;
-	typedef time_t						Value;
-	typedef LastModifiedIndex::NodeTree	NodeTree;
+	typedef LastModifiedIndex								Index;
+	typedef time_t											Value;
+	typedef LastModifiedIndex::NodeTree						NodeTree;
+	typedef GenericIndexIteratorTreePolicy	TreePolicy;
 
 	static NodeTree* GetNodeTree(Index* index)
 	{
diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
index 9726b05a90..25d3178234 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
@@ -85,9 +85,10 @@ class NameIndex::EntryTree : public _EntryTree {
 
 
 struct NameIndex::IteratorPolicy {
-	typedef NameIndex				Index;
-	typedef const char*				Value;
-	typedef NameIndex::EntryTree	NodeTree;
+	typedef NameIndex										Index;
+	typedef const char*										Value;
+	typedef NameIndex::EntryTree							NodeTree;
+	typedef GenericIndexIteratorTreePolicy	TreePolicy;
 
 	static NodeTree* GetNodeTree(Index* index)
 	{
diff --git a/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp
index 18022286fd..d11224691b 100644
--- a/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp
@@ -104,9 +104,10 @@ class SizeIndex::IteratorList : public SinglyLinkedList {};
 
 
 struct SizeIndex::IteratorPolicy {
-	typedef SizeIndex				Index;
-	typedef off_t					Value;
-	typedef SizeIndex::NodeTree		NodeTree;
+	typedef SizeIndex										Index;
+	typedef off_t											Value;
+	typedef SizeIndex::NodeTree								NodeTree;
+	typedef GenericIndexIteratorTreePolicy	TreePolicy;
 
 	static NodeTree* GetNodeTree(Index* index)
 	{

From 55b969b13bfbfba814aea0c961cae29825083ee6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 8 Jul 2011 16:14:46 +0200
Subject: [PATCH 0261/1170] Attribute index support for non-special attributes

* Add AttributeIndex class.
* Each attribute does now have an attribute index cookie. The new
  attribute index service methods Node::IndexAttribute() and
  IndexCookieForAttribute() create+set/retrieve the cookie. The cookie
  is actually the attribute index's tree node.
* Add OldNodeAttribute::IndexCookieForAttribute() so the cookie is
  available when the node changes.
---
 .../file_systems/packagefs/AttributeIndex.cpp | 410 ++++++++++++++++++
 .../file_systems/packagefs/AttributeIndex.h   |  63 +++
 .../file_systems/packagefs/AttributeIndexer.h |  42 ++
 .../packagefs/IndexedAttributeOwner.cpp       |  12 +
 .../packagefs/IndexedAttributeOwner.h         |  20 +
 .../kernel/file_systems/packagefs/Jamfile     |   2 +
 .../kernel/file_systems/packagefs/Node.cpp    |  14 +
 .../kernel/file_systems/packagefs/Node.h      |   4 +
 .../file_systems/packagefs/NodeListener.cpp   |   7 +
 .../file_systems/packagefs/NodeListener.h     |   1 +
 .../packagefs/OldUnpackingNodeAttributes.cpp  |   8 +
 .../packagefs/OldUnpackingNodeAttributes.h    |   1 +
 .../file_systems/packagefs/PackageNode.cpp    |   7 +
 .../file_systems/packagefs/PackageNode.h      |  16 +-
 .../packagefs/PackageNodeAttribute.cpp        |   1 +
 .../packagefs/PackageNodeAttribute.h          |   5 +
 .../packagefs/UnpackingAttributeCookie.cpp    |  77 +++-
 .../packagefs/UnpackingAttributeCookie.h      |   8 +
 .../packagefs/UnpackingDirectory.cpp          |  17 +
 .../packagefs/UnpackingDirectory.h            |   3 +
 .../packagefs/UnpackingLeafNode.cpp           |  17 +
 .../packagefs/UnpackingLeafNode.h             |   3 +
 22 files changed, 722 insertions(+), 16 deletions(-)
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/AttributeIndex.h
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/AttributeIndexer.h
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/IndexedAttributeOwner.cpp
 create mode 100644 src/add-ons/kernel/file_systems/packagefs/IndexedAttributeOwner.h

diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp
new file mode 100644
index 0000000000..3488ce32a8
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp
@@ -0,0 +1,410 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "AttributeIndex.h"
+
+#include 
+
+#include 
+
+#include 
+#include 
+
+#include 
+
+#include "AttributeIndexer.h"
+#include "DebugSupport.h"
+#include "IndexImpl.h"
+#include "Node.h"
+#include "Volume.h"
+
+
+struct AttributeIndexTreeKey {
+	const void*	data;
+	size_t		length;
+
+	AttributeIndexTreeKey()
+	{
+	}
+
+	AttributeIndexTreeKey(const void* data, size_t length)
+		:
+		data(data),
+		length(length)
+	{
+	}
+};
+
+
+struct AttributeIndexTreeValue : AVLTreeNode {
+	Node*					node;
+	IndexedAttributeOwner*	owner;
+	void*					attributeCookie;
+	size_t					length;
+	uint8					data[0];
+
+	static AttributeIndexTreeValue* Create(IndexedAttributeOwner* owner,
+		void* attributeCookie, size_t length)
+	{
+		AttributeIndexTreeValue* self = (AttributeIndexTreeValue*)malloc(
+			sizeof(AttributeIndexTreeValue) + length);
+		if (self == NULL)
+			return NULL;
+
+		self->owner = owner;
+		self->attributeCookie = attributeCookie;
+		self->length = length;
+		return self;
+	}
+
+	void Delete()
+	{
+		free(this);
+	}
+};
+
+
+struct AttributeIndex::TreeDefinition {
+	typedef TreeKey		Key;
+	typedef TreeValue	Value;
+
+	TreeDefinition(uint32 type)
+		:
+		fType(type)
+	{
+	}
+
+	AVLTreeNode* GetAVLTreeNode(Value* value) const
+	{
+		return value;
+	}
+
+	Value* GetValue(AVLTreeNode* node) const
+	{
+		return static_cast(node);
+	}
+
+	int Compare(const Key& a, const Value* b) const
+	{
+		return QueryParser::compareKeys(fType, a.data, a.length, b->data,
+			b->length);
+	}
+
+	int Compare(const Value* a, const Value* b) const
+	{
+		return QueryParser::compareKeys(fType, a->data, a->length, b->data,
+			b->length);
+	}
+
+private:
+	uint32	fType;
+};
+
+
+// #pragma mark - NodeTree
+
+
+struct AttributeIndex::NodeTree : public AVLTree {
+	typedef TreeValue	Node;
+
+	NodeTree(const TreeDefinition& definition)
+		:
+		AVLTree(definition)
+	{
+	}
+};
+
+
+// #pragma mark - IteratorList
+
+
+class AttributeIndex::IteratorList : public SinglyLinkedList {};
+
+
+// #pragma mark - Iterator
+
+
+struct AttributeIndex::IteratorPolicy {
+	typedef AttributeIndex				Index;
+	typedef TreeKey						Value;
+	typedef AttributeIndex::NodeTree	NodeTree;
+	typedef TreeValue					TreeNode;
+	typedef IteratorPolicy				TreePolicy;
+
+	static NodeTree* GetNodeTree(Index* index)
+	{
+		return index->fNodes;
+	}
+
+	static void GetTreeNodeValue(TreeNode* node, void* buffer,
+		size_t* _keyLength)
+	{
+		if (node->length > 0)
+			memcpy(buffer, node->data, node->length);
+		*_keyLength = node->length;
+	}
+
+	static Node* GetNode(TreeNode* treeNode)
+	{
+		return treeNode->node;
+	}
+
+	static TreeNode* GetFirstTreeNode(Index* index)
+	{
+		return index->fNodes->GetIterator().Next();
+	}
+
+	static TreeNode* FindClosestTreeNode(Index* index, const Value& value)
+	{
+		return index->fNodes->FindClosest(value, false);
+	}
+};
+
+
+class AttributeIndex::Iterator : public GenericIndexIterator,
+	public SinglyLinkedListLinkImpl {
+public:
+	virtual	void				NodeChanged(Node* node, uint32 statFields,
+									const OldNodeAttributes& oldAttributes);
+};
+
+
+// #pragma mark - AttributeIndexer
+
+
+AttributeIndexer::AttributeIndexer(AttributeIndex* index)
+	:
+	fIndex(index),
+	fIndexName(index->Name()),
+	fIndexType(index->Type()),
+	fCookie(NULL)
+{
+}
+
+
+AttributeIndexer::~AttributeIndexer()
+{
+}
+
+
+status_t
+AttributeIndexer::CreateCookie(IndexedAttributeOwner* owner,
+	void* attributeCookie, uint32 attributeType, size_t attributeSize,
+	void*& _data, size_t& _toRead)
+{
+	// check the attribute type and size
+	if (attributeType != fIndexType)
+		return B_ERROR;
+
+	if (fIndex->HasFixedKeyLength()) {
+		if (attributeSize != fIndex->KeyLength())
+			return B_ERROR;
+	} else if (attributeSize > kMaxIndexKeyLength)
+		attributeSize = kMaxIndexKeyLength;
+
+	// create the tree value
+	fCookie = AttributeIndexTreeValue::Create(owner, attributeCookie,
+		attributeSize);
+	if (fCookie == NULL)
+		return B_NO_MEMORY;
+
+	_data = fCookie->data;
+	_toRead = attributeSize;
+
+	return B_OK;
+}
+
+
+void
+AttributeIndexer::DeleteCookie()
+{
+	fCookie->Delete();
+	fCookie = NULL;
+}
+
+
+// #pragma mark - AttributeIndex
+
+
+AttributeIndex::AttributeIndex()
+	:
+	Index(),
+	fNodes(NULL),
+	fIteratorsToUpdate(NULL),
+	fIndexer(NULL)
+{
+}
+
+
+AttributeIndex::~AttributeIndex()
+{
+	if (IsListening())
+		fVolume->RemoveNodeListener(this);
+
+	ASSERT(fIteratorsToUpdate->IsEmpty());
+
+	delete fIteratorsToUpdate;
+	delete fNodes;
+	delete fIndexer;
+}
+
+
+status_t
+AttributeIndex::Init(Volume* volume, const char* name,  uint32 type,
+	size_t keyLength)
+{
+	status_t error = Index::Init(volume, name, type, keyLength > 0, keyLength);
+	if (error != B_OK)
+		return error;
+
+	// TODO: Letting each attribute index be a listener is gets more expensive
+	// the more attribute indices we have. Since most attribute indices are
+	// rather sparse, it might be a good idea to rather let Volume iterate
+	// through the actual attributes of an added node and look up and call the
+	// index for each one explicitly. When removing the node, the volume would
+	// iterate through the attributes again and determine based on the index
+	// cookie whether an index has to be notified.
+	fVolume->AddNodeListener(this, NULL);
+
+	fNodes = new(std::nothrow) NodeTree(TreeDefinition(type));
+	fIteratorsToUpdate = new(std::nothrow) IteratorList;
+	fIndexer = new(std::nothrow) AttributeIndexer(this);
+
+	if (fNodes == NULL || fIteratorsToUpdate == NULL || fIndexer == NULL)
+		return B_NO_MEMORY;
+
+	return B_OK;
+}
+
+
+int32
+AttributeIndex::CountEntries() const
+{
+	return fNodes->Count();
+}
+
+
+void
+AttributeIndex::NodeAdded(Node* node)
+{
+	if (node->IndexAttribute(fIndexer) != B_OK)
+		return;
+
+	TreeValue* treeValue = fIndexer->Cookie();
+	treeValue->node = node;
+
+	fNodes->Insert(treeValue);
+}
+
+
+void
+AttributeIndex::NodeRemoved(Node* node)
+{
+	TreeValue* treeValue = (TreeValue*)node->IndexCookieForAttribute(Name());
+	if (treeValue == NULL)
+		return;
+
+	treeValue->owner->UnsetIndexCookie(treeValue->attributeCookie);
+	fNodes->Remove(treeValue);
+}
+
+
+void
+AttributeIndex::NodeChanged(Node* node, uint32 statFields,
+	const OldNodeAttributes& oldAttributes)
+{
+	IteratorList iterators;
+	iterators.MoveFrom(fIteratorsToUpdate);
+
+	TreeValue* oldTreeValue
+		= (TreeValue*)oldAttributes.IndexCookieForAttribute(Name());
+	TreeValue* treeValue = (TreeValue*)node->IndexCookieForAttribute(Name());
+	if (treeValue == NULL && oldTreeValue == NULL)
+		return;
+
+	// move the iterators that point to the node to the previous node
+	if (oldTreeValue != NULL) {
+		for (IteratorList::Iterator it = iterators.GetIterator();
+				Iterator* iterator = it.Next();) {
+			iterator->NodeChangeBegin(node);
+		}
+
+		// remove the node
+		fNodes->Remove(oldTreeValue);
+	}
+
+	// re-insert the node
+	if (treeValue != NULL)
+		fNodes->Insert(treeValue);
+
+	// Move the iterators to the next node again. If the node hasn't changed
+	// its place, they will point to it again, otherwise to the node originally
+	// succeeding it.
+	if (oldTreeValue != NULL) {
+		for (IteratorList::Iterator it = iterators.GetIterator();
+				Iterator* iterator = it.Next();) {
+			iterator->NodeChangeEnd(node);
+		}
+	}
+
+	// update live queries
+	fVolume->UpdateLiveQueries(node, Name(), Type(),
+		oldTreeValue != NULL ? oldTreeValue->data : NULL,
+		oldTreeValue != NULL ? oldTreeValue->length : 0,
+		treeValue != NULL ? treeValue->data : NULL,
+		treeValue != NULL ? treeValue->length : 0);
+
+	if (oldTreeValue != NULL)
+		oldTreeValue->Delete();
+}
+
+
+AbstractIndexIterator*
+AttributeIndex::InternalGetIterator()
+{
+	Iterator* iterator = new(std::nothrow) Iterator;
+	if (iterator != NULL) {
+		if (!iterator->SetTo(this, TreeKey(), true)) {
+			delete iterator;
+			iterator = NULL;
+		}
+	}
+	return iterator;
+}
+
+
+AbstractIndexIterator*
+AttributeIndex::InternalFind(const void* key, size_t length)
+{
+	if (key == NULL)
+		return NULL;
+	Iterator* iterator = new(std::nothrow) Iterator;
+	if (iterator != NULL) {
+		if (!iterator->SetTo(this, TreeKey(key, length))) {
+			delete iterator;
+			iterator = NULL;
+		}
+	}
+	return iterator;
+}
+
+
+void
+AttributeIndex::_AddIteratorToUpdate(Iterator* iterator)
+{
+	fIteratorsToUpdate->Add(iterator);
+}
+
+
+// #pragma mark - Iterator
+
+
+void
+AttributeIndex::Iterator::NodeChanged(Node* node, uint32 statFields,
+	const OldNodeAttributes& oldAttributes)
+{
+	fIndex->_AddIteratorToUpdate(this);
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.h b/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.h
new file mode 100644
index 0000000000..c0e3f1fb58
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef ATTRIBUTE_INDEX_H
+#define ATTRIBUTE_INDEX_H
+
+
+#include "Index.h"
+#include "NodeListener.h"
+
+
+class AttributeIndexer;
+struct AttributeIndexTreeKey;
+struct AttributeIndexTreeValue;
+
+
+class AttributeIndex : public Index, private NodeListener {
+public:
+								AttributeIndex();
+	virtual						~AttributeIndex();
+
+			status_t			Init(Volume* volume, const char* name,
+									uint32 type, size_t keyLength);
+
+	virtual	int32				CountEntries() const;
+
+private:
+	virtual	void				NodeAdded(Node* node);
+	virtual	void				NodeRemoved(Node* node);
+	virtual	void				NodeChanged(Node* node, uint32 statFields,
+									const OldNodeAttributes& oldAttributes);
+
+protected:
+	virtual	AbstractIndexIterator* InternalGetIterator();
+	virtual	AbstractIndexIterator* InternalFind(const void* key,
+									size_t length);
+
+private:
+			typedef AttributeIndexTreeKey TreeKey;
+			typedef AttributeIndexTreeValue TreeValue;
+			struct TreeDefinition;
+			struct NodeTree;
+
+			struct IteratorPolicy;
+			class Iterator;
+			class IteratorList;
+			friend class Iterator;
+			friend struct IteratorPolicy;
+
+			friend class AttributeIndexer;
+
+private:
+			void				_AddIteratorToUpdate(Iterator* iterator);
+
+private:
+			NodeTree*			fNodes;
+			IteratorList*		fIteratorsToUpdate;
+			AttributeIndexer*	fIndexer;
+};
+
+
+#endif	// ATTRIBUTE_INDEX_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeIndexer.h b/src/add-ons/kernel/file_systems/packagefs/AttributeIndexer.h
new file mode 100644
index 0000000000..f332b29f69
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/AttributeIndexer.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef ATTRIBUTE_INDEXER_H
+#define ATTRIBUTE_INDEXER_H
+
+
+#include 
+
+
+class AttributeIndex;
+class AttributeIndexTreeValue;
+class IndexedAttributeOwner;
+
+
+class AttributeIndexer {
+public:
+								AttributeIndexer(AttributeIndex* index);
+								~AttributeIndexer();
+
+			status_t			CreateCookie(IndexedAttributeOwner* owner,
+									void* attributeCookie, uint32 attributeType,
+									size_t attributeSize, void*& _data,
+									size_t& _toRead);
+			void				DeleteCookie();
+
+			AttributeIndexTreeValue* Cookie() const
+									{ return fCookie; }
+
+			const char*			IndexName() const
+									{ return fIndexName; }
+
+private:
+			AttributeIndex*		fIndex;
+			const char*			fIndexName;
+			uint32				fIndexType;
+			AttributeIndexTreeValue* fCookie;
+};
+
+
+#endif	// ATTRIBUTE_INDEX_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/IndexedAttributeOwner.cpp b/src/add-ons/kernel/file_systems/packagefs/IndexedAttributeOwner.cpp
new file mode 100644
index 0000000000..7e173633ab
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/IndexedAttributeOwner.cpp
@@ -0,0 +1,12 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "IndexedAttributeOwner.h"
+
+
+IndexedAttributeOwner::~IndexedAttributeOwner()
+{
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/IndexedAttributeOwner.h b/src/add-ons/kernel/file_systems/packagefs/IndexedAttributeOwner.h
new file mode 100644
index 0000000000..76bcb91edc
--- /dev/null
+++ b/src/add-ons/kernel/file_systems/packagefs/IndexedAttributeOwner.h
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef INDEXED_ATTRIBUTE_OWNER_H
+#define INDEXED_ATTRIBUTE_OWNER_H
+
+
+#include 
+
+
+class IndexedAttributeOwner {
+public:
+	virtual						~IndexedAttributeOwner();
+
+	virtual	void				UnsetIndexCookie(void* attributeCookie) = 0;
+};
+
+
+#endif	// INDEXED_ATTRIBUTE_OWNER_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile
index cc5c5e1d70..d0576a0423 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Jamfile
+++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile
@@ -9,6 +9,7 @@ UsePrivateHeaders shared storage ;
 HAIKU_PACKAGE_FS_SOURCES =
 	AttributeCookie.cpp
 	AttributeDirectoryCookie.cpp
+	AttributeIndex.cpp
 	AutoPackageAttributes.cpp
 	BlockBufferCacheKernel.cpp
 	DebugSupport.cpp
@@ -17,6 +18,7 @@ HAIKU_PACKAGE_FS_SOURCES =
 	EmptyAttributeDirectoryCookie.cpp
 	GlobalFactory.cpp
 	Index.cpp
+	IndexedAttributeOwner.cpp
 	kernel_interface.cpp
 	LastModifiedIndex.cpp
 	NameIndex.cpp
diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.cpp b/src/add-ons/kernel/file_systems/packagefs/Node.cpp
index 2ed70e2669..f452c913a7 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Node.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Node.cpp
@@ -77,3 +77,17 @@ Node::SetParent(Directory* parent)
 {
 	fParent = parent;
 }
+
+
+status_t
+Node::IndexAttribute(AttributeIndexer* indexer)
+{
+	return B_NOT_SUPPORTED;
+}
+
+
+void*
+Node::IndexCookieForAttribute(const char* name) const
+{
+	return NULL;
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h
index fce665329e..d7465af16c 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Node.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Node.h
@@ -19,6 +19,7 @@
 
 class AttributeCookie;
 class AttributeDirectoryCookie;
+class AttributeIndexer;
 class Directory;
 class PackageNode;
 
@@ -83,6 +84,9 @@ public:
 	virtual	status_t			OpenAttribute(const char* name, int openMode,
 									AttributeCookie*& _cookie) = 0;
 
+	virtual	status_t			IndexAttribute(AttributeIndexer* indexer);
+	virtual	void*				IndexCookieForAttribute(const char* name) const;
+
 protected:
 			rw_lock				fLock;
 			ino_t				fID;
diff --git a/src/add-ons/kernel/file_systems/packagefs/NodeListener.cpp b/src/add-ons/kernel/file_systems/packagefs/NodeListener.cpp
index ae77b4c1dc..d38064ed32 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NodeListener.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NodeListener.cpp
@@ -15,6 +15,13 @@ OldNodeAttributes::~OldNodeAttributes()
 }
 
 
+void*
+OldNodeAttributes::IndexCookieForAttribute(const char* name) const
+{
+	return NULL;
+}
+
+
 // #pragma mark - NodeListener
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/NodeListener.h b/src/add-ons/kernel/file_systems/packagefs/NodeListener.h
index 35ab10e19a..1d583acb4b 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NodeListener.h
+++ b/src/add-ons/kernel/file_systems/packagefs/NodeListener.h
@@ -24,6 +24,7 @@ public:
 
 	virtual	timespec			ModifiedTime() const = 0;
 	virtual	off_t				FileSize() const = 0;
+	virtual	void*				IndexCookieForAttribute(const char* name) const;
 };
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.cpp b/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.cpp
index f4508edb41..173a1daf6a 100644
--- a/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.cpp
@@ -33,3 +33,11 @@ OldUnpackingNodeAttributes::FileSize() const
 {
 	return fPackageNode != NULL ? fPackageNode->FileSize() : 0;
 }
+
+
+void*
+OldUnpackingNodeAttributes::IndexCookieForAttribute(const char* name) const
+{
+	return fPackageNode != NULL
+		? fPackageNode->IndexCookieForAttribute(name) : NULL;
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.h b/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.h
index 867ab0741f..c9f348360b 100644
--- a/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.h
+++ b/src/add-ons/kernel/file_systems/packagefs/OldUnpackingNodeAttributes.h
@@ -19,6 +19,7 @@ public:
 
 	virtual	timespec			ModifiedTime() const;
 	virtual	off_t				FileSize() const;
+	virtual	void*				IndexCookieForAttribute(const char* name) const;
 
 private:
 			PackageNode*		fPackageNode;
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp
index 7291a0f381..585907afe4 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp
@@ -90,3 +90,10 @@ PackageNode::FindAttribute(const char* name) const
 
 	return NULL;
 }
+
+
+void
+PackageNode::UnsetIndexCookie(void* attributeCookie)
+{
+	((PackageNodeAttribute*)attributeCookie)->SetIndexCookie(NULL);
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageNode.h b/src/add-ons/kernel/file_systems/packagefs/PackageNode.h
index 1b215ec363..ec6a57fdc5 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageNode.h
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageNode.h
@@ -12,14 +12,16 @@
 
 #include 
 
+#include "IndexedAttributeOwner.h"
 #include "PackageNodeAttribute.h"
 
 
+class AttributeIndexer;
 class Package;
 class PackageDirectory;
 
 
-class PackageNode : public BReferenceable,
+class PackageNode : public BReferenceable, public IndexedAttributeOwner,
 	public SinglyLinkedListLinkImpl {
 public:
 								PackageNode(Package* package, mode_t mode);
@@ -59,6 +61,10 @@ public:
 
 			PackageNodeAttribute* FindAttribute(const char* name) const;
 
+	virtual	void				UnsetIndexCookie(void* attributeCookie);
+
+	inline	void*				IndexCookieForAttribute(const char* name) const;
+
 protected:
 			Package*			fPackage;
 			PackageDirectory*	fParent;
@@ -71,6 +77,14 @@ protected:
 };
 
 
+void*
+PackageNode::IndexCookieForAttribute(const char* name) const
+{
+	PackageNodeAttribute* attribute = FindAttribute(name);
+	return attribute != NULL ? attribute->IndexCookie() : NULL;
+}
+
+
 typedef SinglyLinkedList PackageNodeList;
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.cpp
index e63b578652..cd80d831ac 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.cpp
@@ -15,6 +15,7 @@ PackageNodeAttribute::PackageNodeAttribute(uint32 type,
 	:
 	fData(data),
 	fName(NULL),
+	fIndexCookie(NULL),
 	fType(type)
 {
 }
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.h b/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.h
index f899a04a0c..361dd81647 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.h
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageNodeAttribute.h
@@ -29,10 +29,15 @@ public:
 
 			status_t			Init(const char* name);
 
+			void				SetIndexCookie(void* cookie)
+									{ fIndexCookie = cookie; }
+			void*				IndexCookie() const
+									{ return fIndexCookie; }
 
 protected:
 			BPackageData		fData;
 			char*				fName;
+			void*				fIndexCookie;
 			uint32				fType;
 };
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp
index 8804dcbd93..714bb7d780 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.cpp
@@ -15,6 +15,7 @@
 
 #include 
 
+#include "AttributeIndexer.h"
 #include "AutoPackageAttributes.h"
 #include "DebugSupport.h"
 #include "GlobalFactory.h"
@@ -108,21 +109,7 @@ status_t
 UnpackingAttributeCookie::ReadAttribute(off_t offset, void* buffer,
 	size_t* bufferSize)
 {
-	const BPackageData& data = fAttribute->Data();
-	if (data.IsEncodedInline()) {
-		// inline data
-		BBufferDataReader dataReader(data.InlineData(), data.CompressedSize());
-		return read_package_data(data, &dataReader, offset, buffer, bufferSize);
-	}
-
-	// data not inline -- open the package
-	int fd = fPackage->Open();
-	if (fd < 0)
-		RETURN_ERROR(fd);
-	PackageCloser packageCloser(fPackage);
-
-	BFDDataReader dataReader(fd);
-	return read_package_data(data, &dataReader, offset, buffer, bufferSize);
+	return ReadAttribute(fPackageNode, fAttribute, offset, buffer, bufferSize);
 }
 
 
@@ -134,3 +121,63 @@ UnpackingAttributeCookie::ReadAttributeStat(struct stat* st)
 
 	return B_OK;
 }
+
+
+/*static*/ status_t
+UnpackingAttributeCookie::ReadAttribute(PackageNode* packageNode,
+	PackageNodeAttribute* attribute, off_t offset, void* buffer,
+	size_t* bufferSize)
+{
+	const BPackageData& data = attribute->Data();
+	if (data.IsEncodedInline()) {
+		// inline data
+		BBufferDataReader dataReader(data.InlineData(), data.CompressedSize());
+		return read_package_data(data, &dataReader, offset, buffer, bufferSize);
+	}
+
+	// data not inline -- open the package
+	Package* package = packageNode->GetPackage();
+	int fd = package->Open();
+	if (fd < 0)
+		RETURN_ERROR(fd);
+	PackageCloser packageCloser(package);
+
+	BFDDataReader dataReader(fd);
+	return read_package_data(data, &dataReader, offset, buffer, bufferSize);
+}
+
+
+/*static*/ status_t
+UnpackingAttributeCookie::IndexAttribute(PackageNode* packageNode,
+	AttributeIndexer* indexer)
+{
+	if (packageNode == NULL)
+		return B_ENTRY_NOT_FOUND;
+
+	// get the attribute
+	PackageNodeAttribute* attribute = packageNode->FindAttribute(
+		indexer->IndexName());
+	if (attribute == NULL)
+		return B_ENTRY_NOT_FOUND;
+
+	// create the index cookie
+	void* data;
+	size_t toRead;
+	status_t error = indexer->CreateCookie(packageNode, attribute,
+		attribute->Type(), attribute->Data().UncompressedSize(), data, toRead);
+	if (error != B_OK)
+		return error;
+
+	// read the attribute
+	if (toRead > 0) {
+		error = ReadAttribute(packageNode, attribute, 0, data, &toRead);
+		if (error != B_OK) {
+			indexer->DeleteCookie();
+			return error;
+		}
+	}
+
+	attribute->SetIndexCookie(indexer->Cookie());
+
+	return B_OK;
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.h
index 9dda846775..8a20257efa 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.h
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingAttributeCookie.h
@@ -9,6 +9,7 @@
 #include "AttributeCookie.h"
 
 
+class AttributeIndexer;
 class Package;
 class PackageNode;
 class PackageNodeAttribute;
@@ -29,6 +30,13 @@ public:
 									size_t* bufferSize);
 	virtual	status_t			ReadAttributeStat(struct stat* st);
 
+	static	status_t			ReadAttribute(PackageNode* packageNode,
+									PackageNodeAttribute* attribute,
+									off_t offset, void* buffer,
+									size_t* bufferSize);
+	static	status_t			IndexAttribute(PackageNode* packageNode,
+									AttributeIndexer* indexer);
+
 private:
 			PackageNode*		fPackageNode;
 			Package*			fPackage;
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp
index dad396e1e9..7c70b523b0 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp
@@ -149,6 +149,23 @@ UnpackingDirectory::OpenAttribute(const char* name, int openMode,
 }
 
 
+status_t
+UnpackingDirectory::IndexAttribute(AttributeIndexer* indexer)
+{
+	return UnpackingAttributeCookie::IndexAttribute(fPackageDirectories.Head(),
+		indexer);
+}
+
+
+void*
+UnpackingDirectory::IndexCookieForAttribute(const char* name) const
+{
+	if (PackageDirectory* packageDirectory = fPackageDirectories.Head())
+		return packageDirectory->IndexCookieForAttribute(name);
+	return NULL;
+}
+
+
 // #pragma mark - RootDirectory
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h
index ce2b4a8578..bb94156e9a 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h
@@ -34,6 +34,9 @@ public:
 	virtual	status_t			OpenAttribute(const char* name, int openMode,
 									AttributeCookie*& _cookie);
 
+	virtual	status_t			IndexAttribute(AttributeIndexer* indexer);
+	virtual	void*				IndexCookieForAttribute(const char* name) const;
+
 private:
 			PackageDirectoryList fPackageDirectories;
 };
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp
index 6504ac718a..80ca1b96a3 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp
@@ -210,3 +210,20 @@ UnpackingLeafNode::OpenAttribute(const char* name, int openMode,
 	return UnpackingAttributeCookie::Open(fPackageNodes.Head(), name, openMode,
 		_cookie);
 }
+
+
+status_t
+UnpackingLeafNode::IndexAttribute(AttributeIndexer* indexer)
+{
+	return UnpackingAttributeCookie::IndexAttribute(fPackageNodes.Head(),
+		indexer);
+}
+
+
+void*
+UnpackingLeafNode::IndexCookieForAttribute(const char* name) const
+{
+	if (PackageLeafNode* packageNode = fPackageNodes.Head())
+		return packageNode->IndexCookieForAttribute(name);
+	return NULL;
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h
index 3ebffbd28b..b9ed5de547 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h
@@ -44,6 +44,9 @@ public:
 	virtual	status_t			OpenAttribute(const char* name, int openMode,
 									AttributeCookie*& _cookie);
 
+	virtual	status_t			IndexAttribute(AttributeIndexer* indexer);
+	virtual	void*				IndexCookieForAttribute(const char* name) const;
+
 private:
 			PackageLeafNodeList	fPackageNodes;
 };

From 061337ba5f903fedea109ad526c68cc7238254ff Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 8 Jul 2011 16:15:14 +0200
Subject: [PATCH 0262/1170] Create a "BEOS:APP_SIG" index by default

---
 .../kernel/file_systems/packagefs/Volume.cpp     | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 3976723d48..b8d2154b61 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -30,6 +30,7 @@
 #include 
 #include 
 
+#include "AttributeIndex.h"
 #include "DebugSupport.h"
 #include "kernel_interface.h"
 #include "LastModifiedIndex.h"
@@ -556,6 +557,21 @@ Volume::Mount(const char* parameterString)
 		fIndices.Insert(index);
 	}
 
+	// create a BEOS:APP_SIG index
+	{
+		AttributeIndex* index = new(std::nothrow) AttributeIndex;
+		if (index == NULL)
+			RETURN_ERROR(B_NO_MEMORY);
+
+		error = index->Init(this, "BEOS:APP_SIG", B_MIME_STRING_TYPE, 0);
+		if (error != B_OK) {
+			delete index;
+			RETURN_ERROR(error);
+		}
+
+		fIndices.Insert(index);
+	}
+
 	// get the mount parameters
 	const char* packages = NULL;
 	const char* volumeName = NULL;

From 4006e483694cb960a25d1a95b76ea2209265d217 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 8 Jul 2011 23:32:56 +0200
Subject: [PATCH 0263/1170] Check key length, if index keys are fixed length

---
 src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp
index 3488ce32a8..e93a43424a 100644
--- a/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp
@@ -379,8 +379,9 @@ AttributeIndex::InternalGetIterator()
 AbstractIndexIterator*
 AttributeIndex::InternalFind(const void* key, size_t length)
 {
-	if (key == NULL)
+	if (HasFixedKeyLength() && length != KeyLength())
 		return NULL;
+
 	Iterator* iterator = new(std::nothrow) Iterator;
 	if (iterator != NULL) {
 		if (!iterator->SetTo(this, TreeKey(key, length))) {

From ac6706807e872a28ea43f6fabf83d57e02996aa0 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 8 Jul 2011 23:33:29 +0200
Subject: [PATCH 0264/1170] Remove superfluous checks

---
 src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp | 2 +-
 src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp         | 2 +-
 src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp         | 2 +-
 3 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp
index e46b587438..adee57ceac 100644
--- a/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/LastModifiedIndex.cpp
@@ -260,7 +260,7 @@ LastModifiedIndex::InternalGetIterator()
 AbstractIndexIterator*
 LastModifiedIndex::InternalFind(const void* key, size_t length)
 {
-	if (!key || length != sizeof(time_t))
+	if (length != sizeof(time_t))
 		return NULL;
 	Iterator* iterator = new(std::nothrow) Iterator;
 	if (iterator != NULL) {
diff --git a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
index 25d3178234..833adbfd2c 100644
--- a/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/NameIndex.cpp
@@ -200,7 +200,7 @@ NameIndex::InternalGetIterator()
 AbstractIndexIterator*
 NameIndex::InternalFind(const void* _key, size_t length)
 {
-	if (_key == NULL || length == 0)
+	if (length == 0)
 		return NULL;
 
 	const char* key = (const char*)_key;
diff --git a/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp
index d11224691b..39d8a1b069 100644
--- a/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/SizeIndex.cpp
@@ -258,7 +258,7 @@ SizeIndex::InternalGetIterator()
 AbstractIndexIterator*
 SizeIndex::InternalFind(const void* key, size_t length)
 {
-	if (!key || length != sizeof(off_t))
+	if (length != sizeof(off_t))
 		return NULL;
 	Iterator* iterator = new(std::nothrow) Iterator;
 	if (iterator != NULL) {

From 29ee8957577e434b32d37ec895d7b8125e83a9a5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 8 Jul 2011 23:35:17 +0200
Subject: [PATCH 0265/1170] Remove references in index iterator interface

This avoids checks.
---
 .../kernel/file_systems/packagefs/Index.cpp   | 31 +++++++------------
 .../kernel/file_systems/packagefs/Index.h     |  4 +--
 .../kernel/file_systems/packagefs/Query.cpp   |  4 +--
 3 files changed, 15 insertions(+), 24 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Index.cpp b/src/add-ons/kernel/file_systems/packagefs/Index.cpp
index b0ccfb747e..6b0716a37c 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Index.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Index.cpp
@@ -49,32 +49,23 @@ Index::Init(Volume* volume, const char* name, uint32 type, bool fixedKeyLength,
 
 
 bool
-Index::GetIterator(IndexIterator* iterator)
+Index::GetIterator(IndexIterator& iterator)
 {
-	bool result = false;
-	if (iterator) {
-		AbstractIndexIterator* actualIterator = InternalGetIterator();
-		if (actualIterator) {
-			iterator->SetIterator(actualIterator);
-			result = true;
-		}
-	}
-	return result;
+	AbstractIndexIterator* actualIterator = InternalGetIterator();
+	iterator.SetIterator(actualIterator);
+
+	return actualIterator != NULL;
 }
 
 
 bool
-Index::Find(const void* key, size_t length, IndexIterator* iterator)
+Index::Find(const void* key, size_t length, IndexIterator& iterator)
 {
-	bool result = false;
-	if (key && iterator) {
-		AbstractIndexIterator* actualIterator = InternalFind(key, length);
-		if (actualIterator) {
-			iterator->SetIterator(actualIterator);
-			result = true;
-		}
-	}
-	return result;
+	AbstractIndexIterator* actualIterator
+		= key != NULL ? InternalFind(key, length) : NULL;
+	iterator.SetIterator(actualIterator);
+
+	return actualIterator != NULL;
 }
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Index.h b/src/add-ons/kernel/file_systems/packagefs/Index.h
index 53be4c3215..008c8be33e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Index.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Index.h
@@ -42,9 +42,9 @@ public:
 
 	virtual	int32				CountEntries() const = 0;
 
-			bool				GetIterator(IndexIterator* iterator);
+			bool				GetIterator(IndexIterator& iterator);
 			bool				Find(const void* key, size_t length,
-									IndexIterator* iterator);
+									IndexIterator& iterator);
 									// sets the iterator to the first value
 									// >= key
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Query.cpp b/src/add-ons/kernel/file_systems/packagefs/Query.cpp
index a51bdad153..2f5d39c632 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Query.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Query.cpp
@@ -119,7 +119,7 @@ struct Query::QueryPolicy {
 		if (iterator == NULL)
 			return NULL;
 
-		if (!index.index->GetIterator(iterator)) {
+		if (!index.index->GetIterator(*iterator)) {
 			delete iterator;
 			return NULL;
 		}
@@ -137,7 +137,7 @@ struct Query::QueryPolicy {
 	static status_t IndexIteratorFind(IndexIterator* indexIterator,
 		const void* value, size_t size)
 	{
-		if (!indexIterator->index->Find(value, size, indexIterator))
+		if (!indexIterator->index->Find(value, size, *indexIterator))
 			return B_ENTRY_NOT_FOUND;
 
 		return B_OK;

From 7915349914fe5980f72f721a89c9b207257f6c85 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 8 Jul 2011 23:35:33 +0200
Subject: [PATCH 0266/1170] Remove unused IndexIterator constructor

---
 src/add-ons/kernel/file_systems/packagefs/Index.cpp | 9 ---------
 src/add-ons/kernel/file_systems/packagefs/Index.h   | 1 -
 2 files changed, 10 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Index.cpp b/src/add-ons/kernel/file_systems/packagefs/Index.cpp
index 6b0716a37c..8da53a4035 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Index.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Index.cpp
@@ -93,15 +93,6 @@ IndexIterator::IndexIterator()
 }
 
 
-IndexIterator::IndexIterator(Index* index)
-	:
-	fIterator(NULL)
-{
-	if (index)
-		index->GetIterator(this);
-}
-
-
 IndexIterator::~IndexIterator()
 {
 	SetIterator(NULL);
diff --git a/src/add-ons/kernel/file_systems/packagefs/Index.h b/src/add-ons/kernel/file_systems/packagefs/Index.h
index 008c8be33e..751eaeadf0 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Index.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Index.h
@@ -74,7 +74,6 @@ protected:
 class IndexIterator {
 public:
 								IndexIterator();
-								IndexIterator(Index* index);
 								~IndexIterator();
 
 			bool				HasNext() const;

From bf208087106a127859987f74c5cffc71bb49bba1 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 9 Jul 2011 00:11:06 +0200
Subject: [PATCH 0267/1170] Add set_dirent_name() without name length parameter

---
 src/add-ons/kernel/file_systems/packagefs/Utils.h          | 7 +++++++
 .../kernel/file_systems/packagefs/kernel_interface.cpp     | 2 +-
 2 files changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Utils.h b/src/add-ons/kernel/file_systems/packagefs/Utils.h
index 2a9359368e..4986c56211 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Utils.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Utils.h
@@ -41,6 +41,13 @@ set_dirent_name(struct dirent* buffer, size_t bufferSize, const char* name,
 }
 
 
+static inline bool
+set_dirent_name(struct dirent* buffer, size_t bufferSize, const char* name)
+{
+	return set_dirent_name(buffer, bufferSize, name, strlen(name));
+}
+
+
 static inline void
 get_real_time(timespec& time)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
index 3d2f2539a8..4f8a25244e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
@@ -621,7 +621,7 @@ packagefs_read_dir(fs_volume* fsVolume, fs_vnode* fsNode, void* _cookie,
 
 		// fill in the entry name -- checks whether the entry fits into the
 		// buffer
-		if (!set_dirent_name(buffer, bufferSize, name, strlen(name))) {
+		if (!set_dirent_name(buffer, bufferSize, name)) {
 			if (count == 0)
 				RETURN_ERROR(B_BUFFER_OVERFLOW);
 			break;

From 139bd32c025a1ae8396e5ef9ec0eca7dbb4c1e86 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 9 Jul 2011 00:12:10 +0200
Subject: [PATCH 0268/1170] Implement packagefs index (dir) hooks

---
 .../kernel/file_systems/packagefs/Volume.h    |  4 +
 .../packagefs/kernel_interface.cpp            | 96 +++++++++++++++----
 2 files changed, 84 insertions(+), 16 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index 532e4b9faa..6f68c5c6ad 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -26,6 +26,8 @@ class Directory;
 class PackageFSRoot;
 class UnpackingNode;
 
+typedef IndexHashTable::Iterator IndexDirIterator;
+
 
 enum MountType {
 	MOUNT_TYPE_SYSTEM,
@@ -83,6 +85,8 @@ public:
 
 			Index*				FindIndex(const char* name) const
 									{ return fIndices.Lookup(name); }
+			IndexDirIterator	GetIndexDirIterator() const
+									{ return fIndices.GetIterator(); }
 
 			// VFS wrappers
 			status_t			GetVNode(ino_t nodeID, Node*& _node);
diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
index 4f8a25244e..3be6d2d6de 100644
--- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
@@ -847,44 +847,93 @@ packagefs_read_attr_stat(fs_volume* fsVolume, fs_vnode* fsNode,
 
 // #pragma mark - index directory & index operations
 
+
+// NOTE: We don't do any locking in the index dir hooks, since once mounted
+// the index directory is immutable.
+
+
 status_t
 packagefs_open_index_dir(fs_volume* fsVolume, void** _cookie)
 {
-	// TODO:...
-	return B_NOT_SUPPORTED;
+	Volume* volume = (Volume*)fsVolume->private_volume;
+
+	FUNCTION("volume: %p\n", volume);
+
+	IndexDirIterator* iterator = new(std::nothrow) IndexDirIterator(
+		volume->GetIndexDirIterator());
+	if (iterator == NULL)
+		return B_NO_MEMORY;
+
+	*_cookie = iterator;
+	return B_OK;
 }
 
 
 status_t
 packagefs_close_index_dir(fs_volume* fsVolume, void* cookie)
 {
-	// TODO:...
-	return B_NOT_SUPPORTED;
+	return B_OK;
 }
 
 
 status_t
 packagefs_free_index_dir_cookie(fs_volume* fsVolume, void* cookie)
 {
-	// TODO:...
-	return B_NOT_SUPPORTED;
+	FUNCTION("volume: %p, cookie: %p\n", fsVolume->private_volume, cookie);
+
+	delete (IndexDirIterator*)cookie;
+	return B_OK;
 }
 
 
 status_t
-packagefs_read_index_dir(fs_volume* fsVolume, void* cookie, struct dirent* buffer,
-	size_t bufferSize, uint32* _num)
+packagefs_read_index_dir(fs_volume* fsVolume, void* cookie,
+	struct dirent* buffer, size_t bufferSize, uint32* _num)
 {
-	// TODO:...
-	return B_NOT_SUPPORTED;
+	Volume* volume = (Volume*)fsVolume->private_volume;
+
+	FUNCTION("volume: %p, cookie: %p, buffer: %p, bufferSize: %zu, num: %"
+		B_PRIu32 "\n", volume, cookie, buffer, bufferSize, *_num);
+
+	IndexDirIterator* iterator = (IndexDirIterator*)cookie;
+
+	if (*_num == 0)
+		return B_BAD_VALUE;
+
+	IndexDirIterator previousIterator = *iterator;
+
+	// get the next index
+	Index* index = iterator->Next();
+	if (index == NULL) {
+		*_num = 0;
+		return B_OK;
+	}
+
+	// fill in the entry
+	if (!set_dirent_name(buffer, bufferSize, index->Name())) {
+		*iterator = previousIterator;
+		return B_BUFFER_OVERFLOW;
+	}
+
+	buffer->d_dev = volume->ID();
+	buffer->d_ino = 0;
+
+	*_num = 1;
+	return B_OK;
 }
 
 
 status_t
 packagefs_rewind_index_dir(fs_volume* fsVolume, void* cookie)
 {
-	// TODO:...
-	return B_NOT_SUPPORTED;
+	Volume* volume = (Volume*)fsVolume->private_volume;
+
+	FUNCTION("volume: %p, cookie: %p\n", volume, cookie);
+
+	IndexDirIterator* iterator = (IndexDirIterator*)cookie;
+	*iterator = volume->GetIndexDirIterator();
+
+	return B_OK;
 }
 
 
@@ -892,7 +941,6 @@ status_t
 packagefs_create_index(fs_volume* fsVolume, const char* name, uint32 type,
 	uint32 flags)
 {
-	// TODO:...
 	return B_NOT_SUPPORTED;
 }
 
@@ -900,7 +948,6 @@ packagefs_create_index(fs_volume* fsVolume, const char* name, uint32 type,
 status_t
 packagefs_remove_index(fs_volume* fsVolume, const char* name)
 {
-	// TODO:...
 	return B_NOT_SUPPORTED;
 }
 
@@ -909,8 +956,25 @@ status_t
 packagefs_read_index_stat(fs_volume* fsVolume, const char* name,
 	struct stat* stat)
 {
-	// TODO:...
-	return B_NOT_SUPPORTED;
+	Volume* volume = (Volume*)fsVolume->private_volume;
+
+	FUNCTION("volume: %p, name: \"%s\", stat: %p\n", volume, name, stat);
+
+	Index* index = volume->FindIndex(name);
+	if (index == NULL)
+		return B_ENTRY_NOT_FOUND;
+
+	VolumeReadLocker volumeReadLocker(volume);
+
+	memset(stat, 0, sizeof(*stat));
+		// TODO: st_mtime, st_crtime, st_uid, st_gid are made available to
+		// userland, so we should make an attempt to fill in values that make
+		// sense.
+
+	stat->st_type = index->Type();
+	stat->st_size = index->CountEntries();
+
+	return B_OK;
 }
 
 

From 207a28efee1701840febf7bb71cfee559160641c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 9 Jul 2011 00:53:18 +0200
Subject: [PATCH 0269/1170] Declare packagefs persistent

Besides that it is kind of correct, it also makes tracker queries work
correctly.
---
 .../kernel/file_systems/packagefs/kernel_interface.cpp        | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
index 3be6d2d6de..35f5a24f9d 100644
--- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
@@ -138,8 +138,8 @@ packagefs_read_fs_info(fs_volume* fsVolume, struct fs_info* info)
 
 	FUNCTION("volume: %p, info: %p\n", volume, info);
 
-	info->flags = B_FS_IS_READONLY | B_FS_HAS_MIME | B_FS_HAS_ATTR
-		| B_FS_HAS_QUERY | B_FS_SUPPORTS_NODE_MONITORING;
+	info->flags = B_FS_IS_PERSISTENT | B_FS_IS_READONLY | B_FS_HAS_MIME
+		| B_FS_HAS_ATTR | B_FS_HAS_QUERY | B_FS_SUPPORTS_NODE_MONITORING;
 	info->block_size = 4096;
 	info->io_size = kOptimalIOSize;
 	info->total_blocks = info->free_blocks = 1;

From c98a59c6538ce5a7d0072d1bc563bf2d202a9a9d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 9 Jul 2011 00:56:18 +0200
Subject: [PATCH 0270/1170] Don't show packagefs on desktop or in disks window

More generally: Any volume that is mounted at a directory of a
persistent volume is not shown on the desktop or the disks window any
longer.
---
 src/kits/tracker/PoseView.cpp | 41 ++++++++++++++++++++---------------
 1 file changed, 24 insertions(+), 17 deletions(-)

diff --git a/src/kits/tracker/PoseView.cpp b/src/kits/tracker/PoseView.cpp
index b407c9544b..46caa8b5b0 100644
--- a/src/kits/tracker/PoseView.cpp
+++ b/src/kits/tracker/PoseView.cpp
@@ -1576,28 +1576,35 @@ BPoseView::CreateVolumePose(BVolume *volume, bool watchIndividually)
 	}
 
 	BDirectory root;
-	if (volume->GetRootDirectory(&root) == B_OK) {
-		node_ref itemNode;
-		root.GetNodeRef(&itemNode);
+	if (volume->GetRootDirectory(&root) != B_OK)
+		return;
 
-		BEntry entry;
-		root.GetEntry(&entry);
+	BEntry entry;
+	root.GetEntry(&entry);
 
-		entry_ref ref;
-		entry.GetRef(&ref);
+	entry_ref ref;
+	entry.GetRef(&ref);
 
-		node_ref dirNode;
-		dirNode.device = ref.device;
-		dirNode.node = ref.directory;
+	// If the volume is mounted at a directory of a persistent volume, we don't
+	// want it on the desktop or in the disks window.
+	BVolume parentVolume(ref.device);
+	if (parentVolume.InitCheck() == B_OK && parentVolume.IsPersistent())
+		return;
 
-		BPose *pose = EntryCreated(&dirNode, &itemNode, ref.name, 0);
+	node_ref itemNode;
+	root.GetNodeRef(&itemNode);
 
-		if (pose && watchIndividually) {
-			// make sure volume names still get watched, even though
-			// they are on the desktop which is not their physical parent
-			pose->TargetModel()->WatchVolumeAndMountPoint(B_WATCH_NAME | B_WATCH_STAT
-				| B_WATCH_ATTR, this);
-		}
+	node_ref dirNode;
+	dirNode.device = ref.device;
+	dirNode.node = ref.directory;
+
+	BPose *pose = EntryCreated(&dirNode, &itemNode, ref.name, 0);
+
+	if (pose && watchIndividually) {
+		// make sure volume names still get watched, even though
+		// they are on the desktop which is not their physical parent
+		pose->TargetModel()->WatchVolumeAndMountPoint(B_WATCH_NAME | B_WATCH_STAT
+			| B_WATCH_ATTR, this);
 	}
 }
 

From e94674ce75da4a1795cbe9ca098dee419fb2b3e9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 10 Jul 2011 14:32:02 +0200
Subject: [PATCH 0271/1170] cmake 2.8.5 optional package repackaged as hpkg

---
 build/jam/OptionalPackages | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 80dcf07356..bd73c6d9d1 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -429,9 +429,9 @@ if [ IsOptionalHaikuImagePackageAdded CMake ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				cmake-2.8.4-r1a3-x86-gcc2-2011-05-19.zip
-				: $(baseURL)/cmake-2.8.4-r1a3-x86-gcc2-2011-05-19.zip
-				: : true ;
+				cmake-2.8.5-1-gcc2_x86.hpkg
+				: $(hpkgBaseURL)/cmake-2.8.5-1-gcc2_x86.hpkg
+				: common packages ;
 		}
 	}
 }

From 70de928ed8a7bda307dd4aaf814991ce311f30ec Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 10 Jul 2011 14:58:39 +0200
Subject: [PATCH 0272/1170] Move  to headers/private/system

---
 headers/private/{libroot => system}/directories.h | 6 +++---
 src/system/kernel/fs/vfs_boot.cpp                 | 2 +-
 2 files changed, 4 insertions(+), 4 deletions(-)
 rename headers/private/{libroot => system}/directories.h (96%)

diff --git a/headers/private/libroot/directories.h b/headers/private/system/directories.h
similarity index 96%
rename from headers/private/libroot/directories.h
rename to headers/private/system/directories.h
index e01504bb85..c2ff80a984 100644
--- a/headers/private/libroot/directories.h
+++ b/headers/private/system/directories.h
@@ -2,8 +2,8 @@
  * Copyright 2011, Oliver Tappe 
  * Distributed under the terms of the MIT License.
  */
-#ifndef _LIBROOT_DIRECTORIES_H
-#define _LIBROOT_DIRECTORIES_H
+#ifndef _SYSTEM_DIRECTORIES_H
+#define _SYSTEM_DIRECTORIES_H
 
 
 #define kGlobalBinDirectory 			"/bin"
@@ -65,4 +65,4 @@
 #define kUserNonpackagedLibDirectory 	"/boot/home/config/non-packaged/lib"
 
 
-#endif	// _LIBROOT_DIRECTORIES_H
+#endif	// _SYSTEM_DIRECTORIES_H
diff --git a/src/system/kernel/fs/vfs_boot.cpp b/src/system/kernel/fs/vfs_boot.cpp
index f7657ab45d..eeddab0675 100644
--- a/src/system/kernel/fs/vfs_boot.cpp
+++ b/src/system/kernel/fs/vfs_boot.cpp
@@ -12,11 +12,11 @@
 
 #include 
 
-#include 
 #include 
 #include 
 
 #include 
+#include 
 #include 
 #include 
 #include 

From e96cbb12b42bf1511d39b5f2fb41c722aeefa937 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 12:21:00 +0200
Subject: [PATCH 0273/1170] Update cmake package, create doxygen package

---
 build/jam/OptionalPackages | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index bd73c6d9d1..729798d00c 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -429,8 +429,8 @@ if [ IsOptionalHaikuImagePackageAdded CMake ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				cmake-2.8.5-1-gcc2_x86.hpkg
-				: $(hpkgBaseURL)/cmake-2.8.5-1-gcc2_x86.hpkg
+				cmake-2.8.5-2-gcc2_x86.hpkg
+				: $(hpkgBaseURL)/cmake-2.8.5-2-gcc2_x86.hpkg
 				: common packages ;
 		}
 	}
@@ -629,9 +629,9 @@ if [ IsOptionalHaikuImagePackageAdded Doxygen ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				doxygen-1.6.3-x86-gcc2-2010-05-17.zip
-				: $(baseURL)/doxygen-1.6.3-x86-gcc2-2010-05-17.zip
-				: : true ;
+				doxygen-1.6.3-1-gcc2_x86.hpkg
+				: $(hpkgBaseURL)/doxygen-1.6.3-1-gcc2_x86.hpkg
+				: common packages ;
 		}
 	}
 }

From 3773b4751472f62d68a29116ac9c1508ef7b2a63 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 12:24:52 +0200
Subject: [PATCH 0274/1170] Tracker: Sort volumes like folders

Volumes no longer have a higher sorting priority than folders when "sort
folders first" is enabled.
---
 src/kits/tracker/Model.cpp | 14 ++++++--------
 1 file changed, 6 insertions(+), 8 deletions(-)

diff --git a/src/kits/tracker/Model.cpp b/src/kits/tracker/Model.cpp
index 115381b977..f8b735b57f 100644
--- a/src/kits/tracker/Model.cpp
+++ b/src/kits/tracker/Model.cpp
@@ -320,16 +320,14 @@ Model::CompareFolderNamesFirst(const Model *compareModel) const
 	const Model *resolvedCompareModel = compareModel->ResolveIfLink();
 	const Model *resolvedMe = ResolveIfLink();
 
-	if (resolvedMe->IsVolume()) {
-		if (!resolvedCompareModel->IsVolume())
-			return -1;
-	} else if (resolvedCompareModel->IsVolume())
-		return 1;
+	bool meIsDirOrVolume = resolvedMe->IsDirectory() || resolvedMe->IsVolume();
+	bool otherIsDirOrVolume = resolvedCompareModel->IsDirectory()
+		|| resolvedCompareModel->IsVolume();
 
-	if (resolvedMe->IsDirectory()) {
-		if (!resolvedCompareModel->IsDirectory())
+	if (meIsDirOrVolume) {
+		if (!otherIsDirOrVolume)
 			return -1;
-	} else if (resolvedCompareModel->IsDirectory())
+	} else if (otherIsDirOrVolume)
 		return 1;
 
 	return NaturalCompare(Name(), compareModel->Name());

From 407c09e2d9f356e5a69b40091c0c64c088ec7606 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 12:29:40 +0200
Subject: [PATCH 0275/1170] Create /packages symlink on boot

Rename the package links directory from /package-links to just /packages
and create it when booting.
---
 headers/private/system/directories.h |  3 ++-
 src/system/kernel/fs/vfs_boot.cpp    | 11 ++++++-----
 2 files changed, 8 insertions(+), 6 deletions(-)

diff --git a/headers/private/system/directories.h b/headers/private/system/directories.h
index c2ff80a984..c8c070ef50 100644
--- a/headers/private/system/directories.h
+++ b/headers/private/system/directories.h
@@ -8,7 +8,7 @@
 
 #define kGlobalBinDirectory 			"/bin"
 #define kGlobalEtcDirectory 			"/etc"
-#define kGlobalPackageLinksDirectory	"/package-links"
+#define kGlobalPackageLinksDirectory	"/packages"
 #define kGlobalSystemDirectory 			"/system"
 #define kGlobalTempDirectory 			"/tmp"
 #define kGlobalVarDirectory 			"/var"
@@ -35,6 +35,7 @@
 #define kSystemDevelopDirectory 		"/boot/system/develop"
 #define kSystemLibDirectory 			"/boot/system/lib"
 #define kSystemPackagesDirectory 		"/boot/system/packages"
+#define kSystemPackageLinksDirectory 		"/boot/system/package-links"
 #define kSystemPreferencesDirectory 	"/boot/system/preferences"
 #define kSystemServersDirectory 		"/boot/system/servers"
 
diff --git a/src/system/kernel/fs/vfs_boot.cpp b/src/system/kernel/fs/vfs_boot.cpp
index eeddab0675..22d7e4cf12 100644
--- a/src/system/kernel/fs/vfs_boot.cpp
+++ b/src/system/kernel/fs/vfs_boot.cpp
@@ -46,11 +46,12 @@ static struct {
 	const char *path;
 	const char *target;
 } sPredefinedLinks[] = {
-	{ kGlobalSystemDirectory,	kSystemDirectory },
-	{ kGlobalBinDirectory,		kSystemBinDirectory },
-	{ kGlobalEtcDirectory,		kCommonEtcDirectory },
-	{ kGlobalTempDirectory,		kCommonTempDirectory },
-	{ kGlobalVarDirectory,		kCommonVarDirectory },
+	{ kGlobalSystemDirectory,		kSystemDirectory },
+	{ kGlobalBinDirectory,			kSystemBinDirectory },
+	{ kGlobalEtcDirectory,			kCommonEtcDirectory },
+	{ kGlobalTempDirectory,			kCommonTempDirectory },
+	{ kGlobalVarDirectory,			kCommonVarDirectory },
+	{ kGlobalPackageLinksDirectory,	kSystemPackageLinksDirectory },
 	{NULL}
 };
 

From a0f63477842603c41892e788d432adda6cb92a0d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 13:50:05 +0200
Subject: [PATCH 0276/1170] Fix location of the Deskbar menu symlinks

---
 build/jam/OptionalPackages | 36 ++++++++++++++++++------------------
 1 file changed, 18 insertions(+), 18 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 729798d00c..b8687a1177 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -147,7 +147,7 @@ if [ IsOptionalHaikuImagePackageAdded ArmyKnife ] {
 		InstallOptionalHaikuImagePackage
 			armyknife-63-r1a3-x86-gcc2-2011-06-04.zip
 			: $(baseURL)/armyknife-63-r1a3-x86-gcc2-2011-06-04.zip ;
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/ArmyKnife/ArmyKnife ;
 	}
 }
@@ -181,7 +181,7 @@ if [ IsOptionalHaikuImagePackageAdded BeAE ] {
 				beae-22-r1a3-x86-gcc2-2011-05-18.zip
 				: $(baseURL)/beae-22-r1a3-x86-gcc2-2011-05-18.zip ;
 		}
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/BeAE/BeAE ;
 	}
 }
@@ -196,7 +196,7 @@ if [ IsOptionalHaikuImagePackageAdded Beam ] {
 	} else {
 		InstallOptionalHaikuImagePackage Beam-1.2alpha-x86-gcc2-2010-04-29.zip
 			: $(baseURL)/Beam-1.2alpha-x86-gcc2-2010-04-29.zip ;
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/Beam/Beam ;
 	}
 }
@@ -258,7 +258,7 @@ if [ IsOptionalHaikuImagePackageAdded BePDF ] {
 			bepdf-1.1.1b4-1-x86_gcc2.hpkg
 			: $(hpkgBaseURL)/bepdf-1.1.1b4-1-x86_gcc2.hpkg
 			: common packages ;
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/BePDF/BePDF ;
 	}
 }
@@ -278,7 +278,7 @@ if [ IsOptionalHaikuImagePackageAdded BeZillaBrowser ] {
 				BeZillaBrowser-2.0.0.22pre-r1a2-x86-gcc2-2010-05-02.zip
 				: $(baseURL)/BeZillaBrowser-2.0.0.22pre-r1a2-x86-gcc2-2010-05-02.zip ;
  		}
- 		AddSymlinkToHaikuImage home config be Applications
+ 		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/BeZillaBrowser/BeZillaBrowser ;
 		InstallSourceArchive BeZillaBrowser-2.0.0.22pre-r1a2-sources.tar.xz
 			: $(baseSourceURL)/2010/BeZillaBrowser-2.0.0.22pre-r1a2-sources.tar.xz ;
@@ -299,7 +299,7 @@ if [ IsOptionalHaikuImagePackageAdded Bluetooth ] {
 	AddFilesToHaikuImage system preferences : Bluetooth ;
 	AddFilesToHaikuImage system bin
 		: bt_dev_info bt_discovery ;
-	AddSymlinkToHaikuImage home config be Preferences
+	AddSymlinkToHaikuImage home config settings deskbar Preferences
 		: /boot/system/preferences/Bluetooth ;
 	if [ IsOptionalHaikuImagePackageAdded DevelopmentMin ]
 		&& $(HAIKU_GCC_VERSION[1]) in 2 4 {
@@ -325,7 +325,7 @@ if [ IsOptionalHaikuImagePackageAdded BurnItNow ] {
 			burnitnow-39-r1a3-x86-gcc2-2011-05-18.zip
 			: $(baseURL)/burnitnow-39-r1a3-x86-gcc2-2011-05-18.zip ;
 		}
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/BurnItNow/BurnItNow ;
 	}
 }
@@ -396,7 +396,7 @@ if [ IsOptionalHaikuImagePackageAdded Clockwerk ] {
 				Clockwerk-0.0.2-x86-gcc2-2010-10-13-1.zip
 				: $(baseURL)/Clockwerk-0.0.2-x86-gcc2-2010-10-13-1.zip ;
 		}
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/Clockwerk/Clockwerk ;
 	}
 }
@@ -691,7 +691,7 @@ if [ IsOptionalHaikuImagePackageAdded friss ] {
 				friss-24-r1a3-x86-gcc2-2011-05-31.zip
 				: $(baseURL)/friss-24-r1a3-x86-gcc2-2011-05-31.zip ;
 		}
-#		AddSymlinkToHaikuImage home config be Desktop\ applets
+#		AddSymlinkToHaikuImage home config settings deskbar Desktop\ applets
 #			: /boot/apps/FRiSS/FRiSS ;
 	}
 }
@@ -830,7 +830,7 @@ if [ IsOptionalHaikuImagePackageAdded KeymapSwitcher ] {
 				KeymapSwitcher-1.2.6-r1a3-x86-gcc2-2011-06-12.zip
 				: $(baseURL)/KeymapSwitcher-1.2.6-r1a3-x86-gcc2-2011-06-12.zip ;
 		}
-		AddSymlinkToHaikuImage home config be Preferences
+		AddSymlinkToHaikuImage home config settings deskbar Preferences
 			: /boot/common/bin/KeymapSwitcher ;
 	}
 }
@@ -949,7 +949,7 @@ if [ IsOptionalHaikuImagePackageAdded Links ] {
 	} else {
 		InstallOptionalHaikuImagePackage Links.zip
 			: $(baseURL)/links-x86-gcc2-2008-05-03.zip ;
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/home/config/bin/links ;
 	}
 }
@@ -1096,7 +1096,7 @@ if [ IsOptionalHaikuImagePackageAdded NetSurf ] {
 		InstallOptionalHaikuImagePackage
 			netsurf-2.7-r1a3-x86-gcc2-2011-06-04.zip
 			: $(baseURL)/netsurf-2.7-r1a3-x86-gcc2-2011-06-04.zip ;
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/NetSurf/NetSurf ;
 	}
 }
@@ -1214,7 +1214,7 @@ if [ IsOptionalHaikuImagePackageAdded Paladin ] {
 				: $(baseURL)/paladin-1.3-r1a3-x86-gcc2-2011-05-18.zip ;
 		}
 
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/Paladin/Paladin ;
 		AddSymlinkToHaikuImage common bin
 			: /boot/apps/Paladin/Paladin ;
@@ -1256,7 +1256,7 @@ if [ IsOptionalHaikuImagePackageAdded Pe ] {
 				: $(hpkgBaseURL)/pe-2.4.3_600-1-x86_gcc2.hpkg
 				: common packages ;
 		}
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/Pe/Pe ;
 	}
 }
@@ -1532,7 +1532,7 @@ if [ IsOptionalHaikuImagePackageAdded Vim ] {
 				:  $(baseURL)/vim-7.3-r1a3-x86-gcc2-2011-05-26.zip
 				: : true ;
 		}
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/common/bin/gvim ;
 		# TODO: move this symlink to the archive
 		AddSymlinkToHaikuImage common bin : vim : vi ;
@@ -1554,7 +1554,7 @@ if [ IsOptionalHaikuImagePackageAdded Vision ] {
 				: $(hpkgBaseURL)/vision-908-1-x86_gcc2.hpkg
 				: common packages ;
 		}
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/Vision/Vision ;
 	}
 }
@@ -1570,7 +1570,7 @@ if [ IsOptionalHaikuImagePackageAdded WebPositive ] {
 		InstallOptionalHaikuImagePackage
 			WebPositive-r1a3-gcc4-x86-r580-2011-06-02.zip
 			: $(baseURL)/WebPositive-r1a3-gcc4-x86-r580-2011-06-02.zip ;
-		AddSymlinkToHaikuImage home config be Applications
+		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/WebPositive/WebPositive ;
 	}
 }
@@ -1652,7 +1652,7 @@ if [ IsOptionalHaikuImagePackageAdded WonderBrush ] {
 #		InstallOptionalHaikuImagePackage WonderBrush-2.1.2.zip
 #			: $(baseURL)/WonderBrush-2.1.2-x86-gcc2-2008-11-08.zip
 #			: common apps ;
-#		AddSymlinkToHaikuImage home config be Applications
+#		AddSymlinkToHaikuImage home config settings deskbar Applications
 #			: /boot/apps/WonderBrush/WonderBrush ;
 	}
 }

From e6067d0cf4bd9f945aaf276e0d417c18340ef53e Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 13:51:07 +0200
Subject: [PATCH 0277/1170] Change Haiku package name to lower case

---
 src/data/package_infos/haiku | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku
index 0398f10f66..a5f3aef467 100644
--- a/src/data/package_infos/haiku
+++ b/src/data/package_infos/haiku
@@ -1,4 +1,4 @@
-name 			Haiku
+name 			haiku
 version			R1-alpha3_pm-1
 architecture	x86_gcc2
 summary			"The Haiku base system"

From d7227dfa9e644112f7019d94b4611da400c6c884 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 13:55:35 +0200
Subject: [PATCH 0278/1170] BPackageWriter: Add SetCheckLicenses()

The default is still "true", but now it is possible to disable the
license check.
---
 headers/os/package/hpkg/PackageWriter.h        |  1 +
 .../private/package/hpkg/PackageWriterImpl.h   |  2 ++
 src/kits/package/hpkg/PackageWriter.cpp        |  8 ++++++++
 src/kits/package/hpkg/PackageWriterImpl.cpp    | 18 ++++++++++++++----
 4 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/headers/os/package/hpkg/PackageWriter.h b/headers/os/package/hpkg/PackageWriter.h
index 92e3ce1b55..6b3a9be5fc 100644
--- a/headers/os/package/hpkg/PackageWriter.h
+++ b/headers/os/package/hpkg/PackageWriter.h
@@ -48,6 +48,7 @@ public:
 								~BPackageWriter();
 
 			status_t			Init(const char* fileName, uint32 flags = 0);
+			void				SetCheckLicenses(bool checkLicenses);
 			status_t			AddEntry(const char* fileName, int fd = -1);
 			status_t			Finish();
 
diff --git a/headers/private/package/hpkg/PackageWriterImpl.h b/headers/private/package/hpkg/PackageWriterImpl.h
index 298a159121..2a24b6638c 100644
--- a/headers/private/package/hpkg/PackageWriterImpl.h
+++ b/headers/private/package/hpkg/PackageWriterImpl.h
@@ -43,6 +43,7 @@ public:
 								~PackageWriterImpl();
 
 			status_t			Init(const char* fileName, uint32 flags);
+			void				SetCheckLicenses(bool checkLicenses);
 			status_t			AddEntry(const char* fileName, int fd = -1);
 			status_t			Finish();
 
@@ -147,6 +148,7 @@ private:
 			StringCache			fStringCache;
 
 			BPackageInfo		fPackageInfo;
+			bool				fCheckLicenses;
 };
 
 
diff --git a/src/kits/package/hpkg/PackageWriter.cpp b/src/kits/package/hpkg/PackageWriter.cpp
index 67304d0dcc..dd548087ac 100644
--- a/src/kits/package/hpkg/PackageWriter.cpp
+++ b/src/kits/package/hpkg/PackageWriter.cpp
@@ -39,6 +39,14 @@ BPackageWriter::Init(const char* fileName, uint32 flags)
 }
 
 
+void
+BPackageWriter::SetCheckLicenses(bool checkLicenses)
+{
+	if (fImpl != NULL)
+		fImpl->SetCheckLicenses(checkLicenses);
+}
+
+
 status_t
 BPackageWriter::AddEntry(const char* fileName, int fd)
 {
diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 7ce51700a8..db8a9b7ce8 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -455,7 +455,8 @@ PackageWriterImpl::PackageWriterImpl(BPackageWriterListener* listener)
 	fDataBufferSize(2 * B_HPKG_DEFAULT_DATA_CHUNK_SIZE_ZLIB),
 	fRootEntry(NULL),
 	fRootAttribute(NULL),
-	fTopAttribute(NULL)
+	fTopAttribute(NULL),
+	fCheckLicenses(true)
 {
 }
 
@@ -484,6 +485,13 @@ PackageWriterImpl::Init(const char* fileName, uint32 flags)
 }
 
 
+void
+PackageWriterImpl::SetCheckLicenses(bool checkLicenses)
+{
+	fCheckLicenses = checkLicenses;
+}
+
+
 status_t
 PackageWriterImpl::AddEntry(const char* fileName, int fd)
 {
@@ -569,9 +577,11 @@ PackageWriterImpl::Finish()
 
 		RegisterPackageInfo(PackageAttributes(), fPackageInfo);
 
-		status_t result = _CheckLicenses();
-		if (result != B_OK)
-			return result;
+		if (fCheckLicenses) {
+			status_t result = _CheckLicenses();
+			if (result != B_OK)
+				return result;
+		}
 
 		if ((Flags() & B_HPKG_WRITER_UPDATE_PACKAGE) != 0)
 			_CompactHeap();

From f19957b8e5311ffc5b802032e4f24cdda81f9b50 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 14:00:55 +0200
Subject: [PATCH 0279/1170] Add a package info "install-path" attribute

The attribute is intended for simplifying package building. The
package's install path will be used for the package's .self package
symlink, allowing installation to a temporary directory when building
the package.
---
 headers/os/package/PackageInfo.h               |  3 +++
 headers/os/package/PackageInfoAttributes.h     |  2 ++
 headers/os/package/hpkg/HPKGDefs.h             |  1 +
 headers/os/package/hpkg/PackageWriter.h        |  1 +
 .../private/package/hpkg/PackageWriterImpl.h   |  4 ++++
 src/bin/package/command_list.cpp               |  4 ++++
 src/kits/package/PackageInfo.cpp               | 18 +++++++++++++++++-
 .../package/hpkg/PackageContentHandler.cpp     |  1 +
 src/kits/package/hpkg/PackageWriter.cpp        | 10 ++++++++++
 src/kits/package/hpkg/PackageWriterImpl.cpp    | 12 ++++++++++++
 src/kits/package/hpkg/ReaderImplBase.cpp       |  4 ++++
 src/kits/package/hpkg/WriterImplBase.cpp       | 11 +++++++++++
 12 files changed, 70 insertions(+), 1 deletion(-)

diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h
index 6109a2efa5..e62136dd9d 100644
--- a/headers/os/package/PackageInfo.h
+++ b/headers/os/package/PackageInfo.h
@@ -60,6 +60,7 @@ public:
 			const BString&		Vendor() const;
 			const BString&		Packager() const;
 			const BString&		Checksum() const;
+			const BString&		InstallPath() const;
 
 			uint32				Flags() const;
 
@@ -89,6 +90,7 @@ public:
 			void				SetVendor(const BString& vendor);
 			void				SetPackager(const BString& packager);
 			void				SetChecksum(const BString& checksum);
+			void				SetInstallPath(const BString& installPath);
 
 			void				SetFlags(uint32 flags);
 
@@ -174,6 +176,7 @@ private:
 			BObjectList	fReplacesList;
 
 			BString				fChecksum;
+			BString				fInstallPath;
 };
 
 
diff --git a/headers/os/package/PackageInfoAttributes.h b/headers/os/package/PackageInfoAttributes.h
index d03a21695a..f1b86018ae 100644
--- a/headers/os/package/PackageInfoAttributes.h
+++ b/headers/os/package/PackageInfoAttributes.h
@@ -37,6 +37,8 @@ enum BPackageInfoAttributeID {
 	B_PACKAGE_INFO_URLS,		// list
 	B_PACKAGE_INFO_SOURCE_URLS,	// list
 	B_PACKAGE_INFO_CHECKSUM,	// sha256-checksum
+	B_PACKAGE_INFO_INSTALL_PATH, // package install path; only for package
+								// building
 	//
 	B_PACKAGE_INFO_ENUM_COUNT,
 };
diff --git a/headers/os/package/hpkg/HPKGDefs.h b/headers/os/package/hpkg/HPKGDefs.h
index af83bf3cce..f4e812ef74 100644
--- a/headers/os/package/hpkg/HPKGDefs.h
+++ b/headers/os/package/hpkg/HPKGDefs.h
@@ -126,6 +126,7 @@ enum BHPKGAttributeID {
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES_COMPATIBLE	= 41,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_URL					= 42,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_SOURCE_URL			= 43,
+	B_HPKG_ATTRIBUTE_ID_PACKAGE_INSTALL_PATH		= 44,
 	//
 	B_HPKG_ATTRIBUTE_ID_ENUM_COUNT,
 };
diff --git a/headers/os/package/hpkg/PackageWriter.h b/headers/os/package/hpkg/PackageWriter.h
index 6b3a9be5fc..e3eb30d59b 100644
--- a/headers/os/package/hpkg/PackageWriter.h
+++ b/headers/os/package/hpkg/PackageWriter.h
@@ -48,6 +48,7 @@ public:
 								~BPackageWriter();
 
 			status_t			Init(const char* fileName, uint32 flags = 0);
+			status_t			SetInstallPath(const char* installPath);
 			void				SetCheckLicenses(bool checkLicenses);
 			status_t			AddEntry(const char* fileName, int fd = -1);
 			status_t			Finish();
diff --git a/headers/private/package/hpkg/PackageWriterImpl.h b/headers/private/package/hpkg/PackageWriterImpl.h
index 2a24b6638c..88febb119b 100644
--- a/headers/private/package/hpkg/PackageWriterImpl.h
+++ b/headers/private/package/hpkg/PackageWriterImpl.h
@@ -10,6 +10,8 @@
 #include 
 #include 
 
+#include 
+
 #include 
 #include 
 #include 
@@ -43,6 +45,7 @@ public:
 								~PackageWriterImpl();
 
 			status_t			Init(const char* fileName, uint32 flags);
+			status_t			SetInstallPath(const char* installPath);
 			void				SetCheckLicenses(bool checkLicenses);
 			status_t			AddEntry(const char* fileName, int fd = -1);
 			status_t			Finish();
@@ -148,6 +151,7 @@ private:
 			StringCache			fStringCache;
 
 			BPackageInfo		fPackageInfo;
+			BString				fInstallPath;
 			bool				fCheckLicenses;
 };
 
diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp
index efcf33685e..317cec68fd 100644
--- a/src/bin/package/command_list.cpp
+++ b/src/bin/package/command_list.cpp
@@ -230,6 +230,10 @@ struct PackageContentListHandler : BPackageContentHandler {
 				printf("\treplaces: %s\n", value.string);
 				break;
 
+			case B_PACKAGE_INFO_INSTALL_PATH:
+				printf("\tinstall path: %s\n", value.string);
+				break;
+
 			default:
 				printf(
 					"*** Invalid package attribute section: unexpected "
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index ee3376e7b8..0f3e3b22f6 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -670,7 +670,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 
 		BPackageInfoAttributeID attribute = B_PACKAGE_INFO_ENUM_COUNT;
 		for (int i = 0; i < B_PACKAGE_INFO_ENUM_COUNT; i++) {
-			if (t.text.ICompare(names[i]) == 0) {
+			if (names[i] != NULL && t.text.ICompare(names[i]) == 0) {
 				attribute = (BPackageInfoAttributeID)i;
 				break;
 			}
@@ -803,6 +803,7 @@ const char* BPackageInfo::kElementNames[B_PACKAGE_INFO_ENUM_COUNT] = {
 	"urls",
 	"source-urls",
 	"checksum",		// not being parsed, computed externally
+	NULL,			// install-path -- not settable via .PackageInfo
 };
 
 
@@ -948,6 +949,13 @@ BPackageInfo::Checksum() const
 }
 
 
+const BString&
+BPackageInfo::InstallPath() const
+{
+	return fInstallPath;
+}
+
+
 uint32
 BPackageInfo::Flags() const
 {
@@ -1081,6 +1089,13 @@ BPackageInfo::SetChecksum(const BString& checksum)
 }
 
 
+void
+BPackageInfo::SetInstallPath(const BString& installPath)
+{
+	fInstallPath = installPath;
+}
+
+
 void
 BPackageInfo::SetVersion(const BPackageVersion& version)
 {
@@ -1296,6 +1311,7 @@ BPackageInfo::Clear()
 	fVendor.Truncate(0);
 	fPackager.Truncate(0);
 	fChecksum.Truncate(0);
+	fInstallPath.Truncate(0);
 	fFlags = 0;
 	fArchitecture = B_PACKAGE_ARCHITECTURE_ENUM_COUNT;
 	fVersion.Clear();
diff --git a/src/kits/package/hpkg/PackageContentHandler.cpp b/src/kits/package/hpkg/PackageContentHandler.cpp
index 9d344e715c..418e84bf5d 100644
--- a/src/kits/package/hpkg/PackageContentHandler.cpp
+++ b/src/kits/package/hpkg/PackageContentHandler.cpp
@@ -60,6 +60,7 @@ static const char* kAttributeNames[B_HPKG_ATTRIBUTE_ID_ENUM_COUNT + 1] = {
 	"package:provides.compatible",
 	"package:url",
 	"package:source-url",
+	"package:install-path",
 	NULL
 };
 
diff --git a/src/kits/package/hpkg/PackageWriter.cpp b/src/kits/package/hpkg/PackageWriter.cpp
index dd548087ac..3fcbec8e42 100644
--- a/src/kits/package/hpkg/PackageWriter.cpp
+++ b/src/kits/package/hpkg/PackageWriter.cpp
@@ -39,6 +39,16 @@ BPackageWriter::Init(const char* fileName, uint32 flags)
 }
 
 
+status_t
+BPackageWriter::SetInstallPath(const char* installPath)
+{
+	if (fImpl == NULL)
+		return B_NO_INIT;
+
+	return fImpl->SetInstallPath(installPath);
+}
+
+
 void
 BPackageWriter::SetCheckLicenses(bool checkLicenses)
 {
diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index db8a9b7ce8..06710867a3 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -485,6 +485,16 @@ PackageWriterImpl::Init(const char* fileName, uint32 flags)
 }
 
 
+status_t
+PackageWriterImpl::SetInstallPath(const char* installPath)
+{
+	fInstallPath = installPath;
+	return installPath == NULL
+		|| (size_t)fInstallPath.Length() == strlen(installPath)
+		? B_OK : B_NO_MEMORY;
+}
+
+
 void
 PackageWriterImpl::SetCheckLicenses(bool checkLicenses)
 {
@@ -575,6 +585,8 @@ PackageWriterImpl::Finish()
 			return B_BAD_DATA;
 		}
 
+		fPackageInfo.SetInstallPath(fInstallPath);
+
 		RegisterPackageInfo(PackageAttributes(), fPackageInfo);
 
 		if (fCheckLicenses) {
diff --git a/src/kits/package/hpkg/ReaderImplBase.cpp b/src/kits/package/hpkg/ReaderImplBase.cpp
index 727991d764..7f2c3fd94d 100644
--- a/src/kits/package/hpkg/ReaderImplBase.cpp
+++ b/src/kits/package/hpkg/ReaderImplBase.cpp
@@ -441,6 +441,10 @@ ReaderImplBase::PackageAttributeHandler::HandleAttribute(
 			fPackageInfoValue.SetTo(B_PACKAGE_INFO_CHECKSUM, value.string);
 			break;
 
+		case B_HPKG_ATTRIBUTE_ID_PACKAGE_INSTALL_PATH:
+			fPackageInfoValue.SetTo(B_PACKAGE_INFO_INSTALL_PATH, value.string);
+			break;
+
 		default:
 			context->errorOutput->PrintError(
 				"Error: Invalid package attribute section: unexpected "
diff --git a/src/kits/package/hpkg/WriterImplBase.cpp b/src/kits/package/hpkg/WriterImplBase.cpp
index 74224ff23a..e308190f8c 100644
--- a/src/kits/package/hpkg/WriterImplBase.cpp
+++ b/src/kits/package/hpkg/WriterImplBase.cpp
@@ -527,6 +527,17 @@ WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList,
 			= fPackageStringCache.Get(packageInfo.Checksum().String());
 		attributeList.Add(checksum);
 	}
+
+	// install path (optional)
+	if (!packageInfo.InstallPath().IsEmpty()) {
+		PackageAttribute* installPath = new PackageAttribute(
+			B_HPKG_ATTRIBUTE_ID_PACKAGE_INSTALL_PATH,
+			B_HPKG_ATTRIBUTE_TYPE_STRING,
+			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
+		installPath->string = fPackageStringCache.Get(
+			packageInfo.InstallPath().String());
+		attributeList.Add(installPath);
+	}
 }
 
 

From 6f0f81ef9b73e662fb4cb70c3cc6dcff52fe2bf5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 14:02:37 +0200
Subject: [PATCH 0280/1170] Add options -b and -I to package command

* With -b building a build package can be requested. It will be empty
  save for the .PackageInfo. No license check is performed.
* -I allows to specify an install path.
---
 src/bin/package/command_create.cpp | 43 +++++++++++++++++++++++++++---
 src/bin/package/package.cpp        |  9 +++++++
 2 files changed, 49 insertions(+), 3 deletions(-)

diff --git a/src/bin/package/command_create.cpp b/src/bin/package/command_create.cpp
index c575a7964a..1062185b5a 100644
--- a/src/bin/package/command_create.cpp
+++ b/src/bin/package/command_create.cpp
@@ -34,6 +34,8 @@ command_create(int argc, const char* const* argv)
 {
 	const char* changeToDirectory = NULL;
 	const char* packageInfoFileName = NULL;
+	const char* installPath = NULL;
+	bool isBuildPackage = false;
 	bool quiet = false;
 	bool verbose = false;
 
@@ -46,11 +48,16 @@ command_create(int argc, const char* const* argv)
 		};
 
 		opterr = 0; // don't print errors
-		int c = getopt_long(argc, (char**)argv, "+C:hi:qv", sLongOptions, NULL);
+		int c = getopt_long(argc, (char**)argv, "+bC:hi:I:qv", sLongOptions,
+			NULL);
 		if (c == -1)
 			break;
 
 		switch (c) {
+			case 'b':
+				isBuildPackage = true;
+				break;
+
 			case 'C':
 				changeToDirectory = optarg;
 				break;
@@ -63,6 +70,10 @@ command_create(int argc, const char* const* argv)
 				packageInfoFileName = optarg;
 				break;
 
+			case 'I':
+				installPath = optarg;
+				break;
+
 			case 'q':
 				quiet = true;
 				break;
@@ -83,6 +94,13 @@ command_create(int argc, const char* const* argv)
 
 	const char* packageFileName = argv[optind++];
 
+	// -I is only allowed when -b is given
+	if (installPath != NULL && !isBuildPackage) {
+		fprintf(stderr, "Error: \"-I\" is only allowed when \"-b\" is "
+			"given.\n");
+		return 1;
+	}
+
 	// create package
 	PackageWriterListener listener(verbose, quiet);
 	BPackageWriter packageWriter(&listener);
@@ -97,6 +115,7 @@ command_create(int argc, const char* const* argv)
 		if (packageInfoFD < 0) {
 			fprintf(stderr, "Error: Failed to open package info file \"%s\": "
 				"%s\n", packageInfoFileName, strerror(errno));
+			return 1;
 		}
 	}
 
@@ -106,12 +125,30 @@ command_create(int argc, const char* const* argv)
 			listener.PrintError(
 				"Error: Failed to change the current working directory to "
 				"\"%s\": %s\n", changeToDirectory, strerror(errno));
+			return 1;
+		}
+	}
+
+	if (isBuildPackage)
+		packageWriter.SetCheckLicenses(false);
+
+	// set install path, if specified
+	if (installPath != NULL) {
+		result = packageWriter.SetInstallPath(installPath);
+		if (result != B_OK) {
+			fprintf(stderr, "Error: Failed to set the package install path: "
+				"%s\n", strerror(result));
+			return 1;
 		}
 	}
 
 	// add all files of the current directory, save for the .PackageInfo
-	if (add_current_directory_entries(packageWriter, listener, true) != B_OK)
-		return 1;
+	if (!isBuildPackage) {
+		if (add_current_directory_entries(packageWriter, listener, true)
+				!= B_OK) {
+			return 1;
+		}
+	}
 
 	// add the .PackageInfo
 	result = packageWriter.AddEntry(B_HPKG_PACKAGE_INFO_FILE_NAME,
diff --git a/src/bin/package/package.cpp b/src/bin/package/package.cpp
index 93797fd656..ea0c1c15c3 100644
--- a/src/bin/package/package.cpp
+++ b/src/bin/package/package.cpp
@@ -41,10 +41,19 @@ static const char* kUsage =
 	"  create [  ] \n"
 	"    Creates package file  from contents of current directory.\n"
 	"\n"
+	"    -b         - Create an empty build package. Only the .PackageInfo "
+		"will\n"
+	"                 be added.\n"
 	"    -C    - Change to directory  before adding entries.\n"
 	"    -i   - Use the package info file . It will be added as\n"
 	"                 \".PackageInfo\", overriding a \".PackageInfo\" file,\n"
 	"                 existing.\n"
+	"    -I   - Set the package's installation path to . This is\n"
+	"                 an option only for use in package building. It will "
+		"cause\n"
+	"                 the package .self link to point to , which is "
+		"useful\n"
+	"                 to redirect a \"make install\". Only allowed with -b.\n"
 	"    -q         - Be quiet (don't show any output except for errors).\n"
 	"    -v         - Be verbose (show more info about created package).\n"
 	"\n"

From 48a8980c43ecf127e6a87e92261671b2a4820176 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 14:03:15 +0200
Subject: [PATCH 0281/1170] Add install path support to packagefs

---
 .../kernel/file_systems/packagefs/Package.cpp    | 16 ++++++++++++++++
 .../kernel/file_systems/packagefs/Package.h      |  4 ++++
 .../packagefs/PackageLinkSymlink.cpp             |  7 +++++--
 .../kernel/file_systems/packagefs/Volume.cpp     |  3 +++
 4 files changed, 28 insertions(+), 2 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.cpp b/src/add-ons/kernel/file_systems/packagefs/Package.cpp
index 9e4b43bb1f..c5a21e8c96 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Package.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Package.cpp
@@ -31,6 +31,7 @@ Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID)
 	fDomain(domain),
 	fFileName(NULL),
 	fName(NULL),
+	fInstallPath(NULL),
 	fVersion(NULL),
 	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
 	fLinkDirectory(NULL),
@@ -56,6 +57,7 @@ Package::~Package()
 
 	free(fFileName);
 	free(fName);
+	free(fInstallPath);
 	delete fVersion;
 
 	mutex_destroy(&fLock);
@@ -87,6 +89,20 @@ Package::SetName(const char* name)
 }
 
 
+status_t
+Package::SetInstallPath(const char* installPath)
+{
+	if (fInstallPath != NULL)
+		free(fInstallPath);
+
+	fInstallPath = strdup(installPath);
+	if (fInstallPath == NULL)
+		RETURN_ERROR(B_NO_MEMORY);
+
+	return B_OK;
+}
+
+
 void
 Package::SetVersion(::Version* version)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.h b/src/add-ons/kernel/file_systems/packagefs/Package.h
index ff7a6522b0..2cf5cec1d2 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Package.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Package.h
@@ -44,6 +44,9 @@ public:
 			status_t			SetName(const char* name);
 			const char*			Name() const		{ return fName; }
 
+			status_t			SetInstallPath(const char* installPath);
+			const char*			InstallPath() const	{ return fInstallPath; }
+
 			void				SetVersion(::Version* version);
 									// takes over object ownership
 			::Version*			Version() const
@@ -83,6 +86,7 @@ private:
 			PackageDomain*		fDomain;
 			char*				fFileName;
 			char*				fName;
+			char*				fInstallPath;
 			::Version*			fVersion;
 			BPackageArchitecture fArchitecture;
 			PackageLinkDirectory* fLinkDirectory;
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
index 562200e123..877b0824b7 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
@@ -92,8 +92,11 @@ PackageLinkSymlink::Update(Package* package, PackageLinksListener* listener)
 	OldAttributes oldAttributes(fModifiedTime, FileSize());
 
 	if (package != NULL) {
-		fLinkPath = link_path_for_mount_type(
-			package->Domain()->Volume()->MountType());
+		fLinkPath = package->InstallPath();
+		if (fLinkPath == NULL) {
+			fLinkPath = link_path_for_mount_type(
+				package->Domain()->Volume()->MountType());
+		}
 	} else
 		fLinkPath = kUnknownLinkTarget;
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index b8d2154b61..3304741cc4 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -291,6 +291,9 @@ struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
 			case B_PACKAGE_INFO_NAME:
 				return fPackage->SetName(value.string);
 
+			case B_PACKAGE_INFO_INSTALL_PATH:
+				return fPackage->SetInstallPath(value.string);
+
 			case B_PACKAGE_INFO_VERSION:
 			{
 				Version* version;

From 437651ffccae7aea235b5d9bb34d63071609e625 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 14:24:50 +0200
Subject: [PATCH 0282/1170] Force package names and versions to lower case

---
 src/kits/package/PackageInfo.cpp              | 30 ++++++++++++++-----
 src/kits/package/PackageResolvable.cpp        |  3 ++
 .../package/PackageResolvableExpression.cpp   |  4 +++
 src/kits/package/PackageVersion.cpp           | 19 +++++-------
 4 files changed, 36 insertions(+), 20 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 0f3e3b22f6..024a411fd8 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -82,7 +82,8 @@ private:
 			void				_ParseList(ListElementParser& elementParser,
 									bool allowSingleNonListElement);
 			void				_ParseStringList(BObjectList* value,
-									bool allowQuotedStrings = true);
+									bool allowQuotedStrings = true,
+									bool convertToLowerCase = false);
 			void				_ParseResolvableList(
 									BObjectList* value);
 			void				_ParseResolvableExprList(
@@ -449,16 +450,19 @@ BPackageInfo::Parser::_ParseList(ListElementParser& elementParser,
 
 void
 BPackageInfo::Parser::_ParseStringList(BObjectList* value,
-	bool allowQuotedStrings)
+	bool allowQuotedStrings, bool convertToLowerCase)
 {
 	struct StringParser : public ListElementParser {
 		BObjectList* value;
 		bool allowQuotedStrings;
+		bool convertToLowerCase;
 
-		StringParser(BObjectList* value, bool allowQuotedStrings)
+		StringParser(BObjectList* value, bool allowQuotedStrings,
+			bool convertToLowerCase)
 			:
 			value(value),
-			allowQuotedStrings(allowQuotedStrings)
+			allowQuotedStrings(allowQuotedStrings),
+			convertToLowerCase(convertToLowerCase)
 		{
 		}
 
@@ -475,9 +479,13 @@ BPackageInfo::Parser::_ParseStringList(BObjectList* value,
 					throw ParseError("expected word", token.pos);
 			}
 
-			value->AddItem(new BString(token.text));
+			BString* element = new BString(token.text);
+			if (convertToLowerCase)
+				element->ToLower();
+
+			value->AddItem(element);
 		}
-	} stringParser(value, allowQuotedStrings);
+	} stringParser(value, allowQuotedStrings, convertToLowerCase);
 
 	_ParseList(stringParser, true);
 }
@@ -688,8 +696,12 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 
 		switch (attribute) {
 			case B_PACKAGE_INFO_NAME:
-				_ParseStringValue(&packageInfo->fName);
+			{
+				BString name;
+				_ParseStringValue(&name);
+				packageInfo->SetName(name);
 				break;
+			}
 
 			case B_PACKAGE_INFO_SUMMARY:
 			{
@@ -758,7 +770,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				break;
 
 			case B_PACKAGE_INFO_REPLACES:
-				_ParseStringList(&packageInfo->fReplacesList, false);
+				_ParseStringList(&packageInfo->fReplacesList, false, true);
 				break;
 
 			case B_PACKAGE_INFO_FLAGS:
@@ -1051,6 +1063,7 @@ void
 BPackageInfo::SetName(const BString& name)
 {
 	fName = name;
+	fName.ToLower();
 }
 
 
@@ -1298,6 +1311,7 @@ BPackageInfo::AddReplaces(const BString& replaces)
 	if (newReplaces == NULL)
 		return B_NO_MEMORY;
 
+	newReplaces->ToLower();
 	return fReplacesList.AddItem(newReplaces) ? B_OK : B_ERROR;
 }
 
diff --git a/src/kits/package/PackageResolvable.cpp b/src/kits/package/PackageResolvable.cpp
index 3c1c632ffe..0c70c996ff 100644
--- a/src/kits/package/PackageResolvable.cpp
+++ b/src/kits/package/PackageResolvable.cpp
@@ -48,6 +48,7 @@ BPackageResolvable::BPackageResolvable(const BString& name,
 	fVersion(version),
 	fCompatibleVersion(compatibleVersion)
 {
+	fName.ToLower();
 }
 
 
@@ -110,6 +111,8 @@ BPackageResolvable::SetTo(const BString& name, BPackageResolvableType type,
 	fType = type;
 	fVersion = version;
 	fCompatibleVersion = compatibleVersion;
+
+	fName.ToLower();
 }
 
 
diff --git a/src/kits/package/PackageResolvableExpression.cpp b/src/kits/package/PackageResolvableExpression.cpp
index 3e79ca015f..430dda56cf 100644
--- a/src/kits/package/PackageResolvableExpression.cpp
+++ b/src/kits/package/PackageResolvableExpression.cpp
@@ -38,6 +38,7 @@ BPackageResolvableExpression::BPackageResolvableExpression(
 	fOperator(data.op),
 	fVersion(data.version)
 {
+	fName.ToLower();
 }
 
 
@@ -48,6 +49,7 @@ BPackageResolvableExpression::BPackageResolvableExpression(const BString& name,
 	fOperator(_operator),
 	fVersion(version)
 {
+	fName.ToLower();
 }
 
 
@@ -106,6 +108,8 @@ BPackageResolvableExpression::SetTo(const BString& name,
 	fName = name;
 	fOperator = _operator;
 	fVersion = version;
+
+	fName.ToLower();
 }
 
 
diff --git a/src/kits/package/PackageVersion.cpp b/src/kits/package/PackageVersion.cpp
index 2c1e53c2d6..a4d1dd23dd 100644
--- a/src/kits/package/PackageVersion.cpp
+++ b/src/kits/package/PackageVersion.cpp
@@ -25,25 +25,15 @@ BPackageVersion::BPackageVersion()
 
 
 BPackageVersion::BPackageVersion(const BPackageVersionData& data)
-	:
-	fMajor(data.major),
-	fMinor(data.minor),
-	fMicro(data.micro),
-	fPreRelease(data.preRelease),
-	fRelease(data.release)
 {
+	SetTo(data.major, data.minor, data.micro, data.preRelease, data.release);
 }
 
 
 BPackageVersion::BPackageVersion(const BString& major, const BString& minor,
 	const BString& micro, const BString& preRelease, uint8 release)
-	:
-	fMajor(major),
-	fMinor(minor),
-	fMicro(micro),
-	fPreRelease(preRelease),
-	fRelease(release)
 {
+	SetTo(major, minor, micro, preRelease, release);
 }
 
 
@@ -153,6 +143,11 @@ BPackageVersion::SetTo(const BString& major, const BString& minor,
 	fMicro = micro;
 	fPreRelease = preRelease;
 	fRelease = release;
+
+	fMajor.ToLower();
+	fMinor.ToLower();
+	fMicro.ToLower();
+	fPreRelease.ToLower();
 }
 
 

From 15e694e535dbb1d20370a0bd6c31b3d1d69039b1 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 20:32:09 +0200
Subject: [PATCH 0283/1170] Add UnpackingNode::IsOnlyPackageNode()

It returns whether the given package node is the only package node
attached to that node.
---
 .../kernel/file_systems/packagefs/UnpackingDirectory.cpp  | 8 ++++++++
 .../kernel/file_systems/packagefs/UnpackingDirectory.h    | 1 +
 .../kernel/file_systems/packagefs/UnpackingLeafNode.cpp   | 8 ++++++++
 .../kernel/file_systems/packagefs/UnpackingLeafNode.h     | 1 +
 src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h | 1 +
 5 files changed, 19 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp
index 7c70b523b0..66606aeb04 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp
@@ -132,6 +132,14 @@ UnpackingDirectory::GetPackageNode()
 }
 
 
+bool
+UnpackingDirectory::IsOnlyPackageNode(PackageNode* node) const
+{
+	return node == fPackageDirectories.Head()
+		&& node == fPackageDirectories.Tail();
+}
+
+
 status_t
 UnpackingDirectory::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h
index bb94156e9a..61d73034fc 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h
@@ -28,6 +28,7 @@ public:
 	virtual	void				RemovePackageNode(PackageNode* packageNode);
 
 	virtual	PackageNode*		GetPackageNode();
+	virtual	bool				IsOnlyPackageNode(PackageNode* node) const;
 
 	virtual	status_t			OpenAttributeDirectory(
 									AttributeDirectoryCookie*& _cookie);
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp
index 80ca1b96a3..9d671a389b 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp
@@ -156,6 +156,14 @@ UnpackingLeafNode::GetPackageNode()
 }
 
 
+bool
+UnpackingLeafNode::IsOnlyPackageNode(PackageNode* node) const
+{
+	PackageLeafNode* head = fPackageNodes.Head();
+	return node == head && fPackageNodes.GetNext(head) == NULL;
+}
+
+
 status_t
 UnpackingLeafNode::Read(off_t offset, void* buffer, size_t* bufferSize)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h
index b9ed5de547..e1b8db4340 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h
@@ -31,6 +31,7 @@ public:
 	virtual	void				RemovePackageNode(PackageNode* packageNode);
 
 	virtual	PackageNode*		GetPackageNode();
+	virtual	bool				IsOnlyPackageNode(PackageNode* node) const;
 
 	virtual	status_t			Read(off_t offset, void* buffer,
 									size_t* bufferSize);
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h
index f1edd5fe3d..3ac50316c7 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h
@@ -23,6 +23,7 @@ public:
 	virtual	void				RemovePackageNode(PackageNode* packageNode) = 0;
 
 	virtual	PackageNode*		GetPackageNode() = 0;
+	virtual	bool				IsOnlyPackageNode(PackageNode* node) const = 0;
 };
 
 

From 0c7ef631d8f7bd5ddc951991882c383a6223a85f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 20:35:50 +0200
Subject: [PATCH 0284/1170] Notify earlier when removing a package node

Volume::_RemovePackageNode(): Notify listeners before removing the last
package node from the node, . This prevents the size/last modified
indices from not finding the node anymore, since the node would return
a default value instead of the value it was added to the index with.
---
 .../kernel/file_systems/packagefs/Volume.cpp  | 27 +++++++++++--------
 1 file changed, 16 insertions(+), 11 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 3304741cc4..38fb0de063 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -1274,12 +1274,16 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
 	// details.
 
 	PackageNode* headPackageNode = unpackingNode->GetPackageNode();
-	unpackingNode->RemovePackageNode(packageNode);
-
-	// If the node doesn't have any more package nodes attached, remove it
-	// completely.
 	bool nodeRemoved = false;
-	if (unpackingNode->GetPackageNode() == NULL) {
+
+	// If this is the last package node of the node, remove it completely.
+	if (unpackingNode->IsOnlyPackageNode(packageNode)) {
+		// Notify before removing the node. Otherwise the indices might not
+		// find the node anymore.
+		_NotifyNodeRemoved(node);
+
+		unpackingNode->RemovePackageNode(packageNode);
+
 		// we get and put the vnode to notify the VFS
 		// TODO: We should probably only do that, if the node is known to the
 		// VFS in the first place.
@@ -1293,13 +1297,14 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
 			RemoveVNode(node->ID());
 			PutVNode(node->ID());
 		}
-	}
+	} else {
+		// The node does at least have one more package node.
+		unpackingNode->RemovePackageNode(packageNode);
 
-	if (nodeRemoved)
-		_NotifyNodeRemoved(node);
-	else if (packageNode == headPackageNode) {
-		_NotifyNodeChanged(node, kAllStatFields,
-			OldUnpackingNodeAttributes(headPackageNode));
+		if (packageNode == headPackageNode) {
+			_NotifyNodeChanged(node, kAllStatFields,
+				OldUnpackingNodeAttributes(headPackageNode));
+		}
 	}
 
 	if (!notify)

From f642202ae81d265a891ab77659c566f57b376cc9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 11 Jul 2011 20:42:48 +0200
Subject: [PATCH 0285/1170] Updated gcc 2.95.3 package

The /boot/common include paths are now built in.
---
 build/jam/OptionalPackages | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index b8687a1177..1f9cd8fa21 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -518,13 +518,13 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 		&& $(TARGET_ARCH) = x86 {
 	# gcc and binutils
 	if $(HAIKU_GCC_VERSION[1]) = 2 {
-		InstallOptionalHaikuImagePackage gcc-2.95.3_110304-1.hpkg
-			: $(hpkgBaseURL)/gcc-2.95.3_110304-1.hpkg
+		InstallOptionalHaikuImagePackage gcc-2.95.3_110711-1-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/gcc-2.95.3_110711-1-x86_gcc2.hpkg
 			: common packages ;
 
 		# TODO: remove this when we have a mechanism to switch gcc via PATH
 		AddSymlinkToHaikuImage common settings develop tools
-			: /boot/common/develop/tools/gcc-2.95.3-110304
+			: /boot/common/develop/tools/gcc-2.95.3-110711
 			: current ;
 	}
 

From 30ab13397ba65e2454ee4bb971565fe8457a34e5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 13 Jul 2011 01:44:21 +0200
Subject: [PATCH 0286/1170] Handle the newer package attributes

---
 src/kits/package/hpkg/RepositoryWriterImpl.cpp | 16 ++++++++++++++++
 1 file changed, 16 insertions(+)

diff --git a/src/kits/package/hpkg/RepositoryWriterImpl.cpp b/src/kits/package/hpkg/RepositoryWriterImpl.cpp
index 3da9e94d9b..7e9ba2499c 100644
--- a/src/kits/package/hpkg/RepositoryWriterImpl.cpp
+++ b/src/kits/package/hpkg/RepositoryWriterImpl.cpp
@@ -230,6 +230,22 @@ struct PackageContentHandler : public BPackageContentHandler {
 				fPackageInfo->AddReplaces(value.string);
 				break;
 
+			case B_PACKAGE_INFO_URLS:
+				fPackageInfo->AddURL(value.string);
+				break;
+
+			case B_PACKAGE_INFO_SOURCE_URLS:
+				fPackageInfo->AddSourceURL(value.string);
+				break;
+
+			case B_PACKAGE_INFO_CHECKSUM:
+				fPackageInfo->SetChecksum(value.string);
+				break;
+
+			case B_PACKAGE_INFO_INSTALL_PATH:
+				fPackageInfo->SetInstallPath(value.string);
+				break;
+
 			default:
 				fErrorOutput->PrintError(
 					"Invalid package attribute section: unexpected package "

From c3057c3f039fe2f857ed7490d4db5a80d5239109 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 13 Jul 2011 01:44:57 +0200
Subject: [PATCH 0287/1170] Initialize BRepositoryInfo::fInitStatus

---
 src/kits/package/RepositoryInfo.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/kits/package/RepositoryInfo.cpp b/src/kits/package/RepositoryInfo.cpp
index 5878dfcccd..94065c0016 100644
--- a/src/kits/package/RepositoryInfo.cpp
+++ b/src/kits/package/RepositoryInfo.cpp
@@ -55,7 +55,7 @@ BRepositoryInfo::BRepositoryInfo(BMessage* data)
 
 BRepositoryInfo::BRepositoryInfo(const BEntry& entry)
 {
-	SetTo(entry);
+	fInitStatus = SetTo(entry);
 }
 
 

From c71072069bc544f6f2553f7fd400cbec6de28770 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 13 Jul 2011 01:50:00 +0200
Subject: [PATCH 0288/1170] GetRepositoryCache/Config(): return valid entry

Always create the common repository cache/config paths so the BEntry
that is returned is valid at least. Fixes BRefreshRepositoryRequest
failing when the common repository cache path didn't exist yet.
---
 src/kits/package/PackageRoster.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/kits/package/PackageRoster.cpp b/src/kits/package/PackageRoster.cpp
index 66674faad6..ce6edc9fc9 100644
--- a/src/kits/package/PackageRoster.cpp
+++ b/src/kits/package/PackageRoster.cpp
@@ -139,7 +139,7 @@ BPackageRoster::GetRepositoryCache(const BString& name,
 	if (repoCacheEntry.Exists())
 		return repositoryCache->SetTo(repoCacheEntry);
 
-	if ((result = GetCommonRepositoryCachePath(&path)) != B_OK)
+	if ((result = GetCommonRepositoryCachePath(&path, true)) != B_OK)
 		return result;
 	path.Append(name.String());
 
@@ -166,7 +166,7 @@ BPackageRoster::GetRepositoryConfig(const BString& name,
 	if (repoConfigEntry.Exists())
 		return repositoryConfig->SetTo(repoConfigEntry);
 
-	if ((result = GetCommonRepositoryConfigPath(&path)) != B_OK)
+	if ((result = GetCommonRepositoryConfigPath(&path, true)) != B_OK)
 		return result;
 	path.Append(name.String());
 

From f19b93ff219652717c42346226293e4a69356d42 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 15 Jul 2011 12:57:52 +0200
Subject: [PATCH 0289/1170] Missing newline in error message

---
 src/system/kernel/fs/vfs_boot.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/system/kernel/fs/vfs_boot.cpp b/src/system/kernel/fs/vfs_boot.cpp
index 22d7e4cf12..2ee637f187 100644
--- a/src/system/kernel/fs/vfs_boot.cpp
+++ b/src/system/kernel/fs/vfs_boot.cpp
@@ -530,7 +530,7 @@ vfs_mount_boot_file_system(kernel_args* args)
 			"packages /boot/common/packages; type common",
 			0 /* unused argument length */);
 		if (commonPackageMount < 0) {
-			dprintf("Failed to mount common packagefs: %s",
+			dprintf("Failed to mount common packagefs: %s\n",
 				strerror(commonPackageMount));
 		}
 	}

From 61b0ae0f392ca84df38696c8e4accbada4298afb Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 15 Jul 2011 13:03:22 +0200
Subject: [PATCH 0290/1170] Implement more virtuals in Node and Directory

* Node: Add default implementations for UserID(), GroupID(),
  OpenAttributeDirectory(), and OpenAttribute().
* Directory: Add default implementations for Mode() and FileSize().
* Remove the respective hook implementations in the PackageLink*
  classes.
---
 .../file_systems/packagefs/Directory.cpp      | 14 +++++
 .../kernel/file_systems/packagefs/Directory.h |  3 ++
 .../kernel/file_systems/packagefs/Node.cpp    | 35 +++++++++++++
 .../kernel/file_systems/packagefs/Node.h      |  8 +--
 .../packagefs/PackageLinkDirectory.cpp        | 52 -------------------
 .../packagefs/PackageLinkDirectory.h          |  9 ----
 .../packagefs/PackageLinkSymlink.cpp          | 36 -------------
 .../packagefs/PackageLinkSymlink.h            |  7 ---
 .../packagefs/PackageLinksDirectory.cpp       | 51 ------------------
 .../packagefs/PackageLinksDirectory.h         |  9 ----
 10 files changed, 56 insertions(+), 168 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp
index c073dc06ba..0ac01c5f8a 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Directory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Directory.cpp
@@ -41,6 +41,20 @@ Directory::Init(Directory* parent, const char* name, uint32 flags)
 }
 
 
+mode_t
+Directory::Mode() const
+{
+	return S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
+}
+
+
+off_t
+Directory::FileSize() const
+{
+	return 0;
+}
+
+
 status_t
 Directory::Read(off_t offset, void* buffer, size_t* bufferSize)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/Directory.h b/src/add-ons/kernel/file_systems/packagefs/Directory.h
index 3dc604cd37..c117d1ec08 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Directory.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Directory.h
@@ -30,6 +30,9 @@ public:
 	virtual	status_t			Init(Directory* parent, const char* name,
 									uint32 flags);
 
+	virtual	mode_t				Mode() const;
+	virtual	off_t				FileSize() const;
+
 	virtual	status_t			Read(off_t offset, void* buffer,
 									size_t* bufferSize);
 	virtual	status_t			Read(io_request* request);
diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.cpp b/src/add-ons/kernel/file_systems/packagefs/Node.cpp
index f452c913a7..ef137c3dea 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Node.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Node.cpp
@@ -10,6 +10,7 @@
 #include 
 
 #include "DebugSupport.h"
+#include "EmptyAttributeDirectoryCookie.h"
 
 
 Node::Node(ino_t id)
@@ -79,6 +80,40 @@ Node::SetParent(Directory* parent)
 }
 
 
+uid_t
+Node::UserID() const
+{
+	return 0;
+}
+
+
+gid_t
+Node::GroupID() const
+{
+	return 0;
+}
+
+
+status_t
+Node::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
+{
+	AttributeDirectoryCookie* cookie
+		= new(std::nothrow) EmptyAttributeDirectoryCookie;
+	if (cookie == NULL)
+		return B_NO_MEMORY;
+
+	_cookie = cookie;
+	return B_OK;
+}
+
+
+status_t
+Node::OpenAttribute(const char* name, int openMode, AttributeCookie*& _cookie)
+{
+	return B_ENTRY_NOT_FOUND;
+}
+
+
 status_t
 Node::IndexAttribute(AttributeIndexer* indexer)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h
index d7465af16c..e107f7319e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Node.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Node.h
@@ -67,8 +67,8 @@ public:
 			void				SetParent(Directory* parent);
 
 	virtual	mode_t				Mode() const = 0;
-	virtual	uid_t				UserID() const = 0;
-	virtual	gid_t				GroupID() const = 0;
+	virtual	uid_t				UserID() const;
+	virtual	gid_t				GroupID() const;
 	virtual	timespec			ModifiedTime() const = 0;
 	virtual	off_t				FileSize() const = 0;
 
@@ -80,9 +80,9 @@ public:
 									size_t* bufferSize) = 0;
 
 	virtual	status_t			OpenAttributeDirectory(
-									AttributeDirectoryCookie*& _cookie) = 0;
+									AttributeDirectoryCookie*& _cookie);
 	virtual	status_t			OpenAttribute(const char* name, int openMode,
-									AttributeCookie*& _cookie) = 0;
+									AttributeCookie*& _cookie);
 
 	virtual	status_t			IndexAttribute(AttributeIndexer* indexer);
 	virtual	void*				IndexCookieForAttribute(const char* name) const;
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
index 86fab0f19b..baa68818f7 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
@@ -12,7 +12,6 @@
 
 #include 
 
-#include "EmptyAttributeDirectoryCookie.h"
 #include "DebugSupport.h"
 #include "PackageLinksListener.h"
 #include "Utils.h"
@@ -86,63 +85,12 @@ PackageLinkDirectory::Init(Directory* parent, const char* name, uint32 flags)
 }
 
 
-mode_t
-PackageLinkDirectory::Mode() const
-{
-	return S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
-}
-
-
-uid_t
-PackageLinkDirectory::UserID() const
-{
-	return 0;
-}
-
-
-gid_t
-PackageLinkDirectory::GroupID() const
-{
-	return 0;
-}
-
-
 timespec
 PackageLinkDirectory::ModifiedTime() const
 {
 	return fModifiedTime;
 }
 
-
-off_t
-PackageLinkDirectory::FileSize() const
-{
-	return 0;
-}
-
-
-status_t
-PackageLinkDirectory::OpenAttributeDirectory(
-	AttributeDirectoryCookie*& _cookie)
-{
-	AttributeDirectoryCookie* cookie
-		= new(std::nothrow) EmptyAttributeDirectoryCookie;
-	if (cookie == NULL)
-		return B_NO_MEMORY;
-
-	_cookie = cookie;
-	return B_OK;
-}
-
-
-status_t
-PackageLinkDirectory::OpenAttribute(const char* name, int openMode,
-	AttributeCookie*& _cookie)
-{
-	return B_ENTRY_NOT_FOUND;
-}
-
-
 void
 PackageLinkDirectory::AddPackage(Package* package,
 	PackageLinksListener* listener)
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h
index 0aca0837bb..798592c243 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h
@@ -23,16 +23,7 @@ public:
 	virtual	status_t			Init(Directory* parent, const char* name,
 									uint32 flags);
 
-	virtual	mode_t				Mode() const;
-	virtual	uid_t				UserID() const;
-	virtual	gid_t				GroupID() const;
 	virtual	timespec			ModifiedTime() const;
-	virtual	off_t				FileSize() const;
-
-	virtual	status_t			OpenAttributeDirectory(
-									AttributeDirectoryCookie*& _cookie);
-	virtual	status_t			OpenAttribute(const char* name, int openMode,
-									AttributeCookie*& _cookie);
 
 			void				AddPackage(Package* package,
 									PackageLinksListener* listener);
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
index 877b0824b7..ca3e83e667 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
@@ -10,7 +10,6 @@
 
 #include 
 
-#include "EmptyAttributeDirectoryCookie.h"
 #include "DebugSupport.h"
 #include "NodeListener.h"
 #include "PackageLinksListener.h"
@@ -116,20 +115,6 @@ PackageLinkSymlink::Mode() const
 }
 
 
-uid_t
-PackageLinkSymlink::UserID() const
-{
-	return 0;
-}
-
-
-gid_t
-PackageLinkSymlink::GroupID() const
-{
-	return 0;
-}
-
-
 timespec
 PackageLinkSymlink::ModifiedTime() const
 {
@@ -167,24 +152,3 @@ PackageLinkSymlink::ReadSymlink(void* buffer, size_t* bufferSize)
 
 	return B_OK;
 }
-
-
-status_t
-PackageLinkSymlink::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
-{
-	AttributeDirectoryCookie* cookie
-		= new(std::nothrow) EmptyAttributeDirectoryCookie;
-	if (cookie == NULL)
-		return B_NO_MEMORY;
-
-	_cookie = cookie;
-	return B_OK;
-}
-
-
-status_t
-PackageLinkSymlink::OpenAttribute(const char* name, int openMode,
-	AttributeCookie*& _cookie)
-{
-	return B_ENTRY_NOT_FOUND;
-}
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h
index cfa64a8c4d..cbf66fcec3 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h
@@ -22,8 +22,6 @@ public:
 									PackageLinksListener* listener);
 
 	virtual	mode_t				Mode() const;
-	virtual	uid_t				UserID() const;
-	virtual	gid_t				GroupID() const;
 	virtual	timespec			ModifiedTime() const;
 	virtual	off_t				FileSize() const;
 
@@ -33,11 +31,6 @@ public:
 
 	virtual	status_t			ReadSymlink(void* buffer, size_t* bufferSize);
 
-	virtual	status_t			OpenAttributeDirectory(
-									AttributeDirectoryCookie*& _cookie);
-	virtual	status_t			OpenAttribute(const char* name, int openMode,
-									AttributeCookie*& _cookie);
-
 private:
 			struct OldAttributes;
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp
index be3a2a875c..6aa810969f 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp
@@ -8,7 +8,6 @@
 
 #include 
 
-#include "EmptyAttributeDirectoryCookie.h"
 #include "DebugSupport.h"
 #include "PackageLinkDirectory.h"
 #include "PackageLinksListener.h"
@@ -30,27 +29,6 @@ PackageLinksDirectory::~PackageLinksDirectory()
 }
 
 
-mode_t
-PackageLinksDirectory::Mode() const
-{
-	return S_IFDIR | S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH;
-}
-
-
-uid_t
-PackageLinksDirectory::UserID() const
-{
-	return 0;
-}
-
-
-gid_t
-PackageLinksDirectory::GroupID() const
-{
-	return 0;
-}
-
-
 timespec
 PackageLinksDirectory::ModifiedTime() const
 {
@@ -58,35 +36,6 @@ PackageLinksDirectory::ModifiedTime() const
 }
 
 
-off_t
-PackageLinksDirectory::FileSize() const
-{
-	return 0;
-}
-
-
-status_t
-PackageLinksDirectory::OpenAttributeDirectory(
-	AttributeDirectoryCookie*& _cookie)
-{
-	AttributeDirectoryCookie* cookie
-		= new(std::nothrow) EmptyAttributeDirectoryCookie;
-	if (cookie == NULL)
-		return B_NO_MEMORY;
-
-	_cookie = cookie;
-	return B_OK;
-}
-
-
-status_t
-PackageLinksDirectory::OpenAttribute(const char* name, int openMode,
-	AttributeCookie*& _cookie)
-{
-	return B_ENTRY_NOT_FOUND;
-}
-
-
 status_t
 PackageLinksDirectory::AddPackage(Package* package)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h
index 8d509038b8..0777fd5a76 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.h
@@ -18,16 +18,7 @@ public:
 								PackageLinksDirectory();
 	virtual						~PackageLinksDirectory();
 
-	virtual	mode_t				Mode() const;
-	virtual	uid_t				UserID() const;
-	virtual	gid_t				GroupID() const;
 	virtual	timespec			ModifiedTime() const;
-	virtual	off_t				FileSize() const;
-
-	virtual	status_t			OpenAttributeDirectory(
-									AttributeDirectoryCookie*& _cookie);
-	virtual	status_t			OpenAttribute(const char* name, int openMode,
-									AttributeCookie*& _cookie);
 
 			void				SetListener(PackageLinksListener* listener)
 									{ fListener = listener; }

From 3ac7efb860e745099a453541f124f7549c78cdc9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 15 Jul 2011 13:03:56 +0200
Subject: [PATCH 0291/1170] Fix debug output

---
 src/add-ons/kernel/file_systems/packagefs/Index.cpp | 13 ++++++++-----
 1 file changed, 8 insertions(+), 5 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Index.cpp b/src/add-ons/kernel/file_systems/packagefs/Index.cpp
index 8da53a4035..8b4ec21477 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Index.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Index.cpp
@@ -7,6 +7,7 @@
 #include "Index.h"
 
 #include "DebugSupport.h"
+#include "Directory.h"
 #include "Node.h"
 #include "IndexImpl.h"
 
@@ -73,11 +74,13 @@ void
 Index::Dump()
 {
 	D(
-		PRINT(("Index: `%s', type: %lx\n", Name(), Type()));
-		for (IndexIterator it(this); it.Current(); it.Next()) {
-			Node* node = it.Current();
-			PRINT(("  node: `%s', dir: %lld\n", node->GetName(),
-				node->Parent()->ID()));
+		PRINT("Index: `%s', type: %" B_PRIx32 "\n", Name(), Type());
+		IndexIterator it;
+		if (GetIterator(it)) {
+			while (Node* node = it.Next()) {
+				PRINT("  node: `%s', dir: %" B_PRIdINO "\n", node->Name(),
+					node->Parent()->ID());
+			}
 		}
 	)
 }

From f361dbbe9974869b65d743f2d9b6dc469639d7e3 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 15 Jul 2011 13:06:28 +0200
Subject: [PATCH 0292/1170] Fix notifications when adding package link dir

When adding a new package link directory, the volume would only be
notified about the addition of the directory itself, not of the addition
of its contents. Add a new PackageLinkDirectory::NotifyDirectoryAdded()
which does the whole job and use it in
PackageLinksDirectory::AddPackage().
---
 .../packagefs/PackageLinkDirectory.cpp        | 20 +++++++++++++++++++
 .../packagefs/PackageLinkDirectory.h          |  3 +++
 .../packagefs/PackageLinksDirectory.cpp       |  6 ++----
 3 files changed, 25 insertions(+), 4 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
index baa68818f7..c5e1b450e3 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
@@ -149,6 +149,26 @@ PackageLinkDirectory::UpdatePackageDependencies(Package* package,
 }
 
 
+void
+PackageLinkDirectory::NotifyDirectoryAdded(PackageLinksListener* listener)
+{
+	NodeWriteLocker writeLocker(this);
+
+	listener->PackageLinkNodeAdded(this);
+
+	if (fSelfLink != NULL) {
+		NodeWriteLocker selfLinkLocker(fSelfLink);
+		listener->PackageLinkNodeAdded(fSelfLink);
+	}
+
+	for (FamilyDependencyList::Iterator it = fDependencyLinks.GetIterator();
+			DependencyLink* link = it.Next();) {
+		NodeWriteLocker linkLocker(link);
+		listener->PackageLinkNodeAdded(link);
+	}
+}
+
+
 status_t
 PackageLinkDirectory::_Update(PackageLinksListener* listener)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h
index 798592c243..c5adc7ff3d 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h
@@ -32,6 +32,9 @@ public:
 			void				UpdatePackageDependencies(Package* package,
 									PackageLinksListener* listener);
 
+			void				NotifyDirectoryAdded(
+									PackageLinksListener* listener);
+
 			bool				IsEmpty() const
 									{ return fPackages.IsEmpty(); }
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp
index 6aa810969f..bbe09e9610 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp
@@ -70,10 +70,8 @@ PackageLinksDirectory::AddPackage(Package* package)
 		// No entry is in the way, so just add the link directory.
 		AddChild(linkDirectory);
 
-		if (fListener != NULL) {
-			NodeWriteLocker linkDirectoryWriteLocker(linkDirectory);
-			fListener->PackageLinkNodeAdded(linkDirectory);
-		}
+		if (fListener != NULL)
+			linkDirectory->NotifyDirectoryAdded(fListener);
 	}
 
 	return B_OK;

From 6c9fa4613647c05d1cbf4e86e0a9311cc0b04eb0 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 15 Jul 2011 13:21:26 +0200
Subject: [PATCH 0293/1170] Fix handling of shine-through directories

* Add a new class ShineThroughDirectory for shine-through directories
  instead of using UnpackingDirectory.
* Split up setting up the shine-through directories in two steps. First
  the directories are only created. That happens before adding the
  initial package domains. After publishing the root node we bind the
  shine-through directories to the underlying directories.
* This makes adding a package directory with the same name as a
  shine-through directory fail in _AddPackageNode() as originally
  intended. Since we no longer want it to fail -- the package daemon
  will copy the files in the respective directories as part of the
  activation process -- we simply skip the directory now. Adjust
  _AddPackageNode() and _AddPackageContentRootNode() accordingly.
---
 .../kernel/file_systems/packagefs/Volume.cpp  | 145 ++++++++++++++----
 .../kernel/file_systems/packagefs/Volume.h    |   4 +
 2 files changed, 117 insertions(+), 32 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 38fb0de063..2581ed90fb 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -46,6 +46,7 @@
 #include "SizeIndex.h"
 #include "UnpackingLeafNode.h"
 #include "UnpackingDirectory.h"
+#include "Utils.h"
 #include "Version.h"
 
 
@@ -443,6 +444,27 @@ private:
 };
 
 
+// #pragma mark - ShineThroughDirectory
+
+
+struct Volume::ShineThroughDirectory : public Directory {
+	ShineThroughDirectory(ino_t id)
+		:
+		Directory(id)
+	{
+		get_real_time(fModifiedTime);
+	}
+
+	virtual timespec ModifiedTime() const
+	{
+		return fModifiedTime;
+	}
+
+private:
+	timespec	fModifiedTime;
+};
+
+
 // #pragma mark - Volume
 
 
@@ -656,6 +678,11 @@ Volume::Mount(const char* parameterString)
 			RETURN_ERROR(error);
 	}
 
+	// create shine-through directories
+	error = _CreateShineThroughDirectories(shineThrough);
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
 	// create default package domain
 	error = _AddInitialPackageDomain(packages);
 	if (error != B_OK)
@@ -667,11 +694,6 @@ Volume::Mount(const char* parameterString)
 	if (fPackageLoader < 0)
 		RETURN_ERROR(fPackageLoader);
 
-	// establish shine-through directories
-	error = _CreateShineThroughDirectories(shineThrough);
-	if (error != B_OK)
-		RETURN_ERROR(error);
-
 	// publish the root node
 	fRootDirectory->AcquireReference();
 	error = PublishVNode(fRootDirectory);
@@ -680,6 +702,11 @@ Volume::Mount(const char* parameterString)
 		RETURN_ERROR(error);
 	}
 
+	// bind and publish the shine-through directories
+	error = _PublishShineThroughDirectories();
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
 	// run the package loader
 	resume_thread(fPackageLoader);
 
@@ -1083,6 +1110,7 @@ Volume::_AddPackageContentRootNode(Package* package,
 	do {
 		Node* node;
 		status_t error = _AddPackageNode(directory, packageNode, notify, node);
+			// returns B_OK with a NULL node, when skipping the node
 		if (error != B_OK) {
 			// unlock all directories
 			while (directory != NULL) {
@@ -1096,14 +1124,16 @@ Volume::_AddPackageContentRootNode(Package* package,
 			RETURN_ERROR(error);
 		}
 
-		// recursive into directory
-		if (PackageDirectory* packageDirectory
-				= dynamic_cast(packageNode)) {
-			if (packageDirectory->FirstChild() != NULL) {
-				directory = dynamic_cast(node);
-				packageNode = packageDirectory->FirstChild();
-				directory->WriteLock();
-				continue;
+		// recursive into directory, unless we're supposed to skip the node
+		if (node != NULL) {
+			if (PackageDirectory* packageDirectory
+					= dynamic_cast(packageNode)) {
+				if (packageDirectory->FirstChild() != NULL) {
+					directory = dynamic_cast(node);
+					packageNode = packageDirectory->FirstChild();
+					directory->WriteLock();
+					continue;
+				}
 			}
 		}
 
@@ -1196,8 +1226,11 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
 
 	if (node != NULL) {
 		unpackingNode = dynamic_cast(node);
-		if (unpackingNode == NULL)
-			RETURN_ERROR(B_BAD_VALUE);
+		if (unpackingNode == NULL) {
+			_node = NULL;
+			return B_OK;
+		}
+		oldPackageNode = unpackingNode->GetPackageNode();
 	} else {
 		status_t error = _CreateUnpackingNode(packageNode->Mode(), directory,
 			packageNode->Name(), unpackingNode);
@@ -1205,7 +1238,6 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
 			RETURN_ERROR(error);
 
 		node = unpackingNode->GetNode();
-		oldPackageNode = unpackingNode->GetPackageNode();
 		newNode = true;
 	}
 
@@ -1356,7 +1388,7 @@ Volume::_CreateUnpackingNode(mode_t mode, Directory* parent, const char* name,
 
 	fNodes.Insert(node);
 	nodeReference.Detach();
-		// we keep the initial node reference for this table
+		// we keep the initial node reference for the table
 
 	_node = unpackingNode;
 	return B_OK;
@@ -1547,6 +1579,31 @@ Volume::_InitMountType(const char* mountType)
 }
 
 
+status_t
+Volume::_CreateShineThroughDirectory(Directory* parent, const char* name,
+	Directory*& _directory)
+{
+	ShineThroughDirectory* directory = new(std::nothrow) ShineThroughDirectory(
+		fNextNodeID++);
+	if (directory == NULL)
+		RETURN_ERROR(B_NO_MEMORY);
+	BReference directoryReference(directory, true);
+
+	status_t error = directory->Init(parent, name, 0);
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	parent->AddChild(directory);
+
+	fNodes.Insert(directory);
+	directoryReference.Detach();
+		// we keep the initial node reference for the table
+
+	_directory = directory;
+	return B_OK;
+}
+
+
 status_t
 Volume::_CreateShineThroughDirectories(const char* shineThroughSetting)
 {
@@ -1582,9 +1639,38 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting)
 	if (directories == NULL)
 		return B_OK;
 
-	// iterate through the directory list, create the directories, and bind them
-	// to the mount point subdirectories
+	// iterate through the directory list and create the directories
 	while (const char* directoryName = *(directories++)) {
+		// create the directory
+		Directory* directory;
+		status_t error = _CreateShineThroughDirectory(fRootDirectory,
+			directoryName, directory);
+		if (error != B_OK)
+			RETURN_ERROR(error);
+	}
+
+	return B_OK;
+}
+
+
+status_t
+Volume::_PublishShineThroughDirectories()
+{
+	// Iterate through the root directory children and bind the shine-through
+	// directories to the respective mount point subdirectories.
+	Node* nextNode;
+	for (Node* node = fRootDirectory->FirstChild(); node != NULL;
+			node = nextNode) {
+		nextNode = fRootDirectory->NextChild(node);
+
+		// skip anything but shine-through directories
+		ShineThroughDirectory* directory
+			= dynamic_cast(node);
+		if (directory == NULL)
+			continue;
+
+		const char* directoryName = directory->Name();
+
 		// look up the mount point subdirectory
 		struct vnode* vnode;
 		status_t error = vfs_entry_ref_to_vnode(fMountPoint.deviceID,
@@ -1592,6 +1678,7 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting)
 		if (error != B_OK) {
 			dprintf("packagefs: Failed to get shine-through directory \"%s\": "
 				"%s\n", directoryName, strerror(error));
+			_RemoveNode(directory);
 			continue;
 		}
 		CObjectDeleter vnodePutter(vnode, &vfs_put_vnode);
@@ -1602,35 +1689,29 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting)
 		if (error != B_OK) {
 			dprintf("packagefs: Failed to stat shine-through directory \"%s\": "
 				"%s\n", directoryName, strerror(error));
+			_RemoveNode(directory);
 			continue;
 		}
 
 		if (!S_ISDIR(st.st_mode)) {
 			dprintf("packagefs: Shine-through entry \"%s\" is not a "
 				"directory\n", directoryName);
+			_RemoveNode(directory);
 			continue;
 		}
 
-		// create the directory
-		UnpackingNode* directory;
-		error = _CreateUnpackingNode(S_IFDIR, fRootDirectory, directoryName,
-			directory);
-		if (error != B_OK)
-			RETURN_ERROR(error);
-
-		// publish its vnode, so the VFS will find it without asking us
-		Node* directoryNode = directory->GetNode();
-		error = PublishVNode(directoryNode);
+		// publish the vnode, so the VFS will find it without asking us
+		error = PublishVNode(directory);
 		if (error != B_OK) {
-			_RemoveNode(directoryNode);
+			_RemoveNode(directory);
 			RETURN_ERROR(error);
 		}
 
 		// bind the directory
 		error = vfs_bind_mount_directory(st.st_dev, st.st_ino, fFSVolume->id,
-			directoryNode->ID());
+			directory->ID());
 
-		PutVNode(directoryNode->ID());
+		PutVNode(directory->ID());
 			// release our reference again -- on success
 			// vfs_bind_mount_directory() got one
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index 6f68c5c6ad..d939b66a8f 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -111,6 +111,7 @@ private:
 			struct PackageLoaderErrorOutput;
 			struct PackageLoaderContentHandler;
 			struct DomainDirectoryListener;
+			struct ShineThroughDirectory;
 
 			friend struct AddPackageDomainJob;
 			friend struct DomainDirectoryEventJob;
@@ -175,8 +176,11 @@ private:
 									const char* name, bool notify);
 
 			status_t			_InitMountType(const char* mountType);
+			status_t			_CreateShineThroughDirectory(Directory* parent,
+									const char* name, Directory*& _directory);
 			status_t			_CreateShineThroughDirectories(
 									const char* shineThroughSetting);
+			status_t			_PublishShineThroughDirectories();
 
 			status_t			_AddPackageLinksDirectory();
 			void				_RemovePackageLinksDirectory();

From 5bc695204984ddd2ba5da212f71eaa8d7db2dafd Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 15 Jul 2011 13:22:28 +0200
Subject: [PATCH 0294/1170] Add error output in case of invalid compression ID

---
 src/kits/package/hpkg/ReaderImplBase.cpp | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/src/kits/package/hpkg/ReaderImplBase.cpp b/src/kits/package/hpkg/ReaderImplBase.cpp
index 7f2c3fd94d..150c3d12bf 100644
--- a/src/kits/package/hpkg/ReaderImplBase.cpp
+++ b/src/kits/package/hpkg/ReaderImplBase.cpp
@@ -1066,7 +1066,11 @@ ReaderImplBase::ReadCompressedBuffer(const SectionInfo& section)
 		}
 
 		default:
+		{
+			fErrorOutput->PrintError("Error: Invalid compression type: %u\n",
+				section.compression);
 			return B_BAD_DATA;
+		}
 	}
 }
 

From abf1023d31bdf9f17a696c8730365eba6b44bda2 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 15 Jul 2011 13:23:30 +0200
Subject: [PATCH 0295/1170] Handle the newer package attributes

This unbreaks reading repository cache files using the respective
attributes.
---
 src/kits/package/RepositoryCache.cpp | 12 ++++++++++++
 1 file changed, 12 insertions(+)

diff --git a/src/kits/package/RepositoryCache.cpp b/src/kits/package/RepositoryCache.cpp
index 3609b069f0..9b1dc4e160 100644
--- a/src/kits/package/RepositoryCache.cpp
+++ b/src/kits/package/RepositoryCache.cpp
@@ -135,6 +135,18 @@ struct RepositoryContentHandler : BRepositoryContentHandler {
 				fPackageInfo.AddReplaces(value.string);
 				break;
 
+			case B_PACKAGE_INFO_URLS:
+				fPackageInfo.AddURL(value.string);
+				break;
+
+			case B_PACKAGE_INFO_SOURCE_URLS:
+				fPackageInfo.AddSourceURL(value.string);
+				break;
+
+			case B_PACKAGE_INFO_INSTALL_PATH:
+				fPackageInfo.SetInstallPath(value.string);
+				break;
+
 			case B_PACKAGE_INFO_CHECKSUM:
 			{
 				fPackageInfo.SetChecksum(value.string);

From 5a54e156e5b96ef240ce432a09f18dea364dcd47 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 16 Jul 2011 13:51:50 +0200
Subject: [PATCH 0296/1170] Add HashValue() methods to BString

---
 headers/os/support/String.h | 10 ++++++++++
 src/kits/support/String.cpp | 17 +++++++++++++++++
 2 files changed, 27 insertions(+)

diff --git a/headers/os/support/String.h b/headers/os/support/String.h
index 47260f1c5a..f3d5ae61d7 100644
--- a/headers/os/support/String.h
+++ b/headers/os/support/String.h
@@ -30,6 +30,9 @@ public:
 								int32 charCount) const;
 			bool			IsEmpty() const;
 
+			uint32			HashValue() const;
+	static	uint32			HashValue(const char* string);
+
 			// Assignment
 			BString&		operator=(const BString& string);
 			BString&		operator=(const char* string);
@@ -416,6 +419,13 @@ BString::String() const
 }
 
 
+inline uint32
+BString::HashValue() const
+{
+	return HashValue(String());
+}
+
+
 inline BString &
 BString::SetTo(const char* string)
 {
diff --git a/src/kits/support/String.cpp b/src/kits/support/String.cpp
index e1be1c00a4..e153e7ef47 100644
--- a/src/kits/support/String.cpp
+++ b/src/kits/support/String.cpp
@@ -282,6 +282,23 @@ BString::CountBytes(int32 fromCharOffset, int32 charCount) const
 }
 
 
+/*static*/ uint32
+BString::HashValue(const char* string)
+{
+	// from the Dragon Book: a slightly modified hashpjw()
+    uint32 h = 0;
+    if (string != NULL) {
+        for (; *string; string++) {
+            uint32 g = h & 0xf0000000;
+            if (g)
+                h ^= g >> 24;
+            h = (h << 4) + *string;
+        }
+    }
+    return h;
+}
+
+
 //	#pragma mark - Assignment
 
 

From 10e1bc52678bd81eb2c9dd1de8661ecef0d22ee0 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 16 Jul 2011 14:02:49 +0200
Subject: [PATCH 0297/1170] BRepositoryCache: Add iteration, etc.

* Remove InitCheck() and the initializing constructor.
* Rename PackageCount() to CountPackages().
* Use BOpenHashTable instead of HashMap for the internal PackageMap.
* Allow multiple packages with the same name. Equally named packages are
  in a singly linked list after the first package with that name.
* Add an Iterator inner class and a GetIterator() method, so one can now
  iterate through the packages in the repository.
---
 headers/os/package/RepositoryCache.h  |  38 ++++-
 src/bin/pkgman/command_list_repos.cpp |   2 +-
 src/kits/package/RepositoryCache.cpp  | 211 +++++++++++++++++++++-----
 3 files changed, 211 insertions(+), 40 deletions(-)

diff --git a/headers/os/package/RepositoryCache.h b/headers/os/package/RepositoryCache.h
index 49c8232283..cb49150b25 100644
--- a/headers/os/package/RepositoryCache.h
+++ b/headers/os/package/RepositoryCache.h
@@ -15,14 +15,18 @@
 namespace BPackageKit {
 
 
+class BPackageInfo;
+
+
 class BRepositoryCache {
+public:
+			class Iterator;
+
 public:
 								BRepositoryCache();
-								BRepositoryCache(const BEntry& entry);
 	virtual						~BRepositoryCache();
 
 			status_t			SetTo(const BEntry& entry);
-			status_t			InitCheck() const;
 
 			const BRepositoryInfo&	Info() const;
 			const BEntry&		Entry() const;
@@ -30,14 +34,19 @@ public:
 
 			void				SetIsUserSpecific(bool isUserSpecific);
 
-			uint32				PackageCount() const;
+			uint32				CountPackages() const;
+			Iterator			GetIterator() const;
 
 private:
+			struct PackageInfo;
+			struct PackageInfoHashDefinition;
 			struct PackageMap;
+			struct RepositoryContentHandler;
+			struct StandardErrorOutput;
+
+			friend class Iterator;
 
 private:
-			status_t			fInitStatus;
-
 			BEntry				fEntry;
 			BRepositoryInfo		fInfo;
 			bool				fIsUserSpecific;
@@ -46,6 +55,25 @@ private:
 };
 
 
+class BRepositoryCache::Iterator {
+public:
+								Iterator();
+
+			bool				HasNext() const;
+			const BPackageInfo*	Next();
+
+private:
+								Iterator(const BRepositoryCache* cache);
+
+private:
+			friend class BRepositoryCache;
+
+private:
+			const BRepositoryCache* fCache;
+			PackageInfo*		fNextInfo;
+};
+
+
 }	// namespace BPackageKit
 
 
diff --git a/src/bin/pkgman/command_list_repos.cpp b/src/bin/pkgman/command_list_repos.cpp
index d7d1b5c6c4..7df6012571 100644
--- a/src/bin/pkgman/command_list_repos.cpp
+++ b/src/bin/pkgman/command_list_repos.cpp
@@ -116,7 +116,7 @@ command_list_repos(int argc, const char* const* argv)
 					repoCache.Info().Summary().String());
 				printf("\t\tarch:      %s\n", BPackageInfo::kArchitectureNames[
 						repoCache.Info().Architecture()]);
-				printf("\t\tpkg-count: %lu\n", repoCache.PackageCount());
+				printf("\t\tpkg-count: %lu\n", repoCache.CountPackages());
 				printf("\t\torig-url:  %s\n",
 					repoCache.Info().OriginalBaseURL().String());
 				printf("\t\torig-prio: %u\n", repoCache.Info().Priority());
diff --git a/src/kits/package/RepositoryCache.cpp b/src/kits/package/RepositoryCache.cpp
index 9b1dc4e160..811839c675 100644
--- a/src/kits/package/RepositoryCache.cpp
+++ b/src/kits/package/RepositoryCache.cpp
@@ -18,7 +18,7 @@
 #include 
 #include 
 
-#include 
+#include 
 
 #include 
 #include 
@@ -36,14 +36,100 @@ using BPrivate::HashableString;
 using namespace BHPKG;
 
 
-namespace {
+// #pragma mark - PackageInfo
 
 
-typedef ::BPrivate::HashMap PackageHashMap;
+struct BRepositoryCache::PackageInfo : public BPackageInfo {
+	PackageInfo*	hashNext;
+	PackageInfo*	listNext;
 
-struct RepositoryContentHandler : BRepositoryContentHandler {
+	PackageInfo(const BPackageInfo& other)
+		:
+		BPackageInfo(other),
+		listNext(NULL)
+	{
+	}
+};
+
+
+// #pragma mark - PackageInfoHashDefinition
+
+
+struct BRepositoryCache::PackageInfoHashDefinition {
+	typedef const char*		KeyType;
+	typedef	PackageInfo		ValueType;
+
+	size_t HashKey(const char* key) const
+	{
+		return BString::HashValue(key);
+	}
+
+	size_t Hash(const PackageInfo* value) const
+	{
+		return value->Name().HashValue();
+	}
+
+	bool Compare(const char* key, const PackageInfo* value) const
+	{
+		return value->Name() == key;
+	}
+
+	PackageInfo*& GetLink(PackageInfo* value) const
+	{
+		return value->hashNext;
+	}
+};
+
+
+// #pragma mark - PackageMap
+
+
+struct BRepositoryCache::PackageMap
+	: public BOpenHashTable {
+
+	PackageMap()
+		:
+		fCount(0)
+	{
+	}
+
+	~PackageMap()
+	{
+		PackageInfo* info = Clear(true);
+		while (info != NULL) {
+			PackageInfo* next = info->hashNext;
+			delete info;
+			info = next;
+		}
+	}
+
+	void AddPackageInfo(PackageInfo* info)
+	{
+		if (PackageInfo* oldInfo = Lookup(info->Name())) {
+			info->listNext = oldInfo->listNext;
+			oldInfo->listNext = info;
+		} else
+			Insert(info);
+
+		fCount++;
+	}
+
+	uint32 CountPackageInfos() const
+	{
+		return fCount;
+	}
+
+private:
+	uint32	fCount;
+};
+
+
+// #pragma mark - RepositoryContentHandler
+
+
+struct BRepositoryCache::RepositoryContentHandler : BRepositoryContentHandler {
 	RepositoryContentHandler(BRepositoryInfo* repositoryInfo,
-		PackageHashMap* packageMap)
+		PackageMap* packageMap)
 		:
 		fRepositoryInfo(repositoryInfo),
 		fPackageMap(packageMap)
@@ -154,11 +240,21 @@ struct RepositoryContentHandler : BRepositoryContentHandler {
 				if (result != B_OK)
 					return result;
 
-				if (fPackageMap->ContainsKey(fPackageInfo.Name()))
-					return B_NAME_IN_USE;
-				result = fPackageMap->Put(fPackageInfo.Name(), fPackageInfo);
-				if (result != B_OK)
+				PackageInfo* info = new(std::nothrow) PackageInfo(fPackageInfo);
+				if (info == NULL)
+					return B_NO_MEMORY;
+
+				result = info->InitCheck();
+				if (result != B_OK) {
+					delete info;
 					return result;
+				}
+
+				if (PackageInfo* oldInfo = fPackageMap->Lookup(info->Name())) {
+					info->listNext = oldInfo->listNext;
+					oldInfo->listNext = info;
+				} else
+					fPackageMap->Insert(info);
 
 				fPackageInfo.Clear();
 				break;
@@ -185,11 +281,14 @@ struct RepositoryContentHandler : BRepositoryContentHandler {
 private:
 	BRepositoryInfo*	fRepositoryInfo;
 	BPackageInfo		fPackageInfo;
-	PackageHashMap*		fPackageMap;
+	PackageMap*			fPackageMap;
 };
 
 
-class StandardErrorOutput : public BErrorOutput {
+// #pragma mark - StandardErrorOutput
+
+
+class BRepositoryCache::StandardErrorOutput : public BErrorOutput {
 	virtual	void PrintErrorVarArgs(const char* format, va_list args)
 	{
 		vfprintf(stderr, format, args);
@@ -197,28 +296,61 @@ class StandardErrorOutput : public BErrorOutput {
 };
 
 
-}	// anonymous namespace
+// #pragma mark - Iterator
 
 
-struct BRepositoryCache::PackageMap : public PackageHashMap {
-};
-
-
-BRepositoryCache::BRepositoryCache()
+BRepositoryCache::Iterator::Iterator()
 	:
-	fInitStatus(B_NO_INIT),
-	fIsUserSpecific(false),
-	fPackageMap(new (std::nothrow) PackageMap)
+	fCache(NULL),
+	fNextInfo(NULL)
 {
 }
 
 
-BRepositoryCache::BRepositoryCache(const BEntry& entry)
+BRepositoryCache::Iterator::Iterator(const BRepositoryCache* cache)
+	:
+	fCache(cache),
+	fNextInfo(fCache->fPackageMap->GetIterator().Next())
+{
+}
+
+bool
+BRepositoryCache::Iterator::HasNext() const
+{
+	return fNextInfo != NULL;
+}
+
+
+const BPackageInfo*
+BRepositoryCache::Iterator::Next()
+{
+	BPackageInfo* result = fNextInfo;
+
+	if (fNextInfo != NULL) {
+		if (fNextInfo->listNext != NULL) {
+			// get next in list
+			fNextInfo = fNextInfo->listNext;
+		} else {
+			// get next in hash table
+			PackageMap::Iterator iterator
+				= fCache->fPackageMap->GetIterator(fNextInfo->Name());
+			iterator.Next();
+			fNextInfo = iterator.Next();
+		}
+	}
+
+	return result;
+}
+
+
+// #pragma mark - BRepositoryCache
+
+
+BRepositoryCache::BRepositoryCache()
 	:
 	fIsUserSpecific(false),
-	fPackageMap(new (std::nothrow) PackageMap)
+	fPackageMap(NULL)
 {
-	fInitStatus = SetTo(entry);
 }
 
 
@@ -228,13 +360,6 @@ BRepositoryCache::~BRepositoryCache()
 }
 
 
-status_t
-BRepositoryCache::InitCheck() const
-{
-	return fInitStatus;
-}
-
-
 const BEntry&
 BRepositoryCache::Entry() const
 {
@@ -266,14 +391,25 @@ BRepositoryCache::SetIsUserSpecific(bool isUserSpecific)
 status_t
 BRepositoryCache::SetTo(const BEntry& entry)
 {
+	// unset
+	if (fPackageMap != NULL) {
+		delete fPackageMap;
+		fPackageMap = NULL;
+	}
+
+	fEntry.Unset();
+
+	// create the package map
+	fPackageMap = new (std::nothrow) PackageMap;
 	if (fPackageMap == NULL)
 		return B_NO_MEMORY;
-	status_t result = fPackageMap->InitCheck();
+
+	status_t result = fPackageMap->Init();
 	if (result != B_OK)
 		return result;
 
+	// get cache file path
 	fEntry = entry;
-	fPackageMap->Clear();
 
 	BPath repositoryCachePath;
 	if ((result = entry.GetPath(&repositoryCachePath)) != B_OK)
@@ -301,12 +437,19 @@ BRepositoryCache::SetTo(const BEntry& entry)
 
 
 uint32
-BRepositoryCache::PackageCount() const
+BRepositoryCache::CountPackages() const
 {
 	if (fPackageMap == NULL)
 		return 0;
 
-	return fPackageMap->Size();
+	return fPackageMap->CountPackageInfos();
+}
+
+
+BRepositoryCache::Iterator
+BRepositoryCache::GetIterator() const
+{
+	return Iterator(this);
 }
 
 

From d0c417848b2a5b665578911e6acb3593bed8d0e8 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 16 Jul 2011 15:59:49 +0200
Subject: [PATCH 0298/1170] BString::Private class to access BString internals

---
 headers/build/private/support/StringPrivate.h |  1 +
 headers/os/support/String.h                   | 15 +++-
 headers/private/support/StringPrivate.h       | 75 +++++++++++++++++++
 src/build/libbe/support/Jamfile               |  2 +-
 src/kits/support/String.cpp                   | 36 ++++-----
 5 files changed, 106 insertions(+), 23 deletions(-)
 create mode 100644 headers/build/private/support/StringPrivate.h
 create mode 100644 headers/private/support/StringPrivate.h

diff --git a/headers/build/private/support/StringPrivate.h b/headers/build/private/support/StringPrivate.h
new file mode 100644
index 0000000000..c9b2aa39a3
--- /dev/null
+++ b/headers/build/private/support/StringPrivate.h
@@ -0,0 +1 @@
+#include <../private/support/StringPrivate.h>
diff --git a/headers/os/support/String.h b/headers/os/support/String.h
index f3d5ae61d7..bbe5354d51 100644
--- a/headers/os/support/String.h
+++ b/headers/os/support/String.h
@@ -321,9 +321,20 @@ public:
 			BString&		operator<<(float value);
 			BString&		operator<<(double value);
 
+public:
+			class Private;
+			friend class Private;
+
 private:
-	class PosVect;
-	friend class BStringRef;
+			class PosVect;
+			friend class BStringRef;
+
+			enum PrivateDataTag {
+				PRIVATE_DATA
+			};
+
+private:
+							BString(char* privateData, PrivateDataTag tag);
 
 			// Management
 			status_t		_MakeWritable();
diff --git a/headers/private/support/StringPrivate.h b/headers/private/support/StringPrivate.h
new file mode 100644
index 0000000000..68a098dc21
--- /dev/null
+++ b/headers/private/support/StringPrivate.h
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _SUPPORT_BSTRING_PRIVATE_H_
+#define _SUPPORT_BSTRING_PRIVATE_H_
+
+
+#include 
+
+#include 
+
+
+class BString::Private {
+public:
+	static const uint32 kPrivateDataOffset = 2 * sizeof(int32);
+
+public:
+	Private(const BString& string)
+		:
+		fString(string)
+	{
+	}
+
+	char* Data()
+	{
+		return fString.fPrivateData;
+	}
+
+	static vint32& DataRefCount(char* data)
+	{
+		return *(((int32 *)data) - 2);
+	}
+
+	vint32& DataRefCount()
+	{
+		return DataRefCount(Data());
+	}
+
+	static int32& DataLength(char* data)
+	{
+		return *(((int32*)data) - 1);
+	}
+
+	int32& DataLength()
+	{
+		return DataLength(Data());
+	}
+
+	static void IncrementDataRefCount(char* data)
+	{
+		if (data != NULL)
+			atomic_add(&DataRefCount(data), 1);
+	}
+
+	static void DecrementDataRefCount(char* data)
+	{
+		if (data != NULL) {
+			if (atomic_add(&DataRefCount(data), -1) == 1)
+				free(data - kPrivateDataOffset);
+		}
+	}
+
+	static BString StringFromData(char* data)
+	{
+		return BString(data, BString::PRIVATE_DATA);
+	}
+
+private:
+	const BString&	fString;
+};
+
+
+#endif	// _SUPPORT_BSTRING_PRIVATE_H_
+
diff --git a/src/build/libbe/support/Jamfile b/src/build/libbe/support/Jamfile
index 3f7e07e499..46a34b82dc 100644
--- a/src/build/libbe/support/Jamfile
+++ b/src/build/libbe/support/Jamfile
@@ -1,6 +1,6 @@
 SubDir HAIKU_TOP src build libbe support ;
 
-UsePrivateBuildHeaders app interface shared ;
+UsePrivateBuildHeaders app interface shared support ;
 
 USES_BE_API on support_kit.o = true ;
 
diff --git a/src/kits/support/String.cpp b/src/kits/support/String.cpp
index e153e7ef47..a31b9f2063 100644
--- a/src/kits/support/String.cpp
+++ b/src/kits/support/String.cpp
@@ -23,6 +23,7 @@
 
 #include 
 
+#include 
 #include 
 
 
@@ -34,7 +35,7 @@
 #define REPLACE_ALL 0x7FFFFFFF
 
 
-const uint32 kPrivateDataOffset = 2 * sizeof(int32);
+static const uint32 kPrivateDataOffset = BString::Private::kPrivateDataOffset;
 
 const char* B_EMPTY_STRING = "";
 
@@ -79,20 +80,6 @@ safestr(const char* str)
 }
 
 
-static inline vint32&
-data_reference_count(char* data)
-{
-	return *(((int32 *)data) - 2);
-}
-
-
-static inline int32&
-data_length(char* data)
-{
-	return *(((int32*)data) - 1);
-}
-
-
 //	#pragma mark - PosVect
 
 
@@ -202,14 +189,14 @@ BStringRef::operator&()
 inline vint32&
 BString::_ReferenceCount()
 {
-	return data_reference_count(fPrivateData);
+	return Private::DataRefCount(fPrivateData);
 }
 
 
 inline const vint32&
 BString::_ReferenceCount() const
 {
-	return data_reference_count(fPrivateData);
+	return Private::DataRefCount(fPrivateData);
 }
 
 
@@ -2148,6 +2135,15 @@ BString::operator<<(double value)
 //	#pragma mark - Private or reserved
 
 
+BString::BString(char* privateData, PrivateDataTag tag)
+	:
+	fPrivateData(privateData)
+{
+	if (fPrivateData != NULL)
+		atomic_add(&_ReferenceCount(), 1);
+}
+
+
 /*!	Detaches this string from an eventually shared fPrivateData, ie. this makes
 	this string writable.
 */
@@ -2226,8 +2222,8 @@ BString::_Allocate(int32 length)
 	newData[length] = '\0';
 
 	// initialize reference count & length
-	data_reference_count(newData) = 1;
-	data_length(newData) = length & 0x7fffffff;
+	Private::DataRefCount(newData) = 1;
+	Private::DataLength(newData) = length & 0x7fffffff;
 
 	return newData;
 }
@@ -2319,7 +2315,7 @@ BString::_ShrinkAtBy(int32 offset, int32 length)
 void
 BString::_SetLength(int32 length)
 {
-	data_length(fPrivateData) = length & 0x7fffffff;
+	Private::DataLength(fPrivateData) = length & 0x7fffffff;
 }
 
 

From 808a51161a479ea97517b4a3e57a27e684970007 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 16 Jul 2011 16:00:20 +0200
Subject: [PATCH 0299/1170] Add a BStringList class

---
 headers/build/os/support/StringList.h |   1 +
 headers/os/support/StringList.h       |  85 +++++++
 src/build/libbe/support/Jamfile       |   1 +
 src/kits/support/Jamfile              |   1 +
 src/kits/support/StringList.cpp       | 330 ++++++++++++++++++++++++++
 5 files changed, 418 insertions(+)
 create mode 100644 headers/build/os/support/StringList.h
 create mode 100644 headers/os/support/StringList.h
 create mode 100644 src/kits/support/StringList.cpp

diff --git a/headers/build/os/support/StringList.h b/headers/build/os/support/StringList.h
new file mode 100644
index 0000000000..b85cbcc9db
--- /dev/null
+++ b/headers/build/os/support/StringList.h
@@ -0,0 +1 @@
+#include <../os/support/StringList.h>
diff --git a/headers/os/support/StringList.h b/headers/os/support/StringList.h
new file mode 100644
index 0000000000..dba5edf70a
--- /dev/null
+++ b/headers/os/support/StringList.h
@@ -0,0 +1,85 @@
+/*
+ * Copyright 2011, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _SUPPORT_BSTRING_LIST_H_
+#define _SUPPORT_BSTRING_LIST_H_
+
+
+#include 
+#include 
+#include 
+
+
+class BStringList {
+public:
+								BStringList(int32 count = 20);
+								BStringList(const BStringList& other);
+	virtual						~BStringList();
+
+	// Adding and removing items.
+			bool				Add(const BString& string, int32 index);
+			bool				Add(const BString& string);
+			bool				Add(const BStringList& list, int32 index);
+			bool				Add(const BStringList& list);
+
+			bool				Remove(const BString& string,
+									bool ignoreCase = false);
+			BString				Remove(int32 index);
+			bool				Remove(int32 index, int32 count);
+			bool				Replace(int32 index, const BString& string);
+
+			void				MakeEmpty();
+
+	// Reorder items
+			void				Sort(bool ignoreCase = false);
+									// TODO: Sort() with custom sort function.
+			bool				Swap(int32 indexA, int32 indexB);
+			bool				Move(int32 fromIndex, int32 toIndex);
+
+	// Retrieve items
+			BString				StringAt(int32 index) const;
+			BString				First() const;
+			BString				Last() const;
+
+	// Query
+			bool				HasString(const BString& string,
+									bool ignoreCase = false) const;
+			int32				IndexOf(const BString& string,
+									bool ignoreCase = false) const;
+			int32				CountStrings() const;
+			bool				IsEmpty() const;
+
+	// Iteration
+			void				DoForEach(bool (*func)(const BString& string));
+			void				DoForEach(bool (*func)(const BString& string,
+									void* arg2), void* arg2);
+
+			BStringList&		operator=(const BStringList& other);
+			bool				operator==(const BStringList& other) const;
+			bool				operator!=(const BStringList& other) const;
+
+private:
+			void				_IncrementRefCounts() const;
+			void				_DecrementRefCounts() const;
+
+private:
+			BList				fStrings;
+};
+
+
+inline bool
+BStringList::HasString(const BString& string, bool ignoreCase) const
+{
+	return IndexOf(string, ignoreCase) >= 0;
+}
+
+
+inline bool
+BStringList::operator!=(const BStringList& other) const
+{
+	return !(*this == other);
+}
+
+
+#endif	// _SUPPORT_BSTRING_LIST_H_
diff --git a/src/build/libbe/support/Jamfile b/src/build/libbe/support/Jamfile
index 46a34b82dc..afa735e866 100644
--- a/src/build/libbe/support/Jamfile
+++ b/src/build/libbe/support/Jamfile
@@ -16,4 +16,5 @@ BuildPlatformMergeObjectPIC support_kit.o :
 	Locker.cpp
 	PointerList.cpp
 	String.cpp
+	StringList.cpp
 ;
diff --git a/src/kits/support/Jamfile b/src/kits/support/Jamfile
index 119f7cd2d2..1d21862838 100644
--- a/src/kits/support/Jamfile
+++ b/src/kits/support/Jamfile
@@ -20,5 +20,6 @@ MergeObject support_kit.o :
 	Referenceable.cpp
 	StopWatch.cpp
 	String.cpp
+	StringList.cpp
 	Url.cpp
 ;
diff --git a/src/kits/support/StringList.cpp b/src/kits/support/StringList.cpp
new file mode 100644
index 0000000000..9e0dc8ce22
--- /dev/null
+++ b/src/kits/support/StringList.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include 
+
+#include 
+
+#include 
+
+
+static int
+compare_private_data(const void* a, const void* b)
+{
+	return BString::Private::StringFromData((char*)a).Compare(
+		BString::Private::StringFromData((char*)b));
+}
+
+
+static int
+compare_private_data_ignore_case(const void* a, const void* b)
+{
+	return BString::Private::StringFromData((char*)a).ICompare(
+		BString::Private::StringFromData((char*)b));
+}
+
+
+// #pragma mark - BStringList
+
+
+BStringList::BStringList(int32 count)
+	:
+	fStrings(count)
+{
+}
+
+
+BStringList::BStringList(const BStringList& other)
+	:
+	fStrings(other.fStrings)
+{
+	_IncrementRefCounts();
+}
+
+
+BStringList::~BStringList()
+{
+	_DecrementRefCounts();
+}
+
+
+bool
+BStringList::Add(const BString& string, int32 index)
+{
+	char* privateData = BString::Private(string).Data();
+	if (!fStrings.AddItem(privateData, index))
+		return false;
+
+	BString::Private::IncrementDataRefCount(privateData);
+	return true;
+}
+
+
+bool
+BStringList::Add(const BString& string)
+{
+	char* privateData = BString::Private(string).Data();
+	if (!fStrings.AddItem(privateData))
+		return false;
+
+	BString::Private::IncrementDataRefCount(privateData);
+	return true;
+}
+
+
+bool
+BStringList::Add(const BStringList& list, int32 index)
+{
+	if (!fStrings.AddList(&list.fStrings, index))
+		return false;
+
+	list._IncrementRefCounts();
+	return true;
+}
+
+
+bool
+BStringList::Add(const BStringList& list)
+{
+	if (!fStrings.AddList(&list.fStrings))
+		return false;
+
+	list._IncrementRefCounts();
+	return true;
+}
+
+
+bool
+BStringList::Remove(const BString& string, bool ignoreCase)
+{
+	bool result = false;
+	int32 count = fStrings.CountItems();
+
+	if (ignoreCase) {
+		int32 length = string.Length();
+
+		for (int32 i = count - 1; i >= 0; i--) {
+			BString element(StringAt(i));
+			if (length == element.Length() && string.ICompare(element) == 0) {
+				Remove(i);
+				result = true;
+			}
+		}
+	} else {
+		for (int32 i = count - 1; i >= 0; i--) {
+			if (string == StringAt(i)) {
+				Remove(i);
+				result = true;
+			}
+		}
+	}
+
+	return result;
+}
+
+
+BString
+BStringList::Remove(int32 index)
+{
+	if (index < 0 || index >= fStrings.CountItems())
+		return BString();
+
+	char* privateData = (char*)fStrings.RemoveItem(index);
+	BString string(BString::Private::StringFromData(privateData));
+	BString::Private::DecrementDataRefCount(privateData);
+	return string;
+}
+
+
+bool
+BStringList::Remove(int32 index, int32 count)
+{
+	int32 stringCount = fStrings.CountItems();
+	if (index < 0 || index > stringCount)
+		return false;
+
+	int32 end = index + std::min(stringCount - index, count);
+	for (int32 i = index; i < end; i++)
+		BString::Private::DecrementDataRefCount((char*)fStrings.ItemAt(i));
+
+	fStrings.RemoveItems(index, end - index);
+	return true;
+}
+
+
+bool
+BStringList::Replace(int32 index, const BString& string)
+{
+	if (index < 0 || index >= fStrings.CountItems())
+		return false;
+
+	BString::Private::DecrementDataRefCount((char*)fStrings.ItemAt(index));
+
+	char* privateData = BString::Private(string).Data();
+	BString::Private::IncrementDataRefCount(privateData);
+	fStrings.ReplaceItem(index, privateData);
+
+	return true;
+}
+
+
+void
+BStringList::MakeEmpty()
+{
+	_DecrementRefCounts();
+	fStrings.MakeEmpty();
+}
+
+
+void
+BStringList::Sort(bool ignoreCase)
+{
+	fStrings.SortItems(ignoreCase
+		? compare_private_data_ignore_case : compare_private_data);
+}
+
+
+bool
+BStringList::Swap(int32 indexA, int32 indexB)
+{
+	return fStrings.SwapItems(indexA, indexB);
+}
+
+
+bool
+BStringList::Move(int32 fromIndex, int32 toIndex)
+{
+	return fStrings.MoveItem(fromIndex, toIndex);
+}
+
+
+BString
+BStringList::StringAt(int32 index) const
+{
+	return BString::Private::StringFromData((char*)fStrings.ItemAt(index));
+}
+
+
+BString
+BStringList::First() const
+{
+	return BString::Private::StringFromData((char*)fStrings.FirstItem());
+}
+
+
+BString
+BStringList::Last() const
+{
+	return BString::Private::StringFromData((char*)fStrings.LastItem());
+}
+
+
+int32
+BStringList::IndexOf(const BString& string, bool ignoreCase) const
+{
+	int32 count = fStrings.CountItems();
+
+	if (ignoreCase) {
+		int32 length = string.Length();
+
+		for (int32 i = 0; i < count; i++) {
+			BString element(StringAt(i));
+			if (length == element.Length() && string.ICompare(element) == 0)
+				return true;
+		}
+	} else {
+		for (int32 i = 0; i < count; i++) {
+			if (string == StringAt(i))
+				return true;
+		}
+	}
+
+	return false;
+}
+
+
+int32
+BStringList::CountStrings() const
+{
+	return fStrings.CountItems();
+}
+
+
+bool
+BStringList::IsEmpty() const
+{
+	return fStrings.IsEmpty();
+}
+
+
+void
+BStringList::DoForEach(bool (*func)(const BString& string))
+{
+	int32 count = fStrings.CountItems();
+	for (int32 i = 0; i < count; i++)
+		func(StringAt(i));
+}
+
+
+void
+BStringList::DoForEach(bool (*func)(const BString& string, void* arg2),
+	void* arg2)
+{
+	int32 count = fStrings.CountItems();
+	for (int32 i = 0; i < count; i++)
+		func(StringAt(i), arg2);
+}
+
+
+BStringList&
+BStringList::operator=(const BStringList& other)
+{
+	if (this != &other) {
+		_DecrementRefCounts();
+		fStrings = other.fStrings;
+		_IncrementRefCounts();
+	}
+
+	return *this;
+}
+
+
+bool
+BStringList::operator==(const BStringList& other) const
+{
+	if (this == &other)
+		return true;
+
+	int32 count = fStrings.CountItems();
+	if (count != other.fStrings.CountItems())
+		return false;
+
+	for (int32 i = 0; i < count; i++) {
+		if (StringAt(i) != other.StringAt(i))
+			return false;
+	}
+
+	return true;
+}
+
+
+void
+BStringList::_IncrementRefCounts() const
+{
+	int32 count = fStrings.CountItems();
+	for (int32 i = 0; i < count; i++) {
+		BString::Private::IncrementDataRefCount((char*)fStrings.ItemAt(i));
+	}
+}
+
+
+void
+BStringList::_DecrementRefCounts() const
+{
+	int32 count = fStrings.CountItems();
+	for (int32 i = 0; i < count; i++)
+		BString::Private::DecrementDataRefCount((char*)fStrings.ItemAt(i));
+}

From 2021c9842e1e61a3bf0f6550725ec3baf53d44b1 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 16 Jul 2011 16:36:36 +0200
Subject: [PATCH 0300/1170] Use BStringList in package kit

Replace all instances of BObjectList by BStringList.
---
 headers/os/package/PackageInfo.h              | 21 +++---
 headers/os/package/PackageRoster.h            |  4 +-
 headers/os/package/RepositoryInfo.h           | 10 +--
 src/bin/package_repo/command_list.cpp         |  6 +-
 src/bin/pkgman/command_list_repos.cpp         |  6 +-
 src/bin/pkgman/command_refresh.cpp            | 12 ++--
 src/kits/package/PackageInfo.cpp              | 65 +++++++------------
 src/kits/package/PackageRoster.cpp            | 14 ++--
 src/kits/package/RepositoryInfo.cpp           | 27 +++-----
 src/kits/package/hpkg/PackageWriterImpl.cpp   |  6 +-
 .../package/hpkg/RepositoryWriterImpl.cpp     |  9 ++-
 src/kits/package/hpkg/WriterImplBase.cpp      | 34 +++++-----
 12 files changed, 89 insertions(+), 125 deletions(-)

diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h
index e62136dd9d..9554a209f9 100644
--- a/headers/os/package/PackageInfo.h
+++ b/headers/os/package/PackageInfo.h
@@ -8,6 +8,7 @@
 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -68,10 +69,10 @@ public:
 
 			const BPackageVersion&	Version() const;
 
-			const BObjectList&	CopyrightList() const;
-			const BObjectList&	LicenseList() const;
-			const BObjectList&	URLList() const;
-			const BObjectList&	SourceURLList() const;
+			const BStringList&	CopyrightList() const;
+			const BStringList&	LicenseList() const;
+			const BStringList&	URLList() const;
+			const BStringList&	SourceURLList() const;
 
 			const BObjectList&	ProvidesList() const;
 			const BObjectList&
@@ -82,7 +83,7 @@ public:
 								ConflictsList() const;
 			const BObjectList&
 								FreshensList() const;
-			const BObjectList&	ReplacesList() const;
+			const BStringList&	ReplacesList() const;
 
 			void				SetName(const BString& name);
 			void				SetSummary(const BString& summary);
@@ -159,10 +160,10 @@ private:
 
 			BPackageVersion		fVersion;
 
-			BObjectList	fCopyrightList;
-			BObjectList	fLicenseList;
-			BObjectList	fURLList;
-			BObjectList	fSourceURLList;
+			BStringList			fCopyrightList;
+			BStringList			fLicenseList;
+			BStringList			fURLList;
+			BStringList			fSourceURLList;
 
 			BObjectList	fProvidesList;
 
@@ -173,7 +174,7 @@ private:
 
 			BObjectList	fFreshensList;
 
-			BObjectList	fReplacesList;
+			BStringList			fReplacesList;
 
 			BString				fChecksum;
 			BString				fInstallPath;
diff --git a/headers/os/package/PackageRoster.h b/headers/os/package/PackageRoster.h
index 1bb452468e..9178b50cf9 100644
--- a/headers/os/package/PackageRoster.h
+++ b/headers/os/package/PackageRoster.h
@@ -11,7 +11,7 @@
 #include 
 
 
-template  class BObjectList;
+class BStringList;
 
 
 namespace BPackageKit {
@@ -45,7 +45,7 @@ public:
 			status_t			GetUserRepositoryConfigPath(BPath* path,
 									bool create = false) const;
 
-			status_t			GetRepositoryNames(BObjectList& names);
+			status_t			GetRepositoryNames(BStringList& names);
 
 			status_t			VisitCommonRepositoryConfigs(
 									BRepositoryConfigVisitor& visitor);
diff --git a/headers/os/package/RepositoryInfo.h b/headers/os/package/RepositoryInfo.h
index f84a815ff4..b74f01780b 100644
--- a/headers/os/package/RepositoryInfo.h
+++ b/headers/os/package/RepositoryInfo.h
@@ -8,7 +8,7 @@
 
 #include 
 #include 
-#include 
+#include 
 #include 
 
 #include 
@@ -38,8 +38,8 @@ public:
 			const BString&		Summary() const;
 			uint8				Priority() const;
 			BPackageArchitecture	Architecture() const;
-			const BObjectList&	LicenseNames() const;
-			const BObjectList&	LicenseTexts() const;
+			const BStringList&	LicenseNames() const;
+			const BStringList&	LicenseTexts() const;
 
 			void				SetName(const BString& name);
 			void				SetOriginalBaseURL(const BString& url);
@@ -75,8 +75,8 @@ private:
 			BString				fSummary;
 			uint8				fPriority;
 			BPackageArchitecture	fArchitecture;
-			BObjectList	fLicenseNames;
-			BObjectList	fLicenseTexts;
+			BStringList			fLicenseNames;
+			BStringList			fLicenseTexts;
 };
 
 
diff --git a/src/bin/package_repo/command_list.cpp b/src/bin/package_repo/command_list.cpp
index c1ff03b683..0745b59fe2 100644
--- a/src/bin/package_repo/command_list.cpp
+++ b/src/bin/package_repo/command_list.cpp
@@ -214,11 +214,11 @@ struct RepositoryContentListHandler : BRepositoryContentHandler {
 		printf("\tpriority: %u\n", repositoryInfo.Priority());
 		printf("\tarchitecture: %s\n",
 			BPackageInfo::kArchitectureNames[repositoryInfo.Architecture()]);
-		const BObjectList licenseNames = repositoryInfo.LicenseNames();
+		const BStringList licenseNames = repositoryInfo.LicenseNames();
 		if (!licenseNames.IsEmpty()) {
 			printf("\tlicenses:\n");
-			for (int i = 0; i < licenseNames.CountItems(); ++i)
-				printf("\t\t%s\n", licenseNames.ItemAt(i)->String());
+			for (int i = 0; i < licenseNames.CountStrings(); ++i)
+				printf("\t\t%s\n", licenseNames.StringAt(i).String());
 		}
 
 		return B_OK;
diff --git a/src/bin/pkgman/command_list_repos.cpp b/src/bin/pkgman/command_list_repos.cpp
index 7df6012571..244404dca2 100644
--- a/src/bin/pkgman/command_list_repos.cpp
+++ b/src/bin/pkgman/command_list_repos.cpp
@@ -82,14 +82,14 @@ command_list_repos(int argc, const char* const* argv)
 	if (argc != optind)
 		print_command_usage_and_exit(true);
 
-	BObjectList repositoryNames(20, true);
+	BStringList repositoryNames(20);
 	BPackageRoster roster;
 	status_t result = roster.GetRepositoryNames(repositoryNames);
 	if (result != B_OK)
 		DIE(result, "can't collect repository names");
 
-	for (int i = 0; i < repositoryNames.CountItems(); ++i) {
-		const BString& repoName = *(repositoryNames.ItemAt(i));
+	for (int i = 0; i < repositoryNames.CountStrings(); ++i) {
+		const BString& repoName = repositoryNames.StringAt(i);
 		BRepositoryConfig repoConfig;
 		result = roster.GetRepositoryConfig(repoName, &repoConfig);
 		if (result != B_OK) {
diff --git a/src/bin/pkgman/command_refresh.cpp b/src/bin/pkgman/command_refresh.cpp
index 7118fa9f8d..176f5d2878 100644
--- a/src/bin/pkgman/command_refresh.cpp
+++ b/src/bin/pkgman/command_refresh.cpp
@@ -9,7 +9,7 @@
 #include 
 
 #include 
-#include 
+#include 
 
 #include 
 #include 
@@ -74,7 +74,7 @@ command_refresh(int argc, const char* const* argv)
 	JobStateListener listener;
 	BContext context(decisionProvider, listener);
 
-	BObjectList repositoryNames(20, true);
+	BStringList repositoryNames(20);
 
 	BPackageRoster roster;
 	if (nameCount == 0) {
@@ -83,16 +83,14 @@ command_refresh(int argc, const char* const* argv)
 			DIE(result, "can't collect repository names");
 	} else {
 		for (int i = 0; i < nameCount; ++i) {
-			BString* repoName = new (std::nothrow) BString(repoArgs[i]);
-			if (repoName == NULL)
+			if (!repositoryNames.Add(repoArgs[i]))
 				DIE(B_NO_MEMORY, "can't allocate repository name");
-			repositoryNames.AddItem(repoName);
 		}
 	}
 
 	status_t result;
-	for (int i = 0; i < repositoryNames.CountItems(); ++i) {
-		const BString& repoName = *(repositoryNames.ItemAt(i));
+	for (int i = 0; i < repositoryNames.CountStrings(); ++i) {
+		const BString& repoName = repositoryNames.StringAt(i);
 		BRepositoryConfig repoConfig;
 		result = roster.GetRepositoryConfig(repoName, &repoConfig);
 		if (result != B_OK) {
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 024a411fd8..f24bd9201f 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -81,7 +81,7 @@ private:
 									bool releaseIsOptional);
 			void				_ParseList(ListElementParser& elementParser,
 									bool allowSingleNonListElement);
-			void				_ParseStringList(BObjectList* value,
+			void				_ParseStringList(BStringList* value,
 									bool allowQuotedStrings = true,
 									bool convertToLowerCase = false);
 			void				_ParseResolvableList(
@@ -449,15 +449,15 @@ BPackageInfo::Parser::_ParseList(ListElementParser& elementParser,
 
 
 void
-BPackageInfo::Parser::_ParseStringList(BObjectList* value,
+BPackageInfo::Parser::_ParseStringList(BStringList* value,
 	bool allowQuotedStrings, bool convertToLowerCase)
 {
 	struct StringParser : public ListElementParser {
-		BObjectList* value;
+		BStringList* value;
 		bool allowQuotedStrings;
 		bool convertToLowerCase;
 
-		StringParser(BObjectList* value, bool allowQuotedStrings,
+		StringParser(BStringList* value, bool allowQuotedStrings,
 			bool convertToLowerCase)
 			:
 			value(value),
@@ -479,11 +479,11 @@ BPackageInfo::Parser::_ParseStringList(BObjectList* value,
 					throw ParseError("expected word", token.pos);
 			}
 
-			BString* element = new BString(token.text);
+			BString element(token.text);
 			if (convertToLowerCase)
-				element->ToLower();
+				element.ToLower();
 
-			value->AddItem(element);
+			value->Add(element);
 		}
 	} stringParser(value, allowQuotedStrings, convertToLowerCase);
 
@@ -831,16 +831,16 @@ BPackageInfo::BPackageInfo()
 	:
 	fFlags(0),
 	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
-	fCopyrightList(5, true),
-	fLicenseList(5, true),
-	fURLList(5, true),
-	fSourceURLList(5, true),
+	fCopyrightList(5),
+	fLicenseList(5),
+	fURLList(5),
+	fSourceURLList(5),
 	fProvidesList(20, true),
 	fRequiresList(20, true),
 	fSupplementsList(20, true),
 	fConflictsList(5, true),
 	fFreshensList(5, true),
-	fReplacesList(5, true)
+	fReplacesList(5)
 {
 }
 
@@ -989,28 +989,28 @@ BPackageInfo::Version() const
 }
 
 
-const BObjectList&
+const BStringList&
 BPackageInfo::CopyrightList() const
 {
 	return fCopyrightList;
 }
 
 
-const BObjectList&
+const BStringList&
 BPackageInfo::LicenseList() const
 {
 	return fLicenseList;
 }
 
 
-const BObjectList&
+const BStringList&
 BPackageInfo::URLList() const
 {
 	return fURLList;
 }
 
 
-const BObjectList&
+const BStringList&
 BPackageInfo::SourceURLList() const
 {
 	return fSourceURLList;
@@ -1052,7 +1052,7 @@ BPackageInfo::FreshensList() const
 }
 
 
-const BObjectList&
+const BStringList&
 BPackageInfo::ReplacesList() const
 {
 	return fReplacesList;
@@ -1140,11 +1140,7 @@ BPackageInfo::ClearCopyrightList()
 status_t
 BPackageInfo::AddCopyright(const BString& copyright)
 {
-	BString* newCopyright = new (std::nothrow) BString(copyright);
-	if (newCopyright == NULL)
-		return B_NO_MEMORY;
-
-	return fCopyrightList.AddItem(newCopyright) ? B_OK : B_ERROR;
+	return fCopyrightList.Add(copyright) ? B_OK : B_ERROR;
 }
 
 
@@ -1158,11 +1154,7 @@ BPackageInfo::ClearLicenseList()
 status_t
 BPackageInfo::AddLicense(const BString& license)
 {
-	BString* newLicense = new (std::nothrow) BString(license);
-	if (newLicense == NULL)
-		return B_NO_MEMORY;
-
-	return fLicenseList.AddItem(newLicense) ? B_OK : B_ERROR;
+	return fLicenseList.Add(license) ? B_OK : B_ERROR;
 }
 
 
@@ -1176,11 +1168,7 @@ BPackageInfo::ClearURLList()
 status_t
 BPackageInfo::AddURL(const BString& url)
 {
-	BString* newURL = new (std::nothrow) BString(url);
-	if (newURL == NULL)
-		return B_NO_MEMORY;
-
-	return fURLList.AddItem(newURL) ? B_OK : B_NO_MEMORY;
+	return fURLList.Add(url) ? B_OK : B_NO_MEMORY;
 }
 
 
@@ -1194,11 +1182,7 @@ BPackageInfo::ClearSourceURLList()
 status_t
 BPackageInfo::AddSourceURL(const BString& url)
 {
-	BString* newURL = new (std::nothrow) BString(url);
-	if (newURL == NULL)
-		return B_NO_MEMORY;
-
-	return fSourceURLList.AddItem(newURL) ? B_OK : B_NO_MEMORY;
+	return fSourceURLList.Add(url) ? B_OK : B_NO_MEMORY;
 }
 
 
@@ -1307,12 +1291,7 @@ BPackageInfo::ClearReplacesList()
 status_t
 BPackageInfo::AddReplaces(const BString& replaces)
 {
-	BString* newReplaces = new (std::nothrow) BString(replaces);
-	if (newReplaces == NULL)
-		return B_NO_MEMORY;
-
-	newReplaces->ToLower();
-	return fReplacesList.AddItem(newReplaces) ? B_OK : B_ERROR;
+	return fReplacesList.Add(BString(replaces).ToLower()) ? B_OK : B_ERROR;
 }
 
 
diff --git a/src/kits/package/PackageRoster.cpp b/src/kits/package/PackageRoster.cpp
index ce6edc9fc9..0fb31b535f 100644
--- a/src/kits/package/PackageRoster.cpp
+++ b/src/kits/package/PackageRoster.cpp
@@ -14,9 +14,9 @@
 
 #include 
 #include 
-#include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -89,10 +89,10 @@ BPackageRoster::VisitUserRepositoryConfigs(BRepositoryConfigVisitor& visitor)
 
 
 status_t
-BPackageRoster::GetRepositoryNames(BObjectList& names)
+BPackageRoster::GetRepositoryNames(BStringList& names)
 {
 	struct RepositoryNameCollector : public BRepositoryConfigVisitor {
-		RepositoryNameCollector(BObjectList& _names)
+		RepositoryNameCollector(BStringList& _names)
 			: names(_names)
 		{
 		}
@@ -102,15 +102,15 @@ BPackageRoster::GetRepositoryNames(BObjectList& names)
 			status_t result = entry.GetName(name);
 			if (result != B_OK)
 				return result;
-			int32 count = names.CountItems();
+			int32 count = names.CountStrings();
 			for (int i = 0; i < count; ++i) {
-				if (names.ItemAt(i)->Compare(name) == 0)
+				if (names.StringAt(i).Compare(name) == 0)
 					return B_OK;
 			}
-			names.AddItem(new (std::nothrow) BString(name));
+			names.Add(name);
 			return B_OK;
 		}
-		BObjectList& names;
+		BStringList& names;
 	};
 	RepositoryNameCollector repositoryNameCollector(names);
 	status_t result = VisitUserRepositoryConfigs(repositoryNameCollector);
diff --git a/src/kits/package/RepositoryInfo.cpp b/src/kits/package/RepositoryInfo.cpp
index 94065c0016..1ef4d40c4a 100644
--- a/src/kits/package/RepositoryInfo.cpp
+++ b/src/kits/package/RepositoryInfo.cpp
@@ -47,7 +47,7 @@ BRepositoryInfo::BRepositoryInfo()
 BRepositoryInfo::BRepositoryInfo(BMessage* data)
 	:
 	inherited(data),
-	fLicenseTexts(5, true)
+	fLicenseTexts(5)
 {
 	fInitStatus = SetTo(data);
 }
@@ -94,13 +94,13 @@ BRepositoryInfo::Archive(BMessage* data, bool deep) const
 		return result;
 	if ((result = data->AddUInt8(kArchitectureField, fArchitecture)) != B_OK)
 		return result;
-	for (int i = 0; i < fLicenseNames.CountItems(); ++i) {
-		result = data->AddString(kLicenseNameField, *fLicenseNames.ItemAt(i));
+	for (int i = 0; i < fLicenseNames.CountStrings(); ++i) {
+		result = data->AddString(kLicenseNameField, fLicenseNames.StringAt(i));
 		if (result != B_OK)
 			return result;
 	}
-	for (int i = 0; i < fLicenseTexts.CountItems(); ++i) {
-		result = data->AddString(kLicenseTextField, *fLicenseTexts.ItemAt(i));
+	for (int i = 0; i < fLicenseTexts.CountStrings(); ++i) {
+		result = data->AddString(kLicenseTextField, fLicenseTexts.StringAt(i));
 		if (result != B_OK)
 			return result;
 	}
@@ -146,11 +146,7 @@ BRepositoryInfo::SetTo(const BMessage* data)
 		data->FindString(kLicenseNameField, i, &licenseName) == B_OK
 			&& data->FindString(kLicenseTextField, i, &licenseText) == B_OK;
 		++i) {
-		BString* newLicenseName = new (std::nothrow) BString(licenseName);
-		if (newLicenseName == NULL || !fLicenseNames.AddItem(newLicenseName))
-			return B_NO_MEMORY;
-		BString* newLicenseText = new (std::nothrow) BString(licenseText);
-		if (newLicenseText == NULL || !fLicenseTexts.AddItem(newLicenseText))
+		if (!fLicenseNames.Add(licenseName) || !fLicenseTexts.Add(licenseText))
 			return B_NO_MEMORY;
 	}
 
@@ -269,14 +265,14 @@ BRepositoryInfo::Architecture() const
 }
 
 
-const BObjectList&
+const BStringList&
 BRepositoryInfo::LicenseNames() const
 {
 	return fLicenseNames;
 }
 
 
-const BObjectList&
+const BStringList&
 BRepositoryInfo::LicenseTexts() const
 {
 	return fLicenseTexts;
@@ -329,12 +325,7 @@ status_t
 BRepositoryInfo::AddLicense(const BString& licenseName,
 	const BString& licenseText)
 {
-	BString* newLicenseName = new (std::nothrow) BString(licenseName);
-	if (newLicenseName == NULL || !fLicenseNames.AddItem(newLicenseName))
-		return B_NO_MEMORY;
-
-	BString* newLicenseText = new (std::nothrow) BString(licenseText);
-	if (newLicenseText == NULL || !fLicenseTexts.AddItem(newLicenseText))
+	if (!fLicenseNames.Add(licenseName) || !fLicenseTexts.Add(licenseText))
 		return B_NO_MEMORY;
 
 	return B_OK;
diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index 06710867a3..b838e18ff7 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -681,9 +681,9 @@ PackageWriterImpl::_CheckLicenses()
 
 	BDirectory systemLicenseDir(systemLicensePath.Path());
 
-	const BObjectList& licenseList = fPackageInfo.LicenseList();
-	for (int i = 0; i < licenseList.CountItems(); ++i) {
-		const BString& licenseName = *licenseList.ItemAt(i);
+	const BStringList& licenseList = fPackageInfo.LicenseList();
+	for (int i = 0; i < licenseList.CountStrings(); ++i) {
+		const BString& licenseName = licenseList.StringAt(i);
 		if (licenseName == kPublicDomainLicenseName)
 			continue;
 
diff --git a/src/kits/package/hpkg/RepositoryWriterImpl.cpp b/src/kits/package/hpkg/RepositoryWriterImpl.cpp
index 7e9ba2499c..f6e28e7d7f 100644
--- a/src/kits/package/hpkg/RepositoryWriterImpl.cpp
+++ b/src/kits/package/hpkg/RepositoryWriterImpl.cpp
@@ -119,10 +119,9 @@ struct PackageContentHandler : public BPackageContentHandler {
 			return B_OK;
 
 		// check if license already is in repository
-		const BObjectList& licenseNames
-			= fRepositoryInfo->LicenseNames();
-		for (int i = 0; i < licenseNames.CountItems(); ++i) {
-			if (licenseNames.ItemAt(i)->ICompare(entry->Name()) == 0) {
+		const BStringList& licenseNames = fRepositoryInfo->LicenseNames();
+		for (int i = 0; i < licenseNames.CountStrings(); ++i) {
+			if (licenseNames.StringAt(i).ICompare(entry->Name()) == 0) {
 				// license already exists
 				return B_OK;
 			}
@@ -365,7 +364,7 @@ RepositoryWriterImpl::_Finish()
 		sizeof(header) + infoLengthCompressed, packagesLengthCompressed);
 
 	fListener->OnRepositoryDone(sizeof(header), infoLengthCompressed,
-		fRepositoryInfo->LicenseNames().CountItems(), fPackageCount,
+		fRepositoryInfo->LicenseNames().CountStrings(), fPackageCount,
 		packagesLengthCompressed, totalSize);
 
 	// general
diff --git a/src/kits/package/hpkg/WriterImplBase.cpp b/src/kits/package/hpkg/WriterImplBase.cpp
index e308190f8c..b5b01840a7 100644
--- a/src/kits/package/hpkg/WriterImplBase.cpp
+++ b/src/kits/package/hpkg/WriterImplBase.cpp
@@ -417,46 +417,43 @@ WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList,
 	RegisterPackageVersion(attributeList, packageInfo.Version());
 
 	// copyright list
-	const BObjectList& copyrightList = packageInfo.CopyrightList();
-	for (int i = 0; i < copyrightList.CountItems(); ++i) {
+	const BStringList& copyrightList = packageInfo.CopyrightList();
+	for (int i = 0; i < copyrightList.CountStrings(); ++i) {
 		PackageAttribute* copyright = new PackageAttribute(
 			B_HPKG_ATTRIBUTE_ID_PACKAGE_COPYRIGHT, B_HPKG_ATTRIBUTE_TYPE_STRING,
 			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
-		copyright->string
-			= fPackageStringCache.Get(copyrightList.ItemAt(i)->String());
+		copyright->string = fPackageStringCache.Get(copyrightList.StringAt(i));
 		attributeList.Add(copyright);
 	}
 
 	// license list
-	const BObjectList& licenseList = packageInfo.LicenseList();
-	for (int i = 0; i < licenseList.CountItems(); ++i) {
+	const BStringList& licenseList = packageInfo.LicenseList();
+	for (int i = 0; i < licenseList.CountStrings(); ++i) {
 		PackageAttribute* license = new PackageAttribute(
 			B_HPKG_ATTRIBUTE_ID_PACKAGE_LICENSE, B_HPKG_ATTRIBUTE_TYPE_STRING,
 			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
-		license->string
-			= fPackageStringCache.Get(licenseList.ItemAt(i)->String());
+		license->string = fPackageStringCache.Get(licenseList.StringAt(i));
 		attributeList.Add(license);
 	}
 
 	// URL list
-	const BObjectList& urlList = packageInfo.URLList();
-	for (int i = 0; i < urlList.CountItems(); ++i) {
+	const BStringList& urlList = packageInfo.URLList();
+	for (int i = 0; i < urlList.CountStrings(); ++i) {
 		PackageAttribute* url = new PackageAttribute(
 			B_HPKG_ATTRIBUTE_ID_PACKAGE_URL, B_HPKG_ATTRIBUTE_TYPE_STRING,
 			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
-		url->string = fPackageStringCache.Get(urlList.ItemAt(i)->String());
+		url->string = fPackageStringCache.Get(urlList.StringAt(i));
 		attributeList.Add(url);
 	}
 
 	// source URL list
-	const BObjectList& sourceURLList = packageInfo.SourceURLList();
-	for (int i = 0; i < sourceURLList.CountItems(); ++i) {
+	const BStringList& sourceURLList = packageInfo.SourceURLList();
+	for (int i = 0; i < sourceURLList.CountStrings(); ++i) {
 		PackageAttribute* url = new PackageAttribute(
 			B_HPKG_ATTRIBUTE_ID_PACKAGE_SOURCE_URL,
 			B_HPKG_ATTRIBUTE_TYPE_STRING,
 			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
-		url->string = fPackageStringCache.Get(
-			sourceURLList.ItemAt(i)->String());
+		url->string = fPackageStringCache.Get(sourceURLList.StringAt(i));
 		attributeList.Add(url);
 	}
 
@@ -508,13 +505,12 @@ WriterImplBase::RegisterPackageInfo(PackageAttributeList& attributeList,
 		packageInfo.FreshensList(), B_HPKG_ATTRIBUTE_ID_PACKAGE_FRESHENS);
 
 	// replaces list
-	const BObjectList& replacesList = packageInfo.ReplacesList();
-	for (int i = 0; i < replacesList.CountItems(); ++i) {
+	const BStringList& replacesList = packageInfo.ReplacesList();
+	for (int i = 0; i < replacesList.CountStrings(); ++i) {
 		PackageAttribute* replaces = new PackageAttribute(
 			B_HPKG_ATTRIBUTE_ID_PACKAGE_REPLACES, B_HPKG_ATTRIBUTE_TYPE_STRING,
 			B_HPKG_ATTRIBUTE_ENCODING_STRING_TABLE);
-		replaces->string
-			= fPackageStringCache.Get(replacesList.ItemAt(i)->String());
+		replaces->string = fPackageStringCache.Get(replacesList.StringAt(i));
 		attributeList.Add(replaces);
 	}
 

From f195cdc8c0274c685edc51cc0513d6066da49fd6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 16 Jul 2011 21:45:56 +0200
Subject: [PATCH 0301/1170] Removed left-over code

---
 src/kits/package/hpkg/PackageWriterImpl.cpp | 5 -----
 1 file changed, 5 deletions(-)

diff --git a/src/kits/package/hpkg/PackageWriterImpl.cpp b/src/kits/package/hpkg/PackageWriterImpl.cpp
index b838e18ff7..023f7a8803 100644
--- a/src/kits/package/hpkg/PackageWriterImpl.cpp
+++ b/src/kits/package/hpkg/PackageWriterImpl.cpp
@@ -167,11 +167,6 @@ struct PackageWriterImpl::PackageContentHandler
 	{
 	}
 
-static const char* AttributeNameForID(uint8 id)
-{
-	return BLowLevelPackageContentHandler::AttributeNameForID(id);
-}
-
 	virtual status_t HandleSectionStart(BHPKGPackageSectionID sectionID,
 		bool& _handleSection)
 	{

From db9a50a2c6ecaf7ce4d89595968cfaac2dc5885f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 16 Jul 2011 23:11:25 +0200
Subject: [PATCH 0302/1170] Pull class BPackageInfoSet out of BRepositoryCache

---
 headers/build/os/package/PackageInfoSet.h |   2 +
 headers/os/package/PackageInfoSet.h       |  66 ++++++
 headers/os/package/RepositoryCache.h      |  32 +--
 src/build/libpackage/Jamfile              |   1 +
 src/kits/package/Jamfile                  |   1 +
 src/kits/package/PackageInfoSet.cpp       | 241 ++++++++++++++++++++++
 src/kits/package/RepositoryCache.cpp      | 187 ++---------------
 7 files changed, 326 insertions(+), 204 deletions(-)
 create mode 100644 headers/build/os/package/PackageInfoSet.h
 create mode 100644 headers/os/package/PackageInfoSet.h
 create mode 100644 src/kits/package/PackageInfoSet.cpp

diff --git a/headers/build/os/package/PackageInfoSet.h b/headers/build/os/package/PackageInfoSet.h
new file mode 100644
index 0000000000..c775831aab
--- /dev/null
+++ b/headers/build/os/package/PackageInfoSet.h
@@ -0,0 +1,2 @@
+#include <../os/package/PackageInfoSet.h>
+
diff --git a/headers/os/package/PackageInfoSet.h b/headers/os/package/PackageInfoSet.h
new file mode 100644
index 0000000000..f2545ff73e
--- /dev/null
+++ b/headers/os/package/PackageInfoSet.h
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2011, Haiku, Inc.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE_PACKAGE_INFO_SET_H_
+#define _PACKAGE_PACKAGE_INFO_SET_H_
+
+
+#include 
+
+
+namespace BPackageKit {
+
+
+class BPackageInfo;
+
+
+class BPackageInfoSet {
+public:
+			class Iterator;
+
+public:
+								BPackageInfoSet();
+	virtual						~BPackageInfoSet();
+
+			status_t			Init();
+
+			status_t			AddInfo(const BPackageInfo& info);
+			void				MakeEmpty();
+
+			uint32				CountInfos() const;
+			Iterator			GetIterator() const;
+
+private:
+			struct PackageInfo;
+			struct PackageInfoHashDefinition;
+			struct PackageMap;
+
+			friend class Iterator;
+
+private:
+			PackageMap*			fPackageMap;
+};
+
+
+class BPackageInfoSet::Iterator {
+public:
+								Iterator();
+								Iterator(const BPackageInfoSet* set);
+
+			bool				HasNext() const;
+			const BPackageInfo*	Next();
+
+private:
+			friend class BRepositoryCache;
+
+private:
+			const BPackageInfoSet* fSet;
+			PackageInfo*		fNextInfo;
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif // _PACKAGE_PACKAGE_INFO_SET_H_
diff --git a/headers/os/package/RepositoryCache.h b/headers/os/package/RepositoryCache.h
index cb49150b25..3a1ee37de0 100644
--- a/headers/os/package/RepositoryCache.h
+++ b/headers/os/package/RepositoryCache.h
@@ -9,18 +9,16 @@
 #include 
 #include 
 
+#include 
 #include 
 
 
 namespace BPackageKit {
 
 
-class BPackageInfo;
-
-
 class BRepositoryCache {
 public:
-			class Iterator;
+			typedef BPackageInfoSet::Iterator Iterator;
 
 public:
 								BRepositoryCache();
@@ -38,39 +36,15 @@ public:
 			Iterator			GetIterator() const;
 
 private:
-			struct PackageInfo;
-			struct PackageInfoHashDefinition;
-			struct PackageMap;
 			struct RepositoryContentHandler;
 			struct StandardErrorOutput;
 
-			friend class Iterator;
-
 private:
 			BEntry				fEntry;
 			BRepositoryInfo		fInfo;
 			bool				fIsUserSpecific;
 
-			PackageMap*			fPackageMap;
-};
-
-
-class BRepositoryCache::Iterator {
-public:
-								Iterator();
-
-			bool				HasNext() const;
-			const BPackageInfo*	Next();
-
-private:
-								Iterator(const BRepositoryCache* cache);
-
-private:
-			friend class BRepositoryCache;
-
-private:
-			const BRepositoryCache* fCache;
-			PackageInfo*		fNextInfo;
+			BPackageInfoSet		fPackages;
 };
 
 
diff --git a/src/build/libpackage/Jamfile b/src/build/libpackage/Jamfile
index 1e0a27919c..3bccce80ba 100644
--- a/src/build/libpackage/Jamfile
+++ b/src/build/libpackage/Jamfile
@@ -68,6 +68,7 @@ BuildPlatformSharedLibrary libpackage_build.so
 	Job.cpp
 	JobQueue.cpp
 	PackageInfo.cpp
+	PackageInfoSet.cpp
 	PackageResolvable.cpp
 	PackageResolvableExpression.cpp
 	PackageRoster.cpp
diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile
index ab7a44ed93..309951fad7 100644
--- a/src/kits/package/Jamfile
+++ b/src/kits/package/Jamfile
@@ -55,6 +55,7 @@ SharedLibrary libpackage.so
 	Job.cpp
 	JobQueue.cpp
 	PackageInfo.cpp
+	PackageInfoSet.cpp
 	PackageResolvable.cpp
 	PackageResolvableExpression.cpp
 	PackageRoster.cpp
diff --git a/src/kits/package/PackageInfoSet.cpp b/src/kits/package/PackageInfoSet.cpp
new file mode 100644
index 0000000000..315cedcd92
--- /dev/null
+++ b/src/kits/package/PackageInfoSet.cpp
@@ -0,0 +1,241 @@
+/*
+ * Copyright 2011, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Oliver Tappe 
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+#include 
+
+#include 
+
+#include 
+
+
+namespace BPackageKit {
+
+
+// #pragma mark - PackageInfo
+
+
+struct BPackageInfoSet::PackageInfo : public BPackageInfo {
+	PackageInfo*	hashNext;
+	PackageInfo*	listNext;
+
+	PackageInfo(const BPackageInfo& other)
+		:
+		BPackageInfo(other),
+		listNext(NULL)
+	{
+	}
+};
+
+
+// #pragma mark - PackageInfoHashDefinition
+
+
+struct BPackageInfoSet::PackageInfoHashDefinition {
+	typedef const char*		KeyType;
+	typedef	PackageInfo		ValueType;
+
+	size_t HashKey(const char* key) const
+	{
+		return BString::HashValue(key);
+	}
+
+	size_t Hash(const PackageInfo* value) const
+	{
+		return value->Name().HashValue();
+	}
+
+	bool Compare(const char* key, const PackageInfo* value) const
+	{
+		return value->Name() == key;
+	}
+
+	PackageInfo*& GetLink(PackageInfo* value) const
+	{
+		return value->hashNext;
+	}
+};
+
+
+// #pragma mark - PackageMap
+
+
+struct BPackageInfoSet::PackageMap
+	: public BOpenHashTable {
+
+	PackageMap()
+		:
+		fCount(0)
+	{
+	}
+
+	~PackageMap()
+	{
+		PackageInfo* info = Clear(true);
+		while (info != NULL) {
+			PackageInfo* next = info->hashNext;
+			delete info;
+			info = next;
+		}
+	}
+
+	void AddPackageInfo(PackageInfo* info)
+	{
+		if (PackageInfo* oldInfo = Lookup(info->Name())) {
+			info->listNext = oldInfo->listNext;
+			oldInfo->listNext = info;
+		} else
+			Insert(info);
+
+		fCount++;
+	}
+
+	uint32 CountPackageInfos() const
+	{
+		return fCount;
+	}
+
+private:
+	uint32	fCount;
+};
+
+
+// #pragma mark - Iterator
+
+
+BPackageInfoSet::Iterator::Iterator()
+	:
+	fSet(NULL),
+	fNextInfo(NULL)
+{
+}
+
+
+BPackageInfoSet::Iterator::Iterator(const BPackageInfoSet* set)
+	:
+	fSet(set),
+	fNextInfo(fSet->fPackageMap->GetIterator().Next())
+{
+}
+
+bool
+BPackageInfoSet::Iterator::HasNext() const
+{
+	return fNextInfo != NULL;
+}
+
+
+const BPackageInfo*
+BPackageInfoSet::Iterator::Next()
+{
+	BPackageInfo* result = fNextInfo;
+
+	if (fNextInfo != NULL) {
+		if (fNextInfo->listNext != NULL) {
+			// get next in list
+			fNextInfo = fNextInfo->listNext;
+		} else {
+			// get next in hash table
+			PackageMap::Iterator iterator
+				= fSet->fPackageMap->GetIterator(fNextInfo->Name());
+			iterator.Next();
+			fNextInfo = iterator.Next();
+		}
+	}
+
+	return result;
+}
+
+
+// #pragma mark - BPackageInfoSet
+
+
+BPackageInfoSet::BPackageInfoSet()
+	:
+	fPackageMap(new(std::nothrow) PackageMap)
+{
+}
+
+
+BPackageInfoSet::~BPackageInfoSet()
+{
+	MakeEmpty();
+	delete fPackageMap;
+}
+
+
+status_t
+BPackageInfoSet::Init()
+{
+	return fPackageMap->Init();
+}
+
+
+status_t
+BPackageInfoSet::AddInfo(const BPackageInfo& _info)
+{
+	if (fPackageMap == NULL)
+		return B_NO_INIT;
+
+	PackageInfo* info = new(std::nothrow) PackageInfo(_info);
+	if (info == NULL)
+		return B_NO_MEMORY;
+
+	status_t error = info->InitCheck();
+	if (error != B_OK) {
+		delete info;
+		return error;
+	}
+
+	if (PackageInfo* oldInfo = fPackageMap->Lookup(info->Name())) {
+		// TODO: Check duplicates?
+		info->listNext = oldInfo->listNext;
+		oldInfo->listNext = info;
+	} else
+		fPackageMap->Insert(info);
+
+	return B_OK;
+}
+
+
+void
+BPackageInfoSet::MakeEmpty()
+{
+	if (fPackageMap == NULL)
+		return;
+
+	PackageInfo* info = fPackageMap->Clear(true);
+	while (info != NULL) {
+		PackageInfo* next = info->hashNext;
+		delete info;
+		info = next;
+	}
+}
+
+
+uint32
+BPackageInfoSet::CountInfos() const
+{
+	if (fPackageMap == NULL)
+		return 0;
+
+	return fPackageMap->CountPackageInfos();
+}
+
+
+BPackageInfoSet::Iterator
+BPackageInfoSet::GetIterator() const
+{
+	return Iterator(this);
+}
+
+
+}	// namespace BPackageKit
diff --git a/src/kits/package/RepositoryCache.cpp b/src/kits/package/RepositoryCache.cpp
index 811839c675..d6f5b2759b 100644
--- a/src/kits/package/RepositoryCache.cpp
+++ b/src/kits/package/RepositoryCache.cpp
@@ -18,13 +18,10 @@
 #include 
 #include 
 
-#include 
-
 #include 
 #include 
 #include 
 #include 
-#include 
 #include 
 #include 
 
@@ -32,107 +29,18 @@
 namespace BPackageKit {
 
 
-using BPrivate::HashableString;
 using namespace BHPKG;
 
 
-// #pragma mark - PackageInfo
-
-
-struct BRepositoryCache::PackageInfo : public BPackageInfo {
-	PackageInfo*	hashNext;
-	PackageInfo*	listNext;
-
-	PackageInfo(const BPackageInfo& other)
-		:
-		BPackageInfo(other),
-		listNext(NULL)
-	{
-	}
-};
-
-
-// #pragma mark - PackageInfoHashDefinition
-
-
-struct BRepositoryCache::PackageInfoHashDefinition {
-	typedef const char*		KeyType;
-	typedef	PackageInfo		ValueType;
-
-	size_t HashKey(const char* key) const
-	{
-		return BString::HashValue(key);
-	}
-
-	size_t Hash(const PackageInfo* value) const
-	{
-		return value->Name().HashValue();
-	}
-
-	bool Compare(const char* key, const PackageInfo* value) const
-	{
-		return value->Name() == key;
-	}
-
-	PackageInfo*& GetLink(PackageInfo* value) const
-	{
-		return value->hashNext;
-	}
-};
-
-
-// #pragma mark - PackageMap
-
-
-struct BRepositoryCache::PackageMap
-	: public BOpenHashTable {
-
-	PackageMap()
-		:
-		fCount(0)
-	{
-	}
-
-	~PackageMap()
-	{
-		PackageInfo* info = Clear(true);
-		while (info != NULL) {
-			PackageInfo* next = info->hashNext;
-			delete info;
-			info = next;
-		}
-	}
-
-	void AddPackageInfo(PackageInfo* info)
-	{
-		if (PackageInfo* oldInfo = Lookup(info->Name())) {
-			info->listNext = oldInfo->listNext;
-			oldInfo->listNext = info;
-		} else
-			Insert(info);
-
-		fCount++;
-	}
-
-	uint32 CountPackageInfos() const
-	{
-		return fCount;
-	}
-
-private:
-	uint32	fCount;
-};
-
-
 // #pragma mark - RepositoryContentHandler
 
 
 struct BRepositoryCache::RepositoryContentHandler : BRepositoryContentHandler {
 	RepositoryContentHandler(BRepositoryInfo* repositoryInfo,
-		PackageMap* packageMap)
+		BPackageInfoSet& packages)
 		:
 		fRepositoryInfo(repositoryInfo),
-		fPackageMap(packageMap)
+		fPackages(packages)
 	{
 	}
 
@@ -240,21 +148,9 @@ struct BRepositoryCache::RepositoryContentHandler : BRepositoryContentHandler {
 				if (result != B_OK)
 					return result;
 
-				PackageInfo* info = new(std::nothrow) PackageInfo(fPackageInfo);
-				if (info == NULL)
-					return B_NO_MEMORY;
-
-				result = info->InitCheck();
-				if (result != B_OK) {
-					delete info;
+				result = fPackages.AddInfo(fPackageInfo);
+				if (result != B_OK)
 					return result;
-				}
-
-				if (PackageInfo* oldInfo = fPackageMap->Lookup(info->Name())) {
-					info->listNext = oldInfo->listNext;
-					oldInfo->listNext = info;
-				} else
-					fPackageMap->Insert(info);
 
 				fPackageInfo.Clear();
 				break;
@@ -281,7 +177,7 @@ struct BRepositoryCache::RepositoryContentHandler : BRepositoryContentHandler {
 private:
 	BRepositoryInfo*	fRepositoryInfo;
 	BPackageInfo		fPackageInfo;
-	PackageMap*			fPackageMap;
+	BPackageInfoSet&	fPackages;
 };
 
 
@@ -296,67 +192,19 @@ class BRepositoryCache::StandardErrorOutput : public BErrorOutput {
 };
 
 
-// #pragma mark - Iterator
-
-
-BRepositoryCache::Iterator::Iterator()
-	:
-	fCache(NULL),
-	fNextInfo(NULL)
-{
-}
-
-
-BRepositoryCache::Iterator::Iterator(const BRepositoryCache* cache)
-	:
-	fCache(cache),
-	fNextInfo(fCache->fPackageMap->GetIterator().Next())
-{
-}
-
-bool
-BRepositoryCache::Iterator::HasNext() const
-{
-	return fNextInfo != NULL;
-}
-
-
-const BPackageInfo*
-BRepositoryCache::Iterator::Next()
-{
-	BPackageInfo* result = fNextInfo;
-
-	if (fNextInfo != NULL) {
-		if (fNextInfo->listNext != NULL) {
-			// get next in list
-			fNextInfo = fNextInfo->listNext;
-		} else {
-			// get next in hash table
-			PackageMap::Iterator iterator
-				= fCache->fPackageMap->GetIterator(fNextInfo->Name());
-			iterator.Next();
-			fNextInfo = iterator.Next();
-		}
-	}
-
-	return result;
-}
-
-
 // #pragma mark - BRepositoryCache
 
 
 BRepositoryCache::BRepositoryCache()
 	:
 	fIsUserSpecific(false),
-	fPackageMap(NULL)
+	fPackages()
 {
 }
 
 
 BRepositoryCache::~BRepositoryCache()
 {
-	delete fPackageMap;
 }
 
 
@@ -392,19 +240,11 @@ status_t
 BRepositoryCache::SetTo(const BEntry& entry)
 {
 	// unset
-	if (fPackageMap != NULL) {
-		delete fPackageMap;
-		fPackageMap = NULL;
-	}
-
+	fPackages.MakeEmpty();
 	fEntry.Unset();
 
-	// create the package map
-	fPackageMap = new (std::nothrow) PackageMap;
-	if (fPackageMap == NULL)
-		return B_NO_MEMORY;
-
-	status_t result = fPackageMap->Init();
+	// init package info set
+	status_t result = fPackages.Init();
 	if (result != B_OK)
 		return result;
 
@@ -421,7 +261,7 @@ BRepositoryCache::SetTo(const BEntry& entry)
 	if ((result = repositoryReader.Init(repositoryCachePath.Path())) != B_OK)
 		return result;
 
-	RepositoryContentHandler handler(&fInfo, fPackageMap);
+	RepositoryContentHandler handler(&fInfo, fPackages);
 	if ((result = repositoryReader.ParseContent(&handler)) != B_OK)
 		return result;
 
@@ -439,17 +279,14 @@ BRepositoryCache::SetTo(const BEntry& entry)
 uint32
 BRepositoryCache::CountPackages() const
 {
-	if (fPackageMap == NULL)
-		return 0;
-
-	return fPackageMap->CountPackageInfos();
+	return fPackages.CountInfos();
 }
 
 
 BRepositoryCache::Iterator
 BRepositoryCache::GetIterator() const
 {
-	return Iterator(this);
+	return fPackages.GetIterator();
 }
 
 

From 99ee453ff8ef9697a3755cee30dff7f0e01f37f1 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 16 Jul 2011 23:11:48 +0200
Subject: [PATCH 0303/1170] find_directory(): Fix package links path

---
 src/system/libroot/os/find_directory.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/system/libroot/os/find_directory.cpp b/src/system/libroot/os/find_directory.cpp
index 4cc257c53c..659b9f2546 100644
--- a/src/system/libroot/os/find_directory.cpp
+++ b/src/system/libroot/os/find_directory.cpp
@@ -349,7 +349,7 @@ find_directory(directory_which which, dev_t device, bool createIt,
 			templatePath = "utilities";
 			break;
 		case B_PACKAGE_LINKS_DIRECTORY:
-			templatePath = "package-links";
+			templatePath = "packages";
 			break;
 
 		default:

From 10b8f702768b083af8107f4418fdc910151d6d09 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 16 Jul 2011 23:15:16 +0200
Subject: [PATCH 0304/1170] Add class BPackageInfoContentHandler

A BPackageContentHandler subclass that initializes a BPackageInfo from
the read package attributes. Pulled out of RepositoryWriterImpl's
PackageContentHandler.
---
 .../os/package/PackageInfoContentHandler.h    |   1 +
 .../os/package/PackageInfoContentHandler.h    |  51 ++++++
 src/build/libpackage/Jamfile                  |   1 +
 src/kits/package/Jamfile                      |   1 +
 .../package/PackageInfoContentHandler.cpp     | 161 ++++++++++++++++++
 .../package/hpkg/RepositoryWriterImpl.cpp     | 105 +-----------
 6 files changed, 219 insertions(+), 101 deletions(-)
 create mode 100644 headers/build/os/package/PackageInfoContentHandler.h
 create mode 100644 headers/os/package/PackageInfoContentHandler.h
 create mode 100644 src/kits/package/PackageInfoContentHandler.cpp

diff --git a/headers/build/os/package/PackageInfoContentHandler.h b/headers/build/os/package/PackageInfoContentHandler.h
new file mode 100644
index 0000000000..2726b6bd0f
--- /dev/null
+++ b/headers/build/os/package/PackageInfoContentHandler.h
@@ -0,0 +1 @@
+#include <../os/package/PackageInfoContentHandler.h>
diff --git a/headers/os/package/PackageInfoContentHandler.h b/headers/os/package/PackageInfoContentHandler.h
new file mode 100644
index 0000000000..b186a0f94a
--- /dev/null
+++ b/headers/os/package/PackageInfoContentHandler.h
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2011, Haiku, Inc.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__PACKAGE_INFO_CONTENT_HANDLER_H_
+#define _PACKAGE__PACKAGE_INFO_CONTENT_HANDLER_H_
+
+
+#include 
+
+
+namespace BPackageKit {
+
+
+class BPackageInfo;
+
+
+namespace BHPKG {
+	class BErrorOutput;
+}
+
+
+class BPackageInfoContentHandler : public BHPKG::BPackageContentHandler {
+public:
+								BPackageInfoContentHandler(
+									BPackageInfo& packageInfo,
+									BHPKG::BErrorOutput* errorOutput = NULL);
+	virtual						~BPackageInfoContentHandler();
+
+	virtual	status_t			HandleEntry(BHPKG::BPackageEntry* entry);
+	virtual	status_t			HandleEntryAttribute(
+									BHPKG::BPackageEntry* entry,
+									BHPKG::BPackageEntryAttribute* attribute);
+	virtual	status_t			HandleEntryDone(BHPKG::BPackageEntry* entry);
+
+	virtual	status_t			HandlePackageAttribute(
+									const BHPKG::BPackageInfoAttributeValue&
+										value);
+
+	virtual	void				HandleErrorOccurred();
+
+protected:
+			BPackageInfo&		fPackageInfo;
+			BHPKG::BErrorOutput* fErrorOutput;
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif	// _PACKAGE__PACKAGE_INFO_CONTENT_HANDLER_H_
diff --git a/src/build/libpackage/Jamfile b/src/build/libpackage/Jamfile
index 3bccce80ba..7b7d56f72f 100644
--- a/src/build/libpackage/Jamfile
+++ b/src/build/libpackage/Jamfile
@@ -68,6 +68,7 @@ BuildPlatformSharedLibrary libpackage_build.so
 	Job.cpp
 	JobQueue.cpp
 	PackageInfo.cpp
+	PackageInfoContentHandler.cpp
 	PackageInfoSet.cpp
 	PackageResolvable.cpp
 	PackageResolvableExpression.cpp
diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile
index 309951fad7..a73037b36f 100644
--- a/src/kits/package/Jamfile
+++ b/src/kits/package/Jamfile
@@ -55,6 +55,7 @@ SharedLibrary libpackage.so
 	Job.cpp
 	JobQueue.cpp
 	PackageInfo.cpp
+	PackageInfoContentHandler.cpp
 	PackageInfoSet.cpp
 	PackageResolvable.cpp
 	PackageResolvableExpression.cpp
diff --git a/src/kits/package/PackageInfoContentHandler.cpp b/src/kits/package/PackageInfoContentHandler.cpp
new file mode 100644
index 0000000000..ecd6857dcd
--- /dev/null
+++ b/src/kits/package/PackageInfoContentHandler.cpp
@@ -0,0 +1,161 @@
+/*
+ * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include 
+
+#include 
+#include 
+#include 
+
+
+namespace BPackageKit {
+
+
+using namespace BHPKG;
+
+
+BPackageInfoContentHandler::BPackageInfoContentHandler(
+	BPackageInfo& packageInfo, BErrorOutput* errorOutput)
+	:
+	fPackageInfo(packageInfo),
+	fErrorOutput(errorOutput)
+{
+}
+
+
+BPackageInfoContentHandler::~BPackageInfoContentHandler()
+{
+}
+
+
+status_t
+BPackageInfoContentHandler::HandleEntry(BPackageEntry* entry)
+{
+	return B_OK;
+}
+
+
+status_t
+BPackageInfoContentHandler::HandleEntryAttribute(BPackageEntry* entry,
+	BPackageEntryAttribute* attribute)
+{
+	return B_OK;
+}
+
+
+status_t
+BPackageInfoContentHandler::HandleEntryDone(BPackageEntry* entry)
+{
+	return B_OK;
+}
+
+
+status_t
+BPackageInfoContentHandler::HandlePackageAttribute(
+	const BPackageInfoAttributeValue& value)
+{
+	switch (value.attributeID) {
+		case B_PACKAGE_INFO_NAME:
+			fPackageInfo.SetName(value.string);
+			break;
+
+		case B_PACKAGE_INFO_SUMMARY:
+			fPackageInfo.SetSummary(value.string);
+			break;
+
+		case B_PACKAGE_INFO_DESCRIPTION:
+			fPackageInfo.SetDescription(value.string);
+			break;
+
+		case B_PACKAGE_INFO_VENDOR:
+			fPackageInfo.SetVendor(value.string);
+			break;
+
+		case B_PACKAGE_INFO_PACKAGER:
+			fPackageInfo.SetPackager(value.string);
+			break;
+
+		case B_PACKAGE_INFO_FLAGS:
+			fPackageInfo.SetFlags(value.unsignedInt);
+			break;
+
+		case B_PACKAGE_INFO_ARCHITECTURE:
+			fPackageInfo.SetArchitecture(
+				(BPackageArchitecture)value.unsignedInt);
+			break;
+
+		case B_PACKAGE_INFO_VERSION:
+			fPackageInfo.SetVersion(value.version);
+			break;
+
+		case B_PACKAGE_INFO_COPYRIGHTS:
+			fPackageInfo.AddCopyright(value.string);
+			break;
+
+		case B_PACKAGE_INFO_LICENSES:
+			fPackageInfo.AddLicense(value.string);
+			break;
+
+		case B_PACKAGE_INFO_PROVIDES:
+			fPackageInfo.AddProvides(value.resolvable);
+			break;
+
+		case B_PACKAGE_INFO_REQUIRES:
+			fPackageInfo.AddRequires(value.resolvableExpression);
+			break;
+
+		case B_PACKAGE_INFO_SUPPLEMENTS:
+			fPackageInfo.AddSupplements(value.resolvableExpression);
+			break;
+
+		case B_PACKAGE_INFO_CONFLICTS:
+			fPackageInfo.AddConflicts(value.resolvableExpression);
+			break;
+
+		case B_PACKAGE_INFO_FRESHENS:
+			fPackageInfo.AddFreshens(value.resolvableExpression);
+			break;
+
+		case B_PACKAGE_INFO_REPLACES:
+			fPackageInfo.AddReplaces(value.string);
+			break;
+
+		case B_PACKAGE_INFO_URLS:
+			fPackageInfo.AddURL(value.string);
+			break;
+
+		case B_PACKAGE_INFO_SOURCE_URLS:
+			fPackageInfo.AddSourceURL(value.string);
+			break;
+
+		case B_PACKAGE_INFO_CHECKSUM:
+			fPackageInfo.SetChecksum(value.string);
+			break;
+
+		case B_PACKAGE_INFO_INSTALL_PATH:
+			fPackageInfo.SetInstallPath(value.string);
+			break;
+
+		default:
+			if (fErrorOutput != NULL) {
+				fErrorOutput->PrintError(
+					"Invalid package attribute section: unexpected package "
+					"attribute id %d encountered\n", value.attributeID);
+			}
+			return B_BAD_DATA;
+	}
+
+	return B_OK;
+}
+
+
+void
+BPackageInfoContentHandler::HandleErrorOccurred()
+{
+}
+
+
+}	// namespace BPackageKit
diff --git a/src/kits/package/hpkg/RepositoryWriterImpl.cpp b/src/kits/package/hpkg/RepositoryWriterImpl.cpp
index f6e28e7d7f..8cd6aa0b67 100644
--- a/src/kits/package/hpkg/RepositoryWriterImpl.cpp
+++ b/src/kits/package/hpkg/RepositoryWriterImpl.cpp
@@ -24,6 +24,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 
@@ -85,12 +86,11 @@ private:
 };
 
 
-struct PackageContentHandler : public BPackageContentHandler {
+struct PackageContentHandler : public BPackageInfoContentHandler {
 	PackageContentHandler(BErrorOutput* errorOutput, BPackageInfo* packageInfo,
 		int packageFileFD, BRepositoryInfo* repositoryInfo)
 		:
-		fErrorOutput(errorOutput),
-		fPackageInfo(packageInfo),
+		BPackageInfoContentHandler(*packageInfo, errorOutput),
 		fPackageFileReader(packageFileFD),
 		fRepositoryInfo(repositoryInfo)
 	{
@@ -100,7 +100,7 @@ struct PackageContentHandler : public BPackageContentHandler {
 	{
 		// if license must be approved, read any license files from package such
 		// that those can be stored in the repository later
-		if ((fPackageInfo->Flags() & B_PACKAGE_FLAG_APPROVE_LICENSE) == 0
+		if ((fPackageInfo.Flags() & B_PACKAGE_FLAG_APPROVE_LICENSE) == 0
 			|| entry == NULL)
 			return B_OK;
 
@@ -160,108 +160,11 @@ struct PackageContentHandler : public BPackageContentHandler {
 		return B_OK;
 	}
 
-	virtual status_t HandlePackageAttribute(
-		const BPackageInfoAttributeValue& value)
-	{
-		switch (value.attributeID) {
-			case B_PACKAGE_INFO_NAME:
-				fPackageInfo->SetName(value.string);
-				break;
-
-			case B_PACKAGE_INFO_SUMMARY:
-				fPackageInfo->SetSummary(value.string);
-				break;
-
-			case B_PACKAGE_INFO_DESCRIPTION:
-				fPackageInfo->SetDescription(value.string);
-				break;
-
-			case B_PACKAGE_INFO_VENDOR:
-				fPackageInfo->SetVendor(value.string);
-				break;
-
-			case B_PACKAGE_INFO_PACKAGER:
-				fPackageInfo->SetPackager(value.string);
-				break;
-
-			case B_PACKAGE_INFO_FLAGS:
-				fPackageInfo->SetFlags(value.unsignedInt);
-				break;
-
-			case B_PACKAGE_INFO_ARCHITECTURE:
-				fPackageInfo->SetArchitecture(
-					(BPackageArchitecture)value.unsignedInt);
-				break;
-
-			case B_PACKAGE_INFO_VERSION:
-				fPackageInfo->SetVersion(value.version);
-				break;
-
-			case B_PACKAGE_INFO_COPYRIGHTS:
-				fPackageInfo->AddCopyright(value.string);
-				break;
-
-			case B_PACKAGE_INFO_LICENSES:
-				fPackageInfo->AddLicense(value.string);
-				break;
-
-			case B_PACKAGE_INFO_PROVIDES:
-				fPackageInfo->AddProvides(value.resolvable);
-				break;
-
-			case B_PACKAGE_INFO_REQUIRES:
-				fPackageInfo->AddRequires(value.resolvableExpression);
-				break;
-
-			case B_PACKAGE_INFO_SUPPLEMENTS:
-				fPackageInfo->AddSupplements(value.resolvableExpression);
-				break;
-
-			case B_PACKAGE_INFO_CONFLICTS:
-				fPackageInfo->AddConflicts(value.resolvableExpression);
-				break;
-
-			case B_PACKAGE_INFO_FRESHENS:
-				fPackageInfo->AddFreshens(value.resolvableExpression);
-				break;
-
-			case B_PACKAGE_INFO_REPLACES:
-				fPackageInfo->AddReplaces(value.string);
-				break;
-
-			case B_PACKAGE_INFO_URLS:
-				fPackageInfo->AddURL(value.string);
-				break;
-
-			case B_PACKAGE_INFO_SOURCE_URLS:
-				fPackageInfo->AddSourceURL(value.string);
-				break;
-
-			case B_PACKAGE_INFO_CHECKSUM:
-				fPackageInfo->SetChecksum(value.string);
-				break;
-
-			case B_PACKAGE_INFO_INSTALL_PATH:
-				fPackageInfo->SetInstallPath(value.string);
-				break;
-
-			default:
-				fErrorOutput->PrintError(
-					"Invalid package attribute section: unexpected package "
-					"attribute id %d encountered\n", value.attributeID);
-				return B_BAD_DATA;
-		}
-
-		return B_OK;
-	}
-
 	virtual void HandleErrorOccurred()
 	{
 	}
 
 private:
-	BErrorOutput* 		fErrorOutput;
-	BPackageInfo* 		fPackageInfo;
 	BPackageReader*		fPackageReader;
 	BFDDataReader		fPackageFileReader;
 	BRepositoryInfo*	fRepositoryInfo;

From 8c29f587282dbe71860169bfe1c9832c659f14c0 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 16 Jul 2011 23:19:00 +0200
Subject: [PATCH 0305/1170] Add BPackageRoster::GetActivePackages()

The implementation is temporary. Currently it reads through the packages
in the respective packages directory and checks against the package
links. Once package activation is tracked explicitly we'll use the
activation file/directory.
---
 headers/build/os/package/PackageDefs.h |   2 +
 headers/os/package/PackageDefs.h       |  24 ++++++
 headers/os/package/PackageRoster.h     |   9 ++-
 src/kits/package/PackageRoster.cpp     | 101 +++++++++++++++++++++++++
 4 files changed, 135 insertions(+), 1 deletion(-)
 create mode 100644 headers/build/os/package/PackageDefs.h
 create mode 100644 headers/os/package/PackageDefs.h

diff --git a/headers/build/os/package/PackageDefs.h b/headers/build/os/package/PackageDefs.h
new file mode 100644
index 0000000000..7f036bc7ae
--- /dev/null
+++ b/headers/build/os/package/PackageDefs.h
@@ -0,0 +1,2 @@
+#include <../os/package/PackageDefs.h>
+
diff --git a/headers/os/package/PackageDefs.h b/headers/os/package/PackageDefs.h
new file mode 100644
index 0000000000..1f18345136
--- /dev/null
+++ b/headers/os/package/PackageDefs.h
@@ -0,0 +1,24 @@
+/*
+ * Copyright 2011, Haiku, Inc.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__PACKAGE_DEFS_H_
+#define _PACKAGE__PACKAGE_DEFS_H_
+
+
+namespace BPackageKit {
+
+
+enum BPackageInstallationLocation {
+	B_PACKAGE_INSTALLATION_LOCATION_SYSTEM,
+	B_PACKAGE_INSTALLATION_LOCATION_COMMON,
+	B_PACKAGE_INSTALLATION_LOCATION_HOME,
+
+	B_PACKAGE_INSTALLATION_LOCATION_ENUM_COUNT
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif // _PACKAGE__PACKAGE_DEFS_H_
diff --git a/headers/os/package/PackageRoster.h b/headers/os/package/PackageRoster.h
index 9178b50cf9..d407da7e38 100644
--- a/headers/os/package/PackageRoster.h
+++ b/headers/os/package/PackageRoster.h
@@ -10,6 +10,8 @@
 #include 
 #include 
 
+#include 
+
 
 class BStringList;
 
@@ -26,6 +28,7 @@ struct BRepositoryConfigVisitor {
 };
 
 
+class BPackageInfoSet;
 class BRepositoryCache;
 class BRepositoryConfig;
 
@@ -56,12 +59,16 @@ public:
 									BRepositoryCache* repositoryCache);
 			status_t			GetRepositoryConfig(const BString& name,
 									BRepositoryConfig* repositoryConfig);
+
+			status_t			GetActivePackages(
+									BPackageInstallationLocation location,
+									BPackageInfoSet& packageInfos);
+
 private:
 			status_t			_GetRepositoryPath(BPath* path, bool create,
 									directory_which whichDir) const;
 			status_t			_VisitRepositoryConfigs(const BPath& path,
 									BRepositoryConfigVisitor& visitor);
-
 };
 
 
diff --git a/src/kits/package/PackageRoster.cpp b/src/kits/package/PackageRoster.cpp
index 0fb31b535f..5ee0451718 100644
--- a/src/kits/package/PackageRoster.cpp
+++ b/src/kits/package/PackageRoster.cpp
@@ -18,13 +18,21 @@
 #include 
 #include 
 
+#include 
+#include 
+#include 
 #include 
 #include 
 
+#include 
+
 
 namespace BPackageKit {
 
 
+using namespace BHPKG;
+
+
 BPackageRoster::BPackageRoster()
 {
 }
@@ -175,6 +183,99 @@ BPackageRoster::GetRepositoryConfig(const BString& name,
 }
 
 
+status_t
+BPackageRoster::GetActivePackages(BPackageInstallationLocation location,
+	BPackageInfoSet& packageInfos)
+{
+// This method makes sense only on an installed Haiku, but not for the build
+// tools.
+#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
+	// check the given location
+	directory_which packagesDirectory;
+	switch (location) {
+		case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM:
+			packagesDirectory = B_SYSTEM_PACKAGES_DIRECTORY;
+			break;
+		case B_PACKAGE_INSTALLATION_LOCATION_COMMON:
+			packagesDirectory = B_COMMON_PACKAGES_DIRECTORY;
+			break;
+		case B_PACKAGE_INSTALLATION_LOCATION_HOME:
+			packagesDirectory = B_USER_PACKAGES_DIRECTORY;
+			break;
+		default:
+			return B_BAD_VALUE;
+	}
+
+	// find the package links directory
+	BPath packageLinksPath;
+	status_t error = find_directory(B_PACKAGE_LINKS_DIRECTORY,
+		&packageLinksPath);
+	if (error != B_OK)
+		return error;
+
+	// find and open the packages directory
+	BPath packagesDirPath;
+	error = find_directory(packagesDirectory, &packagesDirPath);
+	if (error != B_OK)
+		return error;
+
+	BDirectory directory;
+	error = directory.SetTo(packagesDirPath.Path());
+	if (error != B_OK)
+		return error;
+
+	// TODO: Implement that correctly be reading the activation files/directory!
+
+	// iterate through the packages
+	char buffer[sizeof(dirent) + B_FILE_NAME_LENGTH];
+	dirent* entry = (dirent*)&buffer;
+	while (directory.GetNextDirents(entry, sizeof(buffer), 1) == 1) {
+		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
+			continue;
+
+		// get the full package file path
+		BPath packagePath;
+		error = packagePath.SetTo(packagesDirPath.Path(), entry->d_name);
+		if (error != B_OK)
+			continue;
+
+		// read the package info from the file
+		BPackageReader packageReader(NULL);
+		error = packageReader.Init(packagePath.Path());
+		if (error != B_OK)
+			continue;
+
+		BPackageInfo info;
+		BPackageInfoContentHandler handler(info);
+		error = packageReader.ParseContent(&handler);
+		if (error != B_OK || info.InitCheck() != B_OK)
+			continue;
+
+		// check whether the package is really active by verifying that a
+		// package link exists for it
+		BString packageLinkName(info.Name());
+		packageLinkName << '-' << info.Version().ToString();
+		BPath packageLinkPath;
+		struct stat st;
+		if (packageLinkPath.SetTo(packageLinksPath.Path(), packageLinkName)
+				!= B_OK
+			|| lstat(packageLinkPath.Path(), &st) != 0) {
+			continue;
+		}
+
+		// add the info
+		error = packageInfos.AddInfo(info);
+		if (error != B_OK)
+			return error;
+	}
+
+	return B_OK;
+#else
+	return B_NOT_SUPPORTED;
+#endif
+}
+
+
 status_t
 BPackageRoster::_GetRepositoryPath(BPath* path, bool create,
 	directory_which whichDir) const

From e99df3a512431f30e07187454953b5d8f1a6b6e5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 17 Jul 2011 02:52:26 +0200
Subject: [PATCH 0306/1170] Fix build due to  move

Apparently I should have done a complete rebuild after moving
directories.h from headers/private/libroot to .../system, since a lot of
stuff didn't build anymore.
---
 headers/build/private/libroot/directories.h       |  1 -
 headers/build/private/system/directories.h        |  1 +
 .../kernel/drivers/audio/ac97/auich/Jamfile       |  3 ++-
 .../kernel/drivers/audio/ac97/auvia/Jamfile       |  3 ++-
 src/add-ons/kernel/drivers/audio/echo/3g/Jamfile  |  7 ++++---
 src/add-ons/kernel/drivers/audio/emuxki/Jamfile   |  3 ++-
 .../kernel/drivers/graphics/matrox/Jamfile        |  5 +++--
 .../kernel/drivers/graphics/neomagic/Jamfile      |  5 +++--
 .../kernel/drivers/graphics/nvidia/Jamfile        |  5 +++--
 src/add-ons/kernel/drivers/network/sis900/Jamfile | 15 ++++++++-------
 src/add-ons/kernel/generic/mpu401/Jamfile         |  2 +-
 src/build/libroot/Jamfile                         |  2 +-
 12 files changed, 30 insertions(+), 22 deletions(-)
 delete mode 100644 headers/build/private/libroot/directories.h
 create mode 100644 headers/build/private/system/directories.h

diff --git a/headers/build/private/libroot/directories.h b/headers/build/private/libroot/directories.h
deleted file mode 100644
index f5eb3aff4e..0000000000
--- a/headers/build/private/libroot/directories.h
+++ /dev/null
@@ -1 +0,0 @@
-#include <../private/libroot/directories.h>
diff --git a/headers/build/private/system/directories.h b/headers/build/private/system/directories.h
new file mode 100644
index 0000000000..f901e61880
--- /dev/null
+++ b/headers/build/private/system/directories.h
@@ -0,0 +1 @@
+#include <../private/system/directories.h>
diff --git a/src/add-ons/kernel/drivers/audio/ac97/auich/Jamfile b/src/add-ons/kernel/drivers/audio/ac97/auich/Jamfile
index 26d6af1cca..1fbdc219cf 100644
--- a/src/add-ons/kernel/drivers/audio/ac97/auich/Jamfile
+++ b/src/add-ons/kernel/drivers/audio/ac97/auich/Jamfile
@@ -1,7 +1,8 @@
 SubDir HAIKU_TOP src add-ons kernel drivers audio ac97 auich ;
 
 SetSubDirSupportedPlatformsBeOSCompatible ;
-UsePrivateHeaders libroot media ;
+UsePrivateSystemHeaders ;
+UsePrivateHeaders media ;
 SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
 SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) ] ;
 
diff --git a/src/add-ons/kernel/drivers/audio/ac97/auvia/Jamfile b/src/add-ons/kernel/drivers/audio/ac97/auvia/Jamfile
index 9333f4295b..f57a5b1180 100644
--- a/src/add-ons/kernel/drivers/audio/ac97/auvia/Jamfile
+++ b/src/add-ons/kernel/drivers/audio/ac97/auvia/Jamfile
@@ -1,7 +1,8 @@
 SubDir HAIKU_TOP src add-ons kernel drivers audio ac97 auvia ;
 
 SetSubDirSupportedPlatformsBeOSCompatible ;
-UsePrivateHeaders libroot media ;
+UsePrivateHeaders media ;
+UsePrivateSystemHeaders ;
 SubDirHdrs [ FDirName $(SUBDIR) $(DOTDOT) ] ;
 SEARCH_SOURCE += [ FDirName $(SUBDIR) $(DOTDOT) ] ;
 
diff --git a/src/add-ons/kernel/drivers/audio/echo/3g/Jamfile b/src/add-ons/kernel/drivers/audio/echo/3g/Jamfile
index 6a25fd102d..5c5f3c7b1a 100644
--- a/src/add-ons/kernel/drivers/audio/echo/3g/Jamfile
+++ b/src/add-ons/kernel/drivers/audio/echo/3g/Jamfile
@@ -12,8 +12,9 @@ SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers audio echo generic ;
 SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers audio echo generic DSP ;
 SubDirHdrs $(HAIKU_TOP) src add-ons kernel drivers audio echo generic ASIC ;
 
-UsePrivateHeaders [ FDirName kernel ] 			# For kernel_cpp.cpp
-	libroot media ;
+UsePrivateSystemHeaders ;
+UsePrivateHeaders kernel 			# For kernel_cpp.cpp
+	media ;
 
 # set some additional defines
 SubDirCcFlags -DECHO_BEOS -DECHO3G_FAMILY ;
@@ -62,7 +63,7 @@ SEARCH on [ FGristFiles
 	] = [ FDirName $(HAIKU_TOP) src add-ons kernel drivers audio echo generic ] ;
 
 SEARCH on [ FGristFiles
-		kernel_cpp.cpp 
+		kernel_cpp.cpp
 	] = [ FDirName $(HAIKU_TOP) src system kernel util ] ;
 
 SEARCH on [ FGristFiles
diff --git a/src/add-ons/kernel/drivers/audio/emuxki/Jamfile b/src/add-ons/kernel/drivers/audio/emuxki/Jamfile
index f3f71b1e67..2351edf86b 100644
--- a/src/add-ons/kernel/drivers/audio/emuxki/Jamfile
+++ b/src/add-ons/kernel/drivers/audio/emuxki/Jamfile
@@ -2,7 +2,8 @@ SubDir HAIKU_TOP src add-ons kernel drivers audio emuxki ;
 
 SetSubDirSupportedPlatformsBeOSCompatible ;
 
-UsePrivateHeaders libroot media ;
+UsePrivateSystemHeaders ;
+UsePrivateHeaders media ;
 
 KernelAddon emuxki :
 	ac97.c
diff --git a/src/add-ons/kernel/drivers/graphics/matrox/Jamfile b/src/add-ons/kernel/drivers/graphics/matrox/Jamfile
index fc53de96a5..4831e722cc 100644
--- a/src/add-ons/kernel/drivers/graphics/matrox/Jamfile
+++ b/src/add-ons/kernel/drivers/graphics/matrox/Jamfile
@@ -2,7 +2,8 @@ SubDir HAIKU_TOP src add-ons kernel drivers graphics matrox ;
 
 SetSubDirSupportedPlatformsBeOSCompatible ;
 
-UsePrivateHeaders graphics libroot ;
+UsePrivateSystemHeaders ;
+UsePrivateHeaders graphics ;
 UsePrivateHeaders [ FDirName graphics matrox ] ;
 
 KernelAddon matrox :
@@ -12,7 +13,7 @@ KernelAddon matrox :
 Package haiku-matrox-cvs :
 	README.html UPDATE.html ;
 Package haiku-matrox-cvs :
-	matrox : 
+	matrox :
 	boot home config add-ons kernel drivers bin ;
 PackageDriverSymLink haiku-matrox-cvs : graphics matrox ;
 Package haiku-matrox-cvs :
diff --git a/src/add-ons/kernel/drivers/graphics/neomagic/Jamfile b/src/add-ons/kernel/drivers/graphics/neomagic/Jamfile
index 3ea2159453..0e8146d538 100644
--- a/src/add-ons/kernel/drivers/graphics/neomagic/Jamfile
+++ b/src/add-ons/kernel/drivers/graphics/neomagic/Jamfile
@@ -2,7 +2,8 @@ SubDir HAIKU_TOP src add-ons kernel drivers graphics neomagic ;
 
 SetSubDirSupportedPlatformsBeOSCompatible ;
 
-UsePrivateHeaders graphics libroot ;
+UsePrivateSystemHeaders ;
+UsePrivateHeaders graphics ;
 UsePrivateHeaders [ FDirName graphics neomagic ] ;
 
 KernelAddon neomagic :
@@ -12,7 +13,7 @@ KernelAddon neomagic :
 Package haiku-neomagic-cvs :
 	README.html UPDATE.html ;
 Package haiku-neomagic-cvs :
-	neomagic : 
+	neomagic :
 	boot home config add-ons kernel drivers bin ;
 PackageDriverSymLink haiku-neomagic-cvs : graphics neomagic ;
 Package haiku-neomagic-cvs :
diff --git a/src/add-ons/kernel/drivers/graphics/nvidia/Jamfile b/src/add-ons/kernel/drivers/graphics/nvidia/Jamfile
index 3ec19127f2..c477c2747f 100644
--- a/src/add-ons/kernel/drivers/graphics/nvidia/Jamfile
+++ b/src/add-ons/kernel/drivers/graphics/nvidia/Jamfile
@@ -2,7 +2,8 @@ SubDir HAIKU_TOP src add-ons kernel drivers graphics nvidia ;
 
 SetSubDirSupportedPlatformsBeOSCompatible ;
 
-UsePrivateHeaders graphics libroot ;
+UsePrivateHeaders graphics ;
+UsePrivateSystemHeaders ;
 UsePrivateHeaders [ FDirName graphics nvidia ] ;
 UsePrivateHeaders [ FDirName graphics common ] ;
 
@@ -13,7 +14,7 @@ KernelAddon nvidia :
 Package haiku-nvidia-cvs :
 	README.html UPDATE.html ;
 Package haiku-nvidia-cvs :
-	nvidia : 
+	nvidia :
 	boot home config add-ons kernel drivers bin ;
 PackageDriverSymLink haiku-nvidia-cvs : graphics nvidia ;
 Package haiku-nvidia-cvs :
diff --git a/src/add-ons/kernel/drivers/network/sis900/Jamfile b/src/add-ons/kernel/drivers/network/sis900/Jamfile
index e7e994bd18..839a89b7a7 100644
--- a/src/add-ons/kernel/drivers/network/sis900/Jamfile
+++ b/src/add-ons/kernel/drivers/network/sis900/Jamfile
@@ -3,8 +3,9 @@ SubDir HAIKU_TOP src add-ons kernel drivers network sis900 ;
 SetSubDirSupportedPlatformsBeOSCompatible ;
 
 
+UsePrivateSystemHeaders ;
 # For ether_driver.h
-UsePrivateHeaders libroot net ;
+UsePrivateHeaders net ;
 
 KernelAddon sis900 :
 	driver.c
@@ -14,7 +15,7 @@ KernelAddon sis900 :
 	;
 
 Package haiku-sis900-cvs :
-	sis900 : 
+	sis900 :
 	boot home config add-ons kernel drivers bin ;
 PackageDriverSymLink haiku-sis900-cvs : net sis900 ;
 Package haiku-sis900-cvs :
@@ -45,12 +46,12 @@ actions ignore InstallSiS900
 
 # Installation
 
-HaikuInstall install-networking : /boot/home/config/add-ons/kernel/drivers/bin : 
- 	sis900 
+HaikuInstall install-networking : /boot/home/config/add-ons/kernel/drivers/bin :
+ 	sis900
 ;
 
-HaikuInstallRelSymLink install-networking : /boot/home/config/add-ons/kernel/drivers/dev/net : 
-	sis900 : 
-	installed-symlink 
+HaikuInstallRelSymLink install-networking : /boot/home/config/add-ons/kernel/drivers/dev/net :
+	sis900 :
+	installed-symlink
 ;
 
diff --git a/src/add-ons/kernel/generic/mpu401/Jamfile b/src/add-ons/kernel/generic/mpu401/Jamfile
index 61b9be3883..32bc4236c9 100644
--- a/src/add-ons/kernel/generic/mpu401/Jamfile
+++ b/src/add-ons/kernel/generic/mpu401/Jamfile
@@ -1,6 +1,6 @@
 SubDir HAIKU_TOP src add-ons kernel generic mpu401 ;
 
-UsePrivateHeaders libroot ;
+UsePrivateSystemHeaders ;
 
 KernelAddon mpu401 :
 	mpu401.c
diff --git a/src/build/libroot/Jamfile b/src/build/libroot/Jamfile
index d704520320..34f947ed00 100644
--- a/src/build/libroot/Jamfile
+++ b/src/build/libroot/Jamfile
@@ -9,7 +9,7 @@ UseHeaders [ FDirName $(HAIKU_TOP) headers build os interface ] : true ;
 UseHeaders [ FDirName $(HAIKU_TOP) headers build os storage ] : true ;
 UseHeaders [ FDirName $(HAIKU_TOP) headers build os support ] : true ;
 
-UsePrivateBuildHeaders kernel libroot ;
+UsePrivateBuildHeaders kernel system ;
 
 {
 	local defines = [ FDefines

From b55bd1da251d647c19080b5334860d72910563fa Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 17 Jul 2011 17:09:23 +0200
Subject: [PATCH 0307/1170] configure: Update required gcc 2 version

---
 configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure b/configure
index d7b4e188a9..13fbdbccee 100755
--- a/configure
+++ b/configure
@@ -311,7 +311,7 @@ HOST_GCC_OBJCOPY=`gcc -print-prog-name=objcopy`
 SFDISK_BINARY=sfdisk
 HOST_SFDISK=$SFDISK_BINARY
 
-haikuRequiredLegacyGCCVersion="2.95.3-110228"
+haikuRequiredLegacyGCCVersion="2.95.3-110711"
 export haikuRequiredLegacyGCCVersion
 	# version of legacy gcc required to build haiku
 

From 8212d04704240401e328b789d4a9284873a63c10 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 18 Jul 2011 21:04:33 +0200
Subject: [PATCH 0308/1170] Repackage BeZillaBrowser as hpkg

---
 build/jam/OptionalPackages | 7 ++++---
 1 file changed, 4 insertions(+), 3 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 1f9cd8fa21..b48ff1f732 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -275,11 +275,12 @@ if [ IsOptionalHaikuImagePackageAdded BeZillaBrowser ] {
 				: $(baseURL)/BeZillaBrowser-2.0.0.22pre-r1a2-x86-gcc4-2010-05-04.zip ;
  		} else {
 			InstallOptionalHaikuImagePackage
-				BeZillaBrowser-2.0.0.22pre-r1a2-x86-gcc2-2010-05-02.zip
-				: $(baseURL)/BeZillaBrowser-2.0.0.22pre-r1a2-x86-gcc2-2010-05-02.zip ;
+				bezillabrowser-2.0.0.22pre_2010_05_02-1-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/bezillabrowser-2.0.0.22pre_2010_05_02-1-x86_gcc2.hpkg
+				: common packages ;
  		}
  		AddSymlinkToHaikuImage home config settings deskbar Applications
-			: /boot/apps/BeZillaBrowser/BeZillaBrowser ;
+			: /boot/common/apps/BeZillaBrowser/BeZillaBrowser ;
 		InstallSourceArchive BeZillaBrowser-2.0.0.22pre-r1a2-sources.tar.xz
 			: $(baseSourceURL)/2010/BeZillaBrowser-2.0.0.22pre-r1a2-sources.tar.xz ;
 	}

From d5c52ccd3933b426a48c1b40b1c3ca42f4bdf4ba Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 21 Jul 2011 00:31:34 +0200
Subject: [PATCH 0309/1170] Fix typo

---
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 2581ed90fb..961928be05 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -1124,7 +1124,7 @@ Volume::_AddPackageContentRootNode(Package* package,
 			RETURN_ERROR(error);
 		}
 
-		// recursive into directory, unless we're supposed to skip the node
+		// recurse into directory, unless we're supposed to skip the node
 		if (node != NULL) {
 			if (PackageDirectory* packageDirectory
 					= dynamic_cast(packageNode)) {
@@ -1178,7 +1178,7 @@ Volume::_RemovePackageContentRootNode(Package* package,
 		if (packageNode == endPackageNode)
 			break;
 
-		// recursive into directory
+		// recurse into directory
 		if (PackageDirectory* packageDirectory
 				= dynamic_cast(packageNode)) {
 			if (packageDirectory->FirstChild() != NULL) {

From 25d31cc472a552a1f5dfa15f4ee0a267ea521907 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 21 Jul 2011 00:35:35 +0200
Subject: [PATCH 0310/1170] Fix package removal with skipped directories

Volume::_RemovePackageContentRootNode(): Check whether a directory
corresponding to the package directory does actually exist. This might
not be the case when the package directory has been skipped due to
clashing with a shine-through directory. Would crash in this case.
---
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 12 +++++++-----
 1 file changed, 7 insertions(+), 5 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 961928be05..88e96cf3a0 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -1182,11 +1182,13 @@ Volume::_RemovePackageContentRootNode(Package* package,
 		if (PackageDirectory* packageDirectory
 				= dynamic_cast(packageNode)) {
 			if (packageDirectory->FirstChild() != NULL) {
-				directory = dynamic_cast(
-					directory->FindChild(packageNode->Name()));
-				packageNode = packageDirectory->FirstChild();
-				directory->WriteLock();
-				continue;
+				if (Directory* childDirectory = dynamic_cast(
+						directory->FindChild(packageNode->Name()))) {
+					directory = childDirectory;
+					packageNode = packageDirectory->FirstChild();
+					directory->WriteLock();
+					continue;
+				}
 			}
 		}
 

From 72796728e3a5318a4963cacbaaf3c2ea9e8975b5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 21 Jul 2011 03:56:23 +0200
Subject: [PATCH 0311/1170] Fix node handling on package addition/removal

* UnpackingLeafNode: Add a fFinalPackageNode attribute. It is set when
  the node is about to be removed and will point to the node's previous
  head package node and be used in its stead. From the perspective of
  the FS hooks this leaves the node in an unchanged state.
* Unpacking[Leaf,Directory]Node:
  - Add WillBeFirstPackageNode(), returning whether the given package
    node would become the head package node when added.
  - Add PrepareForRemoval() which removes all package nodes. In case of
    UnpackingLeafNode it also sets fFinalPackageNode.
  - Add CloneTransferPackageNodes(). It is only implemented for
    UnpackingLeafNode. It clones the node, transfers all package nodes
    to the clone and sets fFinalPackageNode on this node.
* Volume::_{Add,Remove}PackageNode(): Solved the following TODO: When a
  package is added or removed and a file present in both the
  added/removed package and another package with the version in the
  former having precedence, we have to remove the node (leaving it
  unchanged) and replace it by a new node. This prevents clients having
  the node opened or mapped from suddenly seeing different data. It also
  fixes unbalanced calls to PackageNode::VFSInit()/VFSUninit() which
  would result in file descriptors to package files being leaked.
---
 .../packagefs/UnpackingDirectory.cpp          |  21 +++
 .../packagefs/UnpackingDirectory.h            |   4 +
 .../packagefs/UnpackingLeafNode.cpp           | 105 +++++++++--
 .../packagefs/UnpackingLeafNode.h             |  10 ++
 .../file_systems/packagefs/UnpackingNode.cpp  |   7 +
 .../file_systems/packagefs/UnpackingNode.h    |   6 +
 .../kernel/file_systems/packagefs/Volume.cpp  | 165 +++++++++++++-----
 .../kernel/file_systems/packagefs/Volume.h    |   4 +-
 8 files changed, 262 insertions(+), 60 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp
index 66606aeb04..ee67354819 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.cpp
@@ -140,6 +140,27 @@ UnpackingDirectory::IsOnlyPackageNode(PackageNode* node) const
 }
 
 
+bool
+UnpackingDirectory::WillBeFirstPackageNode(PackageNode* packageNode) const
+{
+	PackageDirectory* packageDirectory
+		= dynamic_cast(packageNode);
+	if (packageDirectory == NULL)
+		return false;
+
+	PackageDirectory* other = fPackageDirectories.Head();
+	return other == NULL
+		|| packageDirectory->ModifiedTime() > other->ModifiedTime();
+}
+
+
+void
+UnpackingDirectory::PrepareForRemoval()
+{
+	fPackageDirectories.MakeEmpty();
+}
+
+
 status_t
 UnpackingDirectory::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h
index 61d73034fc..baad89b1d5 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingDirectory.h
@@ -29,6 +29,10 @@ public:
 
 	virtual	PackageNode*		GetPackageNode();
 	virtual	bool				IsOnlyPackageNode(PackageNode* node) const;
+	virtual	bool				WillBeFirstPackageNode(
+									PackageNode* packageNode) const;
+
+	virtual	void				PrepareForRemoval();
 
 	virtual	status_t			OpenAttributeDirectory(
 									AttributeDirectoryCookie*& _cookie);
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp
index 9d671a389b..3ed264b84c 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp
@@ -9,6 +9,7 @@
 #include 
 
 #include 
+#include 
 
 #include "UnpackingAttributeCookie.h"
 #include "UnpackingAttributeDirectoryCookie.h"
@@ -17,20 +18,23 @@
 
 UnpackingLeafNode::UnpackingLeafNode(ino_t id)
 	:
-	Node(id)
+	Node(id),
+	fFinalPackageNode(NULL)
 {
 }
 
 
 UnpackingLeafNode::~UnpackingLeafNode()
 {
+	if (fFinalPackageNode != NULL)
+		fFinalPackageNode->ReleaseReference();
 }
 
 
 status_t
 UnpackingLeafNode::VFSInit(dev_t deviceID)
 {
-	if (PackageLeafNode* packageNode = fPackageNodes.Head())
+	if (PackageLeafNode* packageNode = _ActivePackageNode())
 		return packageNode->VFSInit(deviceID, fID);
 	return B_OK;
 }
@@ -39,7 +43,7 @@ UnpackingLeafNode::VFSInit(dev_t deviceID)
 void
 UnpackingLeafNode::VFSUninit()
 {
-	if (PackageLeafNode* packageNode = fPackageNodes.Head())
+	if (PackageLeafNode* packageNode = _ActivePackageNode())
 		packageNode->VFSUninit();
 }
 
@@ -47,7 +51,7 @@ UnpackingLeafNode::VFSUninit()
 mode_t
 UnpackingLeafNode::Mode() const
 {
-	if (PackageLeafNode* packageNode = fPackageNodes.Head())
+	if (PackageLeafNode* packageNode = _ActivePackageNode())
 		return packageNode->Mode();
 	return S_IFREG | S_IRUSR | S_IRGRP | S_IROTH;
 }
@@ -56,7 +60,7 @@ UnpackingLeafNode::Mode() const
 uid_t
 UnpackingLeafNode::UserID() const
 {
-	if (PackageLeafNode* packageNode = fPackageNodes.Head())
+	if (PackageLeafNode* packageNode = _ActivePackageNode())
 		return packageNode->UserID();
 	return 0;
 }
@@ -65,7 +69,7 @@ UnpackingLeafNode::UserID() const
 gid_t
 UnpackingLeafNode::GroupID() const
 {
-	if (PackageLeafNode* packageNode = fPackageNodes.Head())
+	if (PackageLeafNode* packageNode = _ActivePackageNode())
 		return packageNode->GroupID();
 	return 0;
 }
@@ -74,7 +78,7 @@ UnpackingLeafNode::GroupID() const
 timespec
 UnpackingLeafNode::ModifiedTime() const
 {
-	if (PackageLeafNode* packageNode = fPackageNodes.Head())
+	if (PackageLeafNode* packageNode = _ActivePackageNode())
 		return packageNode->ModifiedTime();
 
 	timespec time = { 0, 0 };
@@ -85,7 +89,7 @@ UnpackingLeafNode::ModifiedTime() const
 off_t
 UnpackingLeafNode::FileSize() const
 {
-	if (PackageLeafNode* packageNode = fPackageNodes.Head())
+	if (PackageLeafNode* packageNode = _ActivePackageNode())
 		return packageNode->FileSize();
 	return 0;
 }
@@ -101,6 +105,8 @@ UnpackingLeafNode::GetNode()
 status_t
 UnpackingLeafNode::AddPackageNode(PackageNode* packageNode)
 {
+	ASSERT(fFinalPackageNode == NULL);
+
 	if (S_ISDIR(packageNode->Mode()))
 		return B_BAD_VALUE;
 
@@ -127,6 +133,8 @@ UnpackingLeafNode::AddPackageNode(PackageNode* packageNode)
 void
 UnpackingLeafNode::RemovePackageNode(PackageNode* packageNode)
 {
+	ASSERT(fFinalPackageNode == NULL);
+
 	bool isNewest = packageNode == fPackageNodes.Head();
 	fPackageNodes.Remove(dynamic_cast(packageNode));
 
@@ -152,22 +160,78 @@ UnpackingLeafNode::RemovePackageNode(PackageNode* packageNode)
 PackageNode*
 UnpackingLeafNode::GetPackageNode()
 {
-	return fPackageNodes.Head();
+	return _ActivePackageNode();
 }
 
 
 bool
 UnpackingLeafNode::IsOnlyPackageNode(PackageNode* node) const
 {
+	ASSERT(fFinalPackageNode == NULL);
+
 	PackageLeafNode* head = fPackageNodes.Head();
 	return node == head && fPackageNodes.GetNext(head) == NULL;
 }
 
 
+bool
+UnpackingLeafNode::WillBeFirstPackageNode(PackageNode* packageNode) const
+{
+	PackageLeafNode* packageLeafNode
+		= dynamic_cast(packageNode);
+	if (packageLeafNode == NULL)
+		return false;
+
+	PackageLeafNode* headNode = fPackageNodes.Head();
+	return headNode == NULL
+		|| packageLeafNode->ModifiedTime() > headNode->ModifiedTime();
+}
+
+void
+UnpackingLeafNode::PrepareForRemoval()
+{
+	ASSERT(fFinalPackageNode == NULL);
+
+	fFinalPackageNode = fPackageNodes.Head();
+	if (fFinalPackageNode != NULL) {
+		fFinalPackageNode->AcquireReference();
+		fPackageNodes.MakeEmpty();
+	}
+}
+
+
+status_t
+UnpackingLeafNode::CloneTransferPackageNodes(ino_t id, UnpackingNode*& _newNode)
+{
+	ASSERT(fFinalPackageNode == NULL);
+
+	UnpackingLeafNode* clone = new(std::nothrow) UnpackingLeafNode(id);
+	if (clone == NULL)
+		return B_NO_MEMORY;
+
+	status_t error = clone->Init(Parent(), Name(), 0);
+	if (error != B_OK) {
+		delete clone;
+		return error;
+	}
+
+	// We keep the old head as fFinalPackageNode, which will make us to behave
+	// exactly as before with respect to FS operations.
+	fFinalPackageNode = fPackageNodes.Head();
+	if (fFinalPackageNode != NULL) {
+		fFinalPackageNode->AcquireReference();
+		clone->fPackageNodes.MoveFrom(&fPackageNodes);
+	}
+
+	_newNode = clone;
+	return B_OK;
+}
+
+
 status_t
 UnpackingLeafNode::Read(off_t offset, void* buffer, size_t* bufferSize)
 {
-	if (PackageLeafNode* packageNode = fPackageNodes.Head())
+	if (PackageLeafNode* packageNode = _ActivePackageNode())
 		return packageNode->Read(offset, buffer, bufferSize);
 	return B_ERROR;
 }
@@ -176,7 +240,7 @@ UnpackingLeafNode::Read(off_t offset, void* buffer, size_t* bufferSize)
 status_t
 UnpackingLeafNode::Read(io_request* request)
 {
-	if (PackageLeafNode* packageNode = fPackageNodes.Head())
+	if (PackageLeafNode* packageNode = _ActivePackageNode())
 		return packageNode->Read(request);
 	return EBADF;
 }
@@ -185,7 +249,7 @@ UnpackingLeafNode::Read(io_request* request)
 status_t
 UnpackingLeafNode::ReadSymlink(void* buffer, size_t* bufferSize)
 {
-	PackageLeafNode* packageNode = fPackageNodes.Head();
+	PackageLeafNode* packageNode = _ActivePackageNode();
 	if (packageNode == NULL)
 		return B_BAD_VALUE;
 
@@ -206,7 +270,7 @@ UnpackingLeafNode::ReadSymlink(void* buffer, size_t* bufferSize)
 status_t
 UnpackingLeafNode::OpenAttributeDirectory(AttributeDirectoryCookie*& _cookie)
 {
-	return UnpackingAttributeDirectoryCookie::Open(fPackageNodes.Head(),
+	return UnpackingAttributeDirectoryCookie::Open(_ActivePackageNode(),
 		_cookie);
 }
 
@@ -215,7 +279,7 @@ status_t
 UnpackingLeafNode::OpenAttribute(const char* name, int openMode,
 	AttributeCookie*& _cookie)
 {
-	return UnpackingAttributeCookie::Open(fPackageNodes.Head(), name, openMode,
+	return UnpackingAttributeCookie::Open(_ActivePackageNode(), name, openMode,
 		_cookie);
 }
 
@@ -223,7 +287,7 @@ UnpackingLeafNode::OpenAttribute(const char* name, int openMode,
 status_t
 UnpackingLeafNode::IndexAttribute(AttributeIndexer* indexer)
 {
-	return UnpackingAttributeCookie::IndexAttribute(fPackageNodes.Head(),
+	return UnpackingAttributeCookie::IndexAttribute(_ActivePackageNode(),
 		indexer);
 }
 
@@ -231,7 +295,16 @@ UnpackingLeafNode::IndexAttribute(AttributeIndexer* indexer)
 void*
 UnpackingLeafNode::IndexCookieForAttribute(const char* name) const
 {
-	if (PackageLeafNode* packageNode = fPackageNodes.Head())
+	if (PackageLeafNode* packageNode = _ActivePackageNode())
 		return packageNode->IndexCookieForAttribute(name);
 	return NULL;
 }
+
+
+PackageLeafNode*
+UnpackingLeafNode::_ActivePackageNode() const
+{
+	if (PackageLeafNode* packageNode = fPackageNodes.Head())
+		return packageNode;
+	return fFinalPackageNode;
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h
index e1b8db4340..e3bb4f175c 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.h
@@ -32,6 +32,12 @@ public:
 
 	virtual	PackageNode*		GetPackageNode();
 	virtual	bool				IsOnlyPackageNode(PackageNode* node) const;
+	virtual	bool				WillBeFirstPackageNode(
+									PackageNode* packageNode) const;
+
+	virtual	void				PrepareForRemoval();
+	virtual	status_t			CloneTransferPackageNodes(ino_t id,
+									UnpackingNode*& _newNode);
 
 	virtual	status_t			Read(off_t offset, void* buffer,
 									size_t* bufferSize);
@@ -48,8 +54,12 @@ public:
 	virtual	status_t			IndexAttribute(AttributeIndexer* indexer);
 	virtual	void*				IndexCookieForAttribute(const char* name) const;
 
+private:
+	inline	PackageLeafNode*	_ActivePackageNode() const;
+
 private:
 			PackageLeafNodeList	fPackageNodes;
+			PackageLeafNode*	fFinalPackageNode;
 };
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.cpp
index dd99ca9dd2..f9700ab7ef 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.cpp
@@ -10,3 +10,10 @@
 UnpackingNode::~UnpackingNode()
 {
 }
+
+
+status_t
+UnpackingNode::CloneTransferPackageNodes(ino_t id, UnpackingNode*& _newNode)
+{
+	return B_BAD_VALUE;
+}
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h b/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h
index 3ac50316c7..28130ca661 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingNode.h
@@ -24,6 +24,12 @@ public:
 
 	virtual	PackageNode*		GetPackageNode() = 0;
 	virtual	bool				IsOnlyPackageNode(PackageNode* node) const = 0;
+	virtual	bool				WillBeFirstPackageNode(
+									PackageNode* packageNode) const = 0;
+
+	virtual	void				PrepareForRemoval() = 0;
+	virtual	status_t			CloneTransferPackageNodes(ino_t id,
+									UnpackingNode*& _newNode);
 };
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 88e96cf3a0..8e7c70e576 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -1243,21 +1243,59 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
 		newNode = true;
 	}
 
-	// TODO: The non-new part is broken for files. If a node is already known to
-	// the VFS, we can't just change the file content. The file might be an
-	// executable or library that is currently in use (i.e. mapped) and when
-	// just changing the file content we break things horribly. In fact we don't
-	// even do that correctly in UnpackingLeafNode::AddPackageNode() -- neither
-	// the former nor the new head package node is notified.
-
 	BReference nodeReference(node);
 	NodeWriteLocker nodeWriteLocker(node);
 
+	BReference newNodeReference;
+	NodeWriteLocker newNodeWriteLocker;
+	Node* oldNode = NULL;
+
+	if (!newNode && !S_ISDIR(node->Mode()) && oldPackageNode != NULL
+		&& unpackingNode->WillBeFirstPackageNode(packageNode)) {
+		// The package node we're going to add will represent the node,
+		// replacing the current head package node. Since the node isn't a
+		// directory, we must make sure that clients having opened or mapped the
+		// node won't be surprised. So we create a new node and remove the
+		// current one.
+		// create a new node and transfer the package nodes to it
+		UnpackingNode* newUnpackingNode;
+		status_t error = unpackingNode->CloneTransferPackageNodes(
+			fNextNodeID++, newUnpackingNode);
+		if (error != B_OK)
+			RETURN_ERROR(error);
+
+		// remove the old node
+		_NotifyNodeRemoved(node);
+		_RemoveNodeAndVNode(node);
+		oldNode = node;
+
+		// add the new node
+		unpackingNode = newUnpackingNode;
+		node = unpackingNode->GetNode();
+		newNodeReference.SetTo(node);
+		newNodeWriteLocker.SetTo(node, false);
+
+		directory->AddChild(node);
+		fNodes.Insert(node);
+		newNode = true;
+	}
+
 	status_t error = unpackingNode->AddPackageNode(packageNode);
 	if (error != B_OK) {
-		// remove the node, if created before
-		if (newNode)
-			_RemoveNode(node);
+		// Remove the node, if created before. If the node was created to
+		// replace the previous node, send out notifications instead.
+		if (newNode) {
+			if (oldNode != NULL) {
+				_NotifyNodeAdded(node);
+				if (notify) {
+					notify_entry_removed(ID(), directory->ID(), oldNode->Name(),
+						oldNode->ID());
+					notify_entry_created(ID(), directory->ID(), node->Name(),
+						node->ID());
+				}
+			} else
+				_RemoveNode(node);
+		}
 		RETURN_ERROR(error);
 	}
 
@@ -1270,21 +1308,18 @@ Volume::_AddPackageNode(Directory* directory, PackageNode* packageNode,
 
 	if (notify) {
 		if (newNode) {
+			if (oldNode != NULL) {
+				notify_entry_removed(ID(), directory->ID(), oldNode->Name(),
+					oldNode->ID());
+			}
 			notify_entry_created(ID(), directory->ID(), node->Name(),
 				node->ID());
 		} else if (packageNode == unpackingNode->GetPackageNode()) {
 			// The new package node has become the one representing the node.
 			// Send stat changed notification for directories and entry
 			// removed + created notifications for files and symlinks.
-			if (S_ISDIR(packageNode->Mode())) {
-				notify_stat_changed(ID(), node->ID(), kAllStatFields);
-				// TODO: Actually the attributes might change, too!
-			} else {
-				notify_entry_removed(ID(), directory->ID(), node->Name(),
-					node->ID());
-				notify_entry_created(ID(), directory->ID(), node->Name(),
-					node->ID());
-			}
+			notify_stat_changed(ID(), node->ID(), kAllStatFields);
+			// TODO: Actually the attributes might change, too!
 		}
 	}
 
@@ -1304,11 +1339,12 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
 	BReference nodeReference(node);
 	NodeWriteLocker nodeWriteLocker(node);
 
-	// TODO: This is broken for files that are in use. Cf. _AddPackageNode() for
-	// details.
-
 	PackageNode* headPackageNode = unpackingNode->GetPackageNode();
 	bool nodeRemoved = false;
+	Node* newNode = NULL;
+
+	BReference newNodeReference;
+	NodeWriteLocker newNodeWriteLocker;
 
 	// If this is the last package node of the node, remove it completely.
 	if (unpackingNode->IsOnlyPackageNode(packageNode)) {
@@ -1316,29 +1352,54 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
 		// find the node anymore.
 		_NotifyNodeRemoved(node);
 
-		unpackingNode->RemovePackageNode(packageNode);
+		unpackingNode->PrepareForRemoval();
 
-		// we get and put the vnode to notify the VFS
-		// TODO: We should probably only do that, if the node is known to the
-		// VFS in the first place.
-		Node* dummyNode;
-		bool gotVNode = GetVNode(node->ID(), dummyNode) == B_OK;
-
-		_RemoveNode(node);
+		_RemoveNodeAndVNode(node);
 		nodeRemoved = true;
-
-		if (gotVNode) {
-			RemoveVNode(node->ID());
-			PutVNode(node->ID());
-		}
-	} else {
-		// The node does at least have one more package node.
-		unpackingNode->RemovePackageNode(packageNode);
-
-		if (packageNode == headPackageNode) {
+	} else if (packageNode == headPackageNode) {
+		// The node does at least have one more package node, but the one to be
+		// removed is the head. Unless it's a directory, we replace the node
+		// with a completely new one and let the old one die. This is necessary
+		// to avoid surprises for clients that have opened/mapped the node.
+		if (S_ISDIR(packageNode->Mode())) {
+			unpackingNode->RemovePackageNode(packageNode);
 			_NotifyNodeChanged(node, kAllStatFields,
 				OldUnpackingNodeAttributes(headPackageNode));
+		} else {
+			// create a new node and transfer the package nodes to it
+			UnpackingNode* newUnpackingNode;
+			status_t error = unpackingNode->CloneTransferPackageNodes(
+				fNextNodeID++, newUnpackingNode);
+			if (error == B_OK) {
+				// remove the package node
+				newUnpackingNode->RemovePackageNode(packageNode);
+
+				// remove the old node
+				_NotifyNodeRemoved(node);
+				_RemoveNodeAndVNode(node);
+
+				// add the new node
+				newNode = newUnpackingNode->GetNode();
+				newNodeReference.SetTo(newNode);
+				newNodeWriteLocker.SetTo(newNode, false);
+
+				directory->AddChild(newNode);
+				fNodes.Insert(newNode);
+				_NotifyNodeAdded(newNode);
+			} else {
+				// There's nothing we can do. Remove the node completely.
+				_NotifyNodeRemoved(node);
+
+				unpackingNode->PrepareForRemoval();
+
+				_RemoveNodeAndVNode(node);
+				nodeRemoved = true;
+			}
 		}
+	} else {
+		// The package node to remove is not the head of the node. This change
+		// doesn't have any visible effect.
+		unpackingNode->RemovePackageNode(packageNode);
 	}
 
 	if (!notify)
@@ -1348,7 +1409,7 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
 	if (nodeRemoved) {
 		notify_entry_removed(ID(), directory->ID(), node->Name(), node->ID());
 	} else if (packageNode == headPackageNode) {
-		// The new package node was the one representing the node.
+		// The removed package node was the one representing the node.
 		// Send stat changed notification for directories and entry
 		// removed + created notifications for files and symlinks.
 		if (S_ISDIR(packageNode->Mode())) {
@@ -1357,8 +1418,8 @@ Volume::_RemovePackageNode(Directory* directory, PackageNode* packageNode,
 		} else {
 			notify_entry_removed(ID(), directory->ID(), node->Name(),
 				node->ID());
-			notify_entry_created(ID(), directory->ID(), node->Name(),
-				node->ID());
+			notify_entry_created(ID(), directory->ID(), newNode->Name(),
+				newNode->ID());
 		}
 	}
 }
@@ -1410,6 +1471,24 @@ Volume::_RemoveNode(Node* node)
 }
 
 
+void
+Volume::_RemoveNodeAndVNode(Node* node)
+{
+	// we get and put the vnode to notify the VFS
+	// TODO: We should probably only do that, if the node is known to the
+	// VFS in the first place.
+	Node* dummyNode;
+	bool gotVNode = GetVNode(node->ID(), dummyNode) == B_OK;
+
+	_RemoveNode(node);
+
+	if (gotVNode) {
+		RemoveVNode(node->ID());
+		PutVNode(node->ID());
+	}
+}
+
+
 void
 Volume::_DomainListenerEventOccurred(PackageDomain* domain,
 	const KMessage* event)
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index d939b66a8f..d2356180ac 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
  * Distributed under the terms of the MIT License.
  */
 #ifndef VOLUME_H
@@ -157,6 +157,8 @@ private:
 									UnpackingNode*& _node);
 									// does *not* return a reference
 			void				_RemoveNode(Node* node);
+			void				_RemoveNodeAndVNode(Node* node);
+									// caller must hold a reference
 
 			void				_DomainListenerEventOccurred(
 									PackageDomain* domain,

From c6a11edc9f5a8436fc2a8b1add0df53995ffc8eb Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 21 Jul 2011 17:43:33 +0200
Subject: [PATCH 0312/1170] Fix removing dependencies on package removal

The dependencies must also be dissociated from the resolvables they have
been resolved to.
---
 src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp
index 4f1ae09c59..1abac70b50 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp
@@ -320,6 +320,9 @@ PackageFSRoot::_RemovePackage(Package* package)
 			} else
 				family->RemoveDependency(dependency);
 		}
+
+		if (Resolvable* resolvable = dependency->Resolvable())
+			resolvable->RemoveDependency(dependency);
 	}
 
 	// unregister resolvables

From b779a874a894cf1fff94aef1819fdcd6979420b6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 21 Jul 2011 19:05:50 +0200
Subject: [PATCH 0313/1170] Node: Keep track of VFS init status

* Node::VFSInit() and VFSUninit() set/clear the new node flag
  NODE_FLAG_KNOWN_TO_VFS. They need to be called by overriding methods,
  now.
* Add Node::IsKnownToVFS() which returns the VFS init status.
---
 .../kernel/file_systems/packagefs/Node.cpp     |  2 ++
 .../kernel/file_systems/packagefs/Node.h       | 18 +++++++++++++++++-
 .../packagefs/UnpackingLeafNode.cpp            | 11 +++++++++--
 3 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.cpp b/src/add-ons/kernel/file_systems/packagefs/Node.cpp
index ef137c3dea..d5e3bb1627 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Node.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Node.cpp
@@ -56,6 +56,7 @@ Node::Init(Directory* parent, const char* name, uint32 flags)
 status_t
 Node::VFSInit(dev_t deviceID)
 {
+	fFlags |= NODE_FLAG_KNOWN_TO_VFS;
 	return B_OK;
 }
 
@@ -63,6 +64,7 @@ Node::VFSInit(dev_t deviceID)
 void
 Node::VFSUninit()
 {
+	fFlags &= ~(uint32)NODE_FLAG_KNOWN_TO_VFS;
 }
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Node.h b/src/add-ons/kernel/file_systems/packagefs/Node.h
index e107f7319e..50c05381f1 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Node.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Node.h
@@ -32,7 +32,9 @@ enum {
 	NODE_FLAG_CONST_NAME	= 0x02,
 		// Init(): The given name is a constant that won't go away during the
 		// lifetime of the object. No need to copy.
-	NODE_FLAG_OWNS_NAME		= NODE_FLAG_KEEP_NAME
+	NODE_FLAG_OWNS_NAME		= NODE_FLAG_KEEP_NAME,
+	NODE_FLAG_KNOWN_TO_VFS	= 0x04,
+		// internal flag
 };
 
 
@@ -61,7 +63,11 @@ public:
 									// so also on error.
 
 	virtual	status_t			VFSInit(dev_t deviceID);
+									// base class version must be called on
+									// success
 	virtual	void				VFSUninit();
+									// base class version must be called
+	inline	bool				IsKnownToVFS() const;
 
 			void				SetID(ino_t id);
 			void				SetParent(Directory* parent);
@@ -126,6 +132,16 @@ Node::WriteUnlock()
 }
 
 
+bool
+Node::IsKnownToVFS() const
+{
+	return (fFlags & NODE_FLAG_KNOWN_TO_VFS) != 0;
+}
+
+
+// #pragma mark -
+
+
 struct NodeNameHashDefinition {
 	typedef const char*		KeyType;
 	typedef	Node			ValueType;
diff --git a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp
index 3ed264b84c..bb68b71db9 100644
--- a/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/UnpackingLeafNode.cpp
@@ -34,9 +34,14 @@ UnpackingLeafNode::~UnpackingLeafNode()
 status_t
 UnpackingLeafNode::VFSInit(dev_t deviceID)
 {
+	status_t error = B_OK;
 	if (PackageLeafNode* packageNode = _ActivePackageNode())
-		return packageNode->VFSInit(deviceID, fID);
-	return B_OK;
+		error = packageNode->VFSInit(deviceID, fID);
+
+	if (error == B_OK)
+		Node::VFSInit(deviceID);
+
+	return error;
 }
 
 
@@ -45,6 +50,8 @@ UnpackingLeafNode::VFSUninit()
 {
 	if (PackageLeafNode* packageNode = _ActivePackageNode())
 		packageNode->VFSUninit();
+
+	Node::VFSUninit();
 }
 
 

From 7723ae9df290e2e6f62e84fa9a75bdf8f9e620f9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 21 Jul 2011 20:28:01 +0200
Subject: [PATCH 0314/1170] Volume::_RemoveNodeAndVNode(): Squash TODO

Only get/remove/put the vnode when the node is actually known to the
VFS. This does not only save unnecessary work, it also solves a
(temporary) deadlock -- at least partially. If another thread caused a
call to our get_vnode() hook just before, it would block on the volume
lock we're holding when adding/removing packages. The vnode would be
marked busy until the other thread's request was fulfilled and our call
to get_vnode() would block until timing out. Now we're calling
get_vnode() only, if we already know that the VFS already has a valid
vnode.

There still remains a race condition. If the VFS discards the vnode
right before we call get_vnode(), we essentially have the same situation
as before (i.e. us calling get_vnode() although the vnode is no longer
known to the VFS) with the same potential problem. For a real solution
we need a get_vnode() variant which can be told not to block.
---
 .../kernel/file_systems/packagefs/Volume.cpp  | 33 +++++++++++++++----
 1 file changed, 27 insertions(+), 6 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 8e7c70e576..f4be297e25 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -1474,15 +1474,36 @@ Volume::_RemoveNode(Node* node)
 void
 Volume::_RemoveNodeAndVNode(Node* node)
 {
-	// we get and put the vnode to notify the VFS
-	// TODO: We should probably only do that, if the node is known to the
-	// VFS in the first place.
-	Node* dummyNode;
-	bool gotVNode = GetVNode(node->ID(), dummyNode) == B_OK;
+	// If the node is known to the VFS, we get the vnode, remove it, and put it,
+	// so that the VFS will discard it as soon as possible (i.e. now, if no one
+	// else is using it).
+	NodeWriteLocker nodeWriteLocker(node);
 
+	// Remove the node from its parent and the volume. This makes the node
+	// inaccessible via the get_vnode() and lookup() hooks.
 	_RemoveNode(node);
 
-	if (gotVNode) {
+	bool getVNode = node->IsKnownToVFS();
+
+	nodeWriteLocker.Unlock();
+
+	// Get a vnode reference, if the node is already known to the VFS.
+	Node* dummyNode;
+	if (getVNode && GetVNode(node->ID(), dummyNode) == B_OK) {
+		// TODO: There still is a race condition here which we can't avoid
+		// without more help from the VFS. Right after we drop the write
+		// lock a vnode for the node could be discarded by the VFS. At that
+		// point another thread trying to get the vnode by ID would create
+		// a vnode, mark it busy and call our get_vnode() hook. It would
+		// block since we (i.e. the package loader thread executing this
+		// method) still have the volume write lock. Our get_vnode() call
+		// would block, since it finds the vnode marked busy. It times out
+		// eventually, but until then a good deal of FS operations might
+		// block as well due to us holding the volume lock and probably
+		// several node locks as well. A get_vnode*() variant (e.g.
+		// get_vnode_etc() with flags parameter) that wouldn't block and
+		// only get the vnode, if already loaded and non-busy, would be
+		// perfect here.
 		RemoveVNode(node->ID());
 		PutVNode(node->ID());
 	}

From c1ef23b188f363e95cc320103df70793a6fb3097 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 5 Nov 2011 17:20:45 +0100
Subject: [PATCH 0315/1170] PackageLinkDirectory::_Update(): Don't unlock after
 delete

When using an AutoLocker on an object, the lock must be released
explicitly before releasing the last certain reference to that object.
---
 .../kernel/file_systems/packagefs/PackageLinkDirectory.cpp    | 4 +++-
 1 file changed, 3 insertions(+), 1 deletion(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
index c5e1b450e3..ce14ceb957 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
@@ -175,11 +175,12 @@ PackageLinkDirectory::_Update(PackageLinksListener* listener)
 	// Always remove all dependency links -- if there's still a package, they
 	// will be re-created below.
 	while (DependencyLink* link = fDependencyLinks.RemoveHead()) {
-		NodeWriteLocker selfLinkLocker(link);
+		NodeWriteLocker linkLocker(link);
 		if (listener != NULL)
 			listener->PackageLinkNodeRemoved(link);
 
 		RemoveChild(link);
+		linkLocker.Unlock();
 		link->ReleaseReference();
 	}
 
@@ -193,6 +194,7 @@ PackageLinkDirectory::_Update(PackageLinksListener* listener)
 				listener->PackageLinkNodeRemoved(fSelfLink);
 
 			RemoveChild(fSelfLink);
+			selfLinkLocker.Unlock();
 			fSelfLink->ReleaseReference();
 			fSelfLink = NULL;
 		}

From 403bb7a568488f266b917f84f82381d3a342f0f5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 27 Mar 2013 19:11:38 +0000
Subject: [PATCH 0316/1170] haiku package info: declare a few provided commands

sh, awk, wget, etc. are currently provided by haiku.hpkg. Declare
them accordingly, since they are already referenced by some
HaikuPorts packates. For the generic ones ("sh", "awk") I've used
version 0.0.0 for the time being; we may need to reconsider that.
---
 src/data/package_infos/haiku | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku
index a5f3aef467..30a02e2a1e 100644
--- a/src/data/package_infos/haiku
+++ b/src/data/package_infos/haiku
@@ -17,6 +17,11 @@ licenses {
 
 provides {
 	haiku=R1-alpha3_pm-1 compat>=R1-alpha1
+	cmd:awk=0.0.0
+	cmd:sh=0.0.0
+	cmd:unzip=5.50
+	cmd:wget=0.0.0
+	cmd:zip=2.32
 }
 
 requires {

From 4e87ae1bbe89b24986fc1deab35d4dc0ad2cc5a2 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 27 Mar 2013 21:17:41 +0000
Subject: [PATCH 0317/1170] Repackaged xz-utils package

It is now declared with architecture x86_gcc2, though it probably
has been built with gcc4. That issue has to be solved for real
eventually, since the package resolver won't allow mixing of gcc2
and gcc4 packages.
---
 build/jam/OptionalPackages | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 4734f0f917..e45742f61e 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -1701,8 +1701,8 @@ if [ IsOptionalHaikuImagePackageAdded XZ-Utils ] {
 		Echo "No optional package XZ-Utils available for $(TARGET_ARCH)" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			xz-utils-5.0.1-1-x86.hpkg
-			: $(hpkgBaseURL)/xz-utils-5.0.1-1-x86.hpkg
+			xz-utils-5.0.1-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/xz-utils-5.0.1-2-x86_gcc2.hpkg
 			: common packages ;
 		AddExpanderRuleToHaikuImage "application/x-xz" : .tar.xz
 			: "tar -Jtvf \\0045s"

From 71051342011e696954083d95c00a9402d0ba22b5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 28 Mar 2013 00:17:37 +0000
Subject: [PATCH 0318/1170] haiku package info: Add more provided resolvable

Also add a compat version to a few.
---
 src/data/package_infos/haiku | 12 ++++++++++--
 1 file changed, 10 insertions(+), 2 deletions(-)

diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku
index 30a02e2a1e..8dbcb88d2c 100644
--- a/src/data/package_infos/haiku
+++ b/src/data/package_infos/haiku
@@ -17,11 +17,19 @@ licenses {
 
 provides {
 	haiku=R1-alpha3_pm-1 compat>=R1-alpha1
+	coreutils=8.4 compat>=0.0
+	diffutils=2.8.1 compat>=0.0
+	findutils=4.2.33 compat>=0.0
 	cmd:awk=0.0.0
+	cmd:cp=8.4 compat>=0.0
+	cmd:diff=2.8.1 compat>=0.0
+	cmd:find=4.2.33 compat>=0.0
+	cmd:ln=8.4 compat>=0.0
+	cmd:mv=8.4 compat>=0.0
 	cmd:sh=0.0.0
-	cmd:unzip=5.50
+	cmd:unzip=5.50 compat>=0.0
 	cmd:wget=0.0.0
-	cmd:zip=2.32
+	cmd:zip=2.32 compat>=0.0
 }
 
 requires {

From 90692f47f7132ef806aef9e210684520d91f2a4f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 28 Mar 2013 00:20:23 +0000
Subject: [PATCH 0319/1170] Rebuilt packages required for bootstrapping

---
 build/jam/OptionalPackages | 40 +++++++++++++++++++-------------------
 1 file changed, 20 insertions(+), 20 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index e45742f61e..07075068a9 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -496,20 +496,20 @@ if [ IsOptionalHaikuImagePackageAdded Development ] && $(TARGET_ARCH) = x86 {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			autoconf-2.68-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/autoconf-2.68-1-x86_gcc2.hpkg
+			autoconf-2.68-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/autoconf-2.68-2-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			automake-1.11.1-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/automake-1.11.1-1-x86_gcc2.hpkg
+			automake-1.11.1-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/automake-1.11.1-2-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			libtool-2.4-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/libtool-2.4-1-x86_gcc2.hpkg
+			libtool-2.4-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/libtool-2.4-2-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			texinfo-4.13a-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/texinfo-4.13a-1-x86_gcc2.hpkg
+			texinfo-4.13a-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/texinfo-4.13a-2-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -520,8 +520,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 		&& $(TARGET_ARCH) = x86 {
 	# gcc and binutils
 	if $(HAIKU_GCC_VERSION[1]) = 2 {
-		InstallOptionalHaikuImagePackage gcc-2.95.3_110711-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/gcc-2.95.3_110711-1-x86_gcc2.hpkg
+		InstallOptionalHaikuImagePackage gcc-2.95.3_110711-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/gcc-2.95.3_110711-2-x86_gcc2.hpkg
 			: common packages ;
 
 		# TODO: remove this when we have a mechanism to switch gcc via PATH
@@ -558,16 +558,16 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 			: $(baseURL)/make-3.82-r1a3-x86-gcc4-2011-05-23.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			bison-2.4.3-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/bison-2.4.3-1-x86_gcc2.hpkg
+			bison-2.4.3-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/bison-2.4.3-2-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			m4-1.4.16-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/m4-1.4.16-1-x86_gcc2.hpkg
+			m4-1.4.16-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/m4-1.4.16-2-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			flex-2.5.35-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/flex-2.5.35-1-x86_gcc2.hpkg
+			flex-2.5.35-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/flex-2.5.35-2-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
 			jam-2.5-1-x86_gcc2.hpkg
@@ -578,8 +578,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 			: $(hpkgBaseURL)/mkdepend-1.7-1-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			make-3.82-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/make-3.82-1-x86_gcc2.hpkg
+			make-3.82-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/make-3.82-2-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -1288,8 +1288,8 @@ if [ IsOptionalHaikuImagePackageAdded Perl ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				perl-5.10.1-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/perl-5.10.1-1-x86_gcc2.hpkg
+				perl-5.10.1-2-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/perl-5.10.1-2-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}

From dd60d4eef66f09888d14f599592956143c02a2a3 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 28 Mar 2013 12:16:41 +0000
Subject: [PATCH 0320/1170] OptionalPackages: Fix CVS URL

Due to a copy'n'paste error the curl package was used. While at it,
use the rebuilt package.
---
 build/jam/OptionalPackages | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 07075068a9..c783890388 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -466,8 +466,8 @@ if [ IsOptionalHaikuImagePackageAdded CVS ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				cvs-1.12.13.1-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/curl-7.21.6-1-x86_gcc2.hpkg
+				cvs-1.12.13.1-2-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/cvs-1.12.13.1-2-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}

From a8026c5f5771f8b1e51a4ec38fdde3366bf0f6dc Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 28 Mar 2013 12:18:21 +0000
Subject: [PATCH 0321/1170] haiku package info: List zlib in provides

---
 src/data/package_infos/haiku | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku
index 8dbcb88d2c..55013927ee 100644
--- a/src/data/package_infos/haiku
+++ b/src/data/package_infos/haiku
@@ -30,6 +30,7 @@ provides {
 	cmd:unzip=5.50 compat>=0.0
 	cmd:wget=0.0.0
 	cmd:zip=2.32 compat>=0.0
+	lib:zlib=1.2.5 compat>=1
 }
 
 requires {

From e3926e56694a5c5bd72ebfb99eaeb31d71649f94 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 28 Mar 2013 13:18:47 +0000
Subject: [PATCH 0322/1170] haiku package info: Fix zlib provides declaration

---
 src/data/package_infos/haiku | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku
index 55013927ee..c72c65d1fb 100644
--- a/src/data/package_infos/haiku
+++ b/src/data/package_infos/haiku
@@ -20,6 +20,7 @@ provides {
 	coreutils=8.4 compat>=0.0
 	diffutils=2.8.1 compat>=0.0
 	findutils=4.2.33 compat>=0.0
+	zlib=1.2.5 compat>=1
 	cmd:awk=0.0.0
 	cmd:cp=8.4 compat>=0.0
 	cmd:diff=2.8.1 compat>=0.0
@@ -30,7 +31,7 @@ provides {
 	cmd:unzip=5.50 compat>=0.0
 	cmd:wget=0.0.0
 	cmd:zip=2.32 compat>=0.0
-	lib:zlib=1.2.5 compat>=1
+	lib:libz=1.2.5 compat>=1
 }
 
 requires {

From 3f986502fd1231831200038bbf5f75f1ef1c82ea Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 29 Mar 2013 02:09:20 +0000
Subject: [PATCH 0323/1170] Rebuilt packages for subversion and its
 dependencies

---
 build/jam/OptionalBuildFeatures |  2 +-
 build/jam/OptionalPackages      | 32 ++++++++++++++++----------------
 2 files changed, 17 insertions(+), 17 deletions(-)

diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures
index 232169caa3..7b8c1903ab 100644
--- a/build/jam/OptionalBuildFeatures
+++ b/build/jam/OptionalBuildFeatures
@@ -14,7 +14,7 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSL ] {
 if $(HAIKU_GCC_VERSION[1]) >= 4 {
 	HAIKU_OPENSSL_PACKAGE = openssl-1.0.0e-x86-gcc4-2011-09-08.zip ;
 } else {
-	HAIKU_OPENSSL_PACKAGE = openssl-1.0.0d-1-x86_gcc2.hpkg ;
+	HAIKU_OPENSSL_PACKAGE = openssl-1.0.0d-2-x86_gcc2.hpkg ;
 }
 
 local baseURL = http://haiku-files.org/files/optional-packages ;
diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index c783890388..7865db5ad0 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -113,8 +113,8 @@ if [ IsOptionalHaikuImagePackageAdded APR ] {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			apr-1.4.2-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/apr-1.4.2-1-x86_gcc2.hpkg
+			apr-1.4.2-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/apr-1.4.2-2-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -131,8 +131,8 @@ if [ IsOptionalHaikuImagePackageAdded APR-util ] {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			apr-util-1.3.10-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/apr-util-1.3.10-1-x86_gcc2.hpkg
+			apr-util-1.3.10-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/apr-util-1.3.10-2-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -667,8 +667,8 @@ if [ IsOptionalHaikuImagePackageAdded Expat ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				expat-2.0.1-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/expat-2.0.1-1-x86_gcc2.hpkg
+				expat-2.0.1-2-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/expat-2.0.1-2-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -881,8 +881,8 @@ if [ IsOptionalHaikuImagePackageAdded LibIconv ] {
 				: $(baseURL)/libiconv-1.13.1-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				libiconv-1.13.1-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/libiconv-1.13.1-1-x86_gcc2.hpkg
+				libiconv-1.13.1-2-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/libiconv-1.13.1-2-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -929,8 +929,8 @@ if [ IsOptionalHaikuImagePackageAdded LibXML2 ] {
 				: $(baseURL)/libxml2-2.7.8-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				libxml2-2.7.8-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/libxml2-2.7.8-1-x86_gcc2.hpkg
+				libxml2-2.7.8-2-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/libxml2-2.7.8-2-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1061,8 +1061,8 @@ if [ IsOptionalHaikuImagePackageAdded Neon ] {
 				: $(baseURL)/neon-0.29.6-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				neon-0.29.6-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/neon-0.29.6-1-x86_gcc2.hpkg
+				neon-0.29.6-2-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/neon-0.29.6-2-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1380,8 +1380,8 @@ if [ IsOptionalHaikuImagePackageAdded SQLite ] {
 				: $(baseURL)/sqlite-3.7.5-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				sqlite3-3.7.5-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/sqlite3-3.7.5-1-x86_gcc2.hpkg
+				sqlite-3.7.5-2-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/sqlite-3.7.5-2-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1400,8 +1400,8 @@ if [ IsOptionalHaikuImagePackageAdded Subversion ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				subversion-1.6.15-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/subversion-1.6.15-1-x86_gcc2.hpkg
+				subversion-1.6.15-2-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/subversion-1.6.15-2-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}

From 999234242738bc3a6cb67500736da110ba87f6d8 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 29 Mar 2013 19:44:12 +0000
Subject: [PATCH 0324/1170] package_repo: command_create(): Fix argument count
 check

---
 src/bin/package_repo/command_create.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/bin/package_repo/command_create.cpp b/src/bin/package_repo/command_create.cpp
index f999171855..ab245c7aa3 100644
--- a/src/bin/package_repo/command_create.cpp
+++ b/src/bin/package_repo/command_create.cpp
@@ -155,7 +155,7 @@ command_create(int argc, const char* const* argv)
 
 	// The remaining arguments are the repository info file plus one or more
 	// package files, i.e. at least two more arguments.
-	if (optind + 2 >= argc)
+	if (optind + 2 > argc)
 		print_usage_and_exit(true);
 
 	const char* repositoryInfoFileName = argv[optind++];

From 10efbe6c5e9350b8683d5b79ca6b9c75d61131a2 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 29 Mar 2013 20:09:20 +0000
Subject: [PATCH 0325/1170] BRepositoryInfo::SetTo(): driver settings unloaded
 too early

The string pointers retrieved from the driver settings are only valid until
the settings handle is freed. The were also used afterwards, though.
---
 src/kits/package/RepositoryInfo.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/kits/package/RepositoryInfo.cpp b/src/kits/package/RepositoryInfo.cpp
index 1ef4d40c4a..5dce7e1fa7 100644
--- a/src/kits/package/RepositoryInfo.cpp
+++ b/src/kits/package/RepositoryInfo.cpp
@@ -17,6 +17,7 @@
 #include 
 #include 
 
+#include 
 #include 
 
 
@@ -182,6 +183,8 @@ BRepositoryInfo::SetTo(const BEntry& entry)
 	void* settingsHandle = parse_driver_settings_string(configString.String());
 	if (settingsHandle == NULL)
 		return B_BAD_DATA;
+	CObjectDeleter settingsHandleDeleter(settingsHandle,
+		&unload_driver_settings);
 
 	const char* name = get_driver_parameter(settingsHandle, "name", NULL, NULL);
 	const char* url = get_driver_parameter(settingsHandle, "url", NULL, NULL);
@@ -194,8 +197,6 @@ BRepositoryInfo::SetTo(const BEntry& entry)
 	const char* architectureString
 		= get_driver_parameter(settingsHandle, "architecture", NULL, NULL);
 
-	unload_driver_settings(settingsHandle);
-
 	if (name == NULL || *name == '\0' || url == NULL || *url == '\0'
 		|| vendor == NULL || *vendor == '\0'
 		|| summary == NULL || *summary == '\0'

From 479ca8169c85621dda097bebe337bcc373eba68f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 1 Apr 2013 00:25:37 +0000
Subject: [PATCH 0326/1170] Beginnings of the PackageKit dependency solver

Not functional (or tested) yet. The libsolv setup for a somewhat
simplified installation case should be more or less complete, though.
The solution conversion to to-be-created Haiku data structures and the
handling of problems is still missing, though.
---
 headers/os/package/solver/Solver.h            |  43 +++
 .../package/solver/SolverPackageSpecifier.h   |  47 +++
 .../solver/SolverPackageSpecifierList.h       |  46 +++
 headers/os/package/solver/SolverRepository.h  |  69 ++++
 src/kits/package/Jamfile                      |   2 +
 src/kits/package/solver/Jamfile               |  23 ++
 src/kits/package/solver/Solver.cpp            | 356 ++++++++++++++++++
 .../package/solver/SolverPackageSpecifier.cpp |  79 ++++
 .../solver/SolverPackageSpecifierList.cpp     | 125 ++++++
 src/kits/package/solver/SolverRepository.cpp  | 235 ++++++++++++
 10 files changed, 1025 insertions(+)
 create mode 100644 headers/os/package/solver/Solver.h
 create mode 100644 headers/os/package/solver/SolverPackageSpecifier.h
 create mode 100644 headers/os/package/solver/SolverPackageSpecifierList.h
 create mode 100644 headers/os/package/solver/SolverRepository.h
 create mode 100644 src/kits/package/solver/Jamfile
 create mode 100644 src/kits/package/solver/Solver.cpp
 create mode 100644 src/kits/package/solver/SolverPackageSpecifier.cpp
 create mode 100644 src/kits/package/solver/SolverPackageSpecifierList.cpp
 create mode 100644 src/kits/package/solver/SolverRepository.cpp

diff --git a/headers/os/package/solver/Solver.h b/headers/os/package/solver/Solver.h
new file mode 100644
index 0000000000..d52d73905c
--- /dev/null
+++ b/headers/os/package/solver/Solver.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__SOLVER_H_
+#define _PACKAGE__SOLVER_H_
+
+
+#include 
+
+
+namespace BPackageKit {
+
+
+class BSolverPackageSpecifierList;
+class BSolverRepository;
+
+
+class BSolver {
+public:
+								BSolver();
+								~BSolver();
+
+			status_t			Init();
+
+			status_t			AddRepository(BSolverRepository* repository);
+
+			status_t			Install(
+									const BSolverPackageSpecifierList&
+										packages);
+
+private:
+			class Implementation;
+
+private:
+			Implementation*		fImplementation;
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif // _PACKAGE__SOLVER_H_
diff --git a/headers/os/package/solver/SolverPackageSpecifier.h b/headers/os/package/solver/SolverPackageSpecifier.h
new file mode 100644
index 0000000000..cfef5849a2
--- /dev/null
+++ b/headers/os/package/solver/SolverPackageSpecifier.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__SOLVER_PACKAGE_SPECIFIER_H_
+#define _PACKAGE__SOLVER_PACKAGE_SPECIFIER_H_
+
+
+#include 
+
+
+namespace BPackageKit {
+
+
+class BSolverRepository;
+
+
+class BSolverPackageSpecifier {
+public:
+								BSolverPackageSpecifier();
+								BSolverPackageSpecifier(
+									const BPackageResolvableExpression&
+										expression);
+								BSolverPackageSpecifier(
+									BSolverRepository* repository,
+									const BPackageResolvableExpression&
+										expression);
+								BSolverPackageSpecifier(
+									const BSolverPackageSpecifier& other);
+								~BSolverPackageSpecifier();
+
+			BSolverRepository*	Repository() const;
+			const BPackageResolvableExpression& Expression() const;
+
+			BSolverPackageSpecifier& operator=(
+									const BSolverPackageSpecifier& other);
+
+private:
+			BSolverRepository*	fRepository;
+			BPackageResolvableExpression fExpression;
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif // _PACKAGE__SOLVER_PACKAGE_SPECIFIER_H_
diff --git a/headers/os/package/solver/SolverPackageSpecifierList.h b/headers/os/package/solver/SolverPackageSpecifierList.h
new file mode 100644
index 0000000000..0557dec065
--- /dev/null
+++ b/headers/os/package/solver/SolverPackageSpecifierList.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__SOLVER_PACKAGE_SPECIFIER_LIST_H_
+#define _PACKAGE__SOLVER_PACKAGE_SPECIFIER_LIST_H_
+
+
+#include 
+
+
+namespace BPackageKit {
+
+
+class BSolverPackageSpecifier;
+
+
+class BSolverPackageSpecifierList {
+public:
+								BSolverPackageSpecifierList();
+								BSolverPackageSpecifierList(
+									const BSolverPackageSpecifierList& other);
+								~BSolverPackageSpecifierList();
+
+			bool				IsEmpty() const;
+			int32				CountSpecifiers() const;
+			const BSolverPackageSpecifier* SpecifierAt(int32 index) const;
+
+			bool				AppendSpecifier(
+									const BSolverPackageSpecifier& specifier);
+
+			BSolverPackageSpecifierList& operator=(
+									const BSolverPackageSpecifierList& other);
+
+private:
+			class Vector;
+
+private:
+			Vector*				fSpecifiers;
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif // _PACKAGE__SOLVER_PACKAGE_SPECIFIER_LIST_H_
diff --git a/headers/os/package/solver/SolverRepository.h b/headers/os/package/solver/SolverRepository.h
new file mode 100644
index 0000000000..579512dda0
--- /dev/null
+++ b/headers/os/package/solver/SolverRepository.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__SOLVER_REPOSITORY_H_
+#define _PACKAGE__SOLVER_REPOSITORY_H_
+
+
+#include 
+#include 
+#include 
+
+
+namespace BPackageKit {
+
+
+class BPackageInfo;
+class BRepositoryConfig;
+
+
+class BSolverRepository {
+public:
+			enum BAllInstallationLocations {
+				B_ALL_INSTALLATION_LOCATIONS
+			};
+
+			typedef BPackageInfoSet::Iterator Iterator;
+
+public:
+								BSolverRepository();
+								BSolverRepository(const BString& name);
+								BSolverRepository(
+									BPackageInstallationLocation location);
+								BSolverRepository(BAllInstallationLocations);
+								BSolverRepository(
+									const BRepositoryConfig& config);
+								~BSolverRepository();
+
+			status_t			SetTo(const BString& name);
+			status_t			SetTo(BPackageInstallationLocation location);
+			status_t			SetTo(BAllInstallationLocations);
+			status_t			SetTo(const BRepositoryConfig& config);
+			void				Unset();
+
+			status_t			InitCheck();
+
+			bool				IsInstalled() const;
+
+			BString				Name() const;
+			uint8				Priority() const;
+
+			status_t			AddPackage(const BPackageInfo& info);
+			status_t			AddPackages(
+									BPackageInstallationLocation location);
+
+			Iterator			GetIterator() const;
+
+private:
+			BString				fName;
+			uint8				fPriority;
+			bool				fIsInstalled;
+			BPackageInfoSet		fPackages;
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif // _PACKAGE__SOLVER_REPOSITORY_H_
diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile
index a73037b36f..207e6a1aa7 100644
--- a/src/kits/package/Jamfile
+++ b/src/kits/package/Jamfile
@@ -74,3 +74,5 @@ SharedLibrary libpackage.so
 	:
 	libshared.a be z $(TARGET_LIBSTDC++)
 ;
+
+HaikuSubInclude solver ;
diff --git a/src/kits/package/solver/Jamfile b/src/kits/package/solver/Jamfile
new file mode 100644
index 0000000000..06ea5a5db2
--- /dev/null
+++ b/src/kits/package/solver/Jamfile
@@ -0,0 +1,23 @@
+SubDir HAIKU_TOP src kits package solver ;
+
+UsePrivateHeaders shared ;
+
+# TODO: Add properly to BuildFeatures and remove here!
+HAIKU_LIBSOLV_INSTALL_DIR ?= /Transfer/ports/libsolv-install/boot/common ;
+HAIKU_LIBSOLV_HEADERS ?= $(HAIKU_LIBSOLV_INSTALL_DIR)/include ;
+HAIKU_LIBSOLV_LIBS ?= $(HAIKU_LIBSOLV_INSTALL_DIR)/lib/libsolv.so
+	$(HAIKU_LIBSOLV_INSTALL_DIR)/lib/libsolvext.so ;
+
+SubDirSysHdrs $(HAIKU_LIBSOLV_HEADERS) ;
+SubDirHdrs $(HAIKU_LIBSOLV_HEADERS)/solv ;
+
+
+SharedLibrary libpackage_solver.so
+	:
+	Solver.cpp
+	SolverPackageSpecifier.cpp
+	SolverPackageSpecifierList.cpp
+	SolverRepository.cpp
+	:
+	package $(HAIKU_LIBSOLV_LIBS) be $(TARGET_LIBSTDC++)
+;
diff --git a/src/kits/package/solver/Solver.cpp b/src/kits/package/solver/Solver.cpp
new file mode 100644
index 0000000000..10ff02d2d4
--- /dev/null
+++ b/src/kits/package/solver/Solver.cpp
@@ -0,0 +1,356 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+
+// TODO: libsolv doesn't have any helpful out-of-memory handling. It just just
+// abort()s. Obviously that isn't good behavior for a library.
+
+
+namespace BPackageKit {
+
+
+// #pragma mark - BSolver::Implementation
+
+
+class BSolver::Implementation {
+public:
+								Implementation();
+								~Implementation();
+
+			status_t			Init();
+
+			status_t			AddRepository(BSolverRepository* repository);
+
+			status_t			Install(
+									const BSolverPackageSpecifierList&
+										packages);
+
+private:
+			struct SolvQueue;
+			struct RepositoryInfo;
+
+			typedef BObjectList RepositoryInfoList;
+
+private:
+			status_t			_AddRepositories();
+			RepositoryInfo*		_GetRepositoryInfo(
+									BSolverRepository* repository) const;
+
+private:
+			Pool*				fPool;
+			RepositoryInfoList	fRepositoryInfos;
+			RepositoryInfo*		fInstalledRepository;
+};
+
+
+struct BSolver::Implementation::SolvQueue : Queue {
+	SolvQueue()
+	{
+		queue_init(this);
+	}
+
+	~SolvQueue()
+	{
+		queue_free(this);
+	}
+};
+
+
+struct BSolver::Implementation::RepositoryInfo {
+	RepositoryInfo(BSolverRepository* repository)
+		:
+		fRepository(repository),
+		fSolvRepo(NULL)
+	{
+	}
+
+	BSolverRepository* Repository() const
+	{
+		return fRepository;
+	}
+
+	Repo* SolvRepo()
+	{
+		return fSolvRepo;
+	}
+
+	void SetSolvRepo(Repo* repo)
+	{
+		fSolvRepo = repo;
+	}
+
+private:
+	BSolverRepository*	fRepository;
+	Repo*				fSolvRepo;
+};
+
+
+// #pragma mark - BSolver
+
+
+BSolver::BSolver()
+	:
+	fImplementation(new(std::nothrow) Implementation)
+{
+}
+
+
+BSolver::~BSolver()
+{
+	delete fImplementation;
+}
+
+
+status_t
+BSolver::Init()
+{
+	return fImplementation != NULL ? fImplementation->Init() : B_NO_MEMORY;
+}
+
+
+status_t
+BSolver::AddRepository(BSolverRepository* repository)
+{
+	return fImplementation != NULL
+		? fImplementation->AddRepository(repository) : B_NO_MEMORY;
+}
+
+
+status_t
+BSolver::Install(const BSolverPackageSpecifierList& packages)
+{
+	return fImplementation != NULL
+		? fImplementation->Install(packages) : B_NO_MEMORY;
+}
+
+
+// #pragma mark - BSolver::Implementation
+
+
+BSolver::Implementation::Implementation()
+	:
+	fPool(NULL),
+	fRepositoryInfos(),
+	fInstalledRepository(NULL)
+{
+}
+
+
+BSolver::Implementation::~Implementation()
+{
+	if (fPool != NULL)
+		pool_free(fPool);
+}
+
+
+status_t
+BSolver::Implementation::Init()
+{
+	// already initialized?
+	if (fPool != NULL)
+		return B_BAD_VALUE;
+
+	fPool = pool_create();
+
+	// Set the system architecture. We use what uname() returns unless we're on
+	// x86 gcc2.
+	{
+		const char* arch;
+		#ifdef __HAIKU_ARCH_X86
+			#if (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2
+				arch = "x86_gcc2";
+			#else
+				arch = "x86";
+			#endif
+		#else
+			struct utsname info;
+			if (uname(&info) != 0)
+				return errno;
+			arch = info.machine;
+		#endif
+
+		pool_setarchpolicy(fPool, arch);
+	}
+
+	return B_OK;
+}
+
+
+status_t
+BSolver::Implementation::AddRepository(BSolverRepository* repository)
+{
+	if (repository == NULL || repository->InitCheck() != B_OK)
+		return B_BAD_VALUE;
+
+	// If the repository represents installed packages, check, if we already
+	// have such a repository.
+	if (repository->IsInstalled() && fInstalledRepository != NULL)
+		return B_BAD_VALUE;
+
+	// add the repository info
+	RepositoryInfo* info = new(std::nothrow) RepositoryInfo(repository);
+	if (info == NULL)
+		return B_NO_MEMORY;
+
+	if (!fRepositoryInfos.AddItem(info)) {
+		delete info;
+		return B_NO_MEMORY;
+	}
+
+	if (repository->IsInstalled())
+		fInstalledRepository = info;
+
+	return B_OK;
+}
+
+
+status_t
+BSolver::Implementation::Install(const BSolverPackageSpecifierList& packages)
+{
+	if (packages.IsEmpty())
+		return B_BAD_VALUE;
+
+// TODO: Clean up first?
+
+	// add repositories to pool
+	status_t error = _AddRepositories();
+	if (error != B_OK)
+		return error;
+
+	// prepare pool for solving
+	pool_createwhatprovides(fPool);
+
+	// add the packages to install to the job queue
+	SolvQueue jobs;
+
+	int32 packageCount = packages.CountSpecifiers();
+	for (int32 i = 0; i < packageCount; i++) {
+		const BSolverPackageSpecifier& specifier = *packages.SpecifierAt(i);
+
+		// find matching packages
+		SolvQueue matchingPackages;
+
+		int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB
+			| SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL;
+// TODO: All flags needed/useful?
+		/*int matchFlags =*/ selection_make(fPool, &matchingPackages,
+			specifier.Expression().Name(), flags);
+// TODO: Don't just match the name, but also the version, if given!
+		if (matchingPackages.count == 0)
+			return B_NAME_NOT_FOUND;
+
+		// restrict to the matching repository
+		if (BSolverRepository* repository = specifier.Repository()) {
+			RepositoryInfo* repositoryInfo = _GetRepositoryInfo(repository);
+			if (repositoryInfo == NULL)
+				return B_BAD_VALUE;
+
+			SolvQueue repoFilter;
+			queue_push2(&repoFilter,
+				SOLVER_SOLVABLE_REPO/* | SOLVER_SETREPO | SOLVER_SETVENDOR*/,
+				repositoryInfo->SolvRepo()->repoid);
+
+			selection_filter(fPool, &matchingPackages, &repoFilter);
+
+			if (matchingPackages.count == 0)
+				return B_NAME_NOT_FOUND;
+		}
+
+		for (int j = 0; j < matchingPackages.count; j++)
+			queue_push(&jobs, matchingPackages.elements[j]);
+	}
+
+	// add solver mode to job queue elements
+	int solverMode = SOLVER_INSTALL;
+	for (int i = 0; i < jobs.count; i += 2) {
+		jobs.elements[i] |= solverMode;
+//		if (cleandeps)
+//			jobs.elements[i] |= SOLVER_CLEANDEPS;
+//		if (forcebest)
+//			jobs.elements[i] |= SOLVER_FORCEBEST;
+	}
+
+	// create the solver and solve
+	Solver* solver = solver_create(fPool);
+	solver_set_flag(solver, SOLVER_FLAG_SPLITPROVIDES, 1);
+	solver_set_flag(solver, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
+
+	int problemCount = solver_solve(solver, &jobs);
+	solver_free(solver);
+
+// TODO: Problem support!
+	return problemCount == 0 ? B_OK : B_BAD_VALUE;
+}
+
+
+status_t
+BSolver::Implementation::_AddRepositories()
+{
+	if (fInstalledRepository == NULL)
+		return B_BAD_VALUE;
+
+	int32 repositoryCount = fRepositoryInfos.CountItems();
+	for (int32 i = 0; i < repositoryCount; i++) {
+		RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
+		BSolverRepository* repository = repositoryInfo->Repository();
+		Repo* repo = repo_create(fPool, repository->Name());
+		repositoryInfo->SetSolvRepo(repo);
+
+		repo->priority = 256 - repository->Priority();
+		repo->appdata = (void*)repositoryInfo;
+
+		BRepositoryCache::Iterator it = repository->GetIterator();
+		while (const BPackageInfo* packageInfo = it.Next()) {
+			repo_add_haiku_package_info(repo, *packageInfo,
+				REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE);
+		}
+
+		repo_internalize(repo);
+
+		if (repository->IsInstalled())
+			pool_set_installed(fPool, repo);
+	}
+
+	return B_OK;
+}
+
+
+BSolver::Implementation::RepositoryInfo*
+BSolver::Implementation::_GetRepositoryInfo(BSolverRepository* repository) const
+{
+	int32 repositoryCount = fRepositoryInfos.CountItems();
+	for (int32 i = 0; i < repositoryCount; i++) {
+		RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
+		if (repository == repositoryInfo->Repository())
+			return repositoryInfo;
+	}
+
+	return NULL;
+}
+
+
+}	// namespace BPackageKit
diff --git a/src/kits/package/solver/SolverPackageSpecifier.cpp b/src/kits/package/solver/SolverPackageSpecifier.cpp
new file mode 100644
index 0000000000..c1469d422a
--- /dev/null
+++ b/src/kits/package/solver/SolverPackageSpecifier.cpp
@@ -0,0 +1,79 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+
+namespace BPackageKit {
+
+
+BSolverPackageSpecifier::BSolverPackageSpecifier()
+	:
+	fRepository(NULL),
+	fExpression()
+{
+}
+
+
+BSolverPackageSpecifier::BSolverPackageSpecifier(
+	const BPackageResolvableExpression& expression)
+	:
+	fRepository(NULL),
+	fExpression(expression)
+{
+}
+
+
+BSolverPackageSpecifier::BSolverPackageSpecifier(BSolverRepository* repository,
+	const BPackageResolvableExpression& expression)
+	:
+	fRepository(repository),
+	fExpression(expression)
+{
+}
+
+
+BSolverPackageSpecifier::BSolverPackageSpecifier(
+	const BSolverPackageSpecifier& other)
+	:
+	fRepository(other.fRepository),
+	fExpression(other.fExpression)
+{
+}
+
+
+BSolverPackageSpecifier::~BSolverPackageSpecifier()
+{
+}
+
+
+BSolverRepository*
+BSolverPackageSpecifier::Repository() const
+{
+	return fRepository;
+}
+
+
+const BPackageResolvableExpression&
+BSolverPackageSpecifier::Expression() const
+{
+	return fExpression;
+}
+
+
+BSolverPackageSpecifier&
+BSolverPackageSpecifier::operator=(const BSolverPackageSpecifier& other)
+{
+	fRepository = other.fRepository;
+	fExpression = other.fExpression;
+	return *this;
+}
+
+
+}	// namespace BPackageKit
diff --git a/src/kits/package/solver/SolverPackageSpecifierList.cpp b/src/kits/package/solver/SolverPackageSpecifierList.cpp
new file mode 100644
index 0000000000..b15c776a5f
--- /dev/null
+++ b/src/kits/package/solver/SolverPackageSpecifierList.cpp
@@ -0,0 +1,125 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+#include 
+#include 
+
+#include 
+
+
+namespace BPackageKit {
+
+class BSolverPackageSpecifierList::Vector
+	: public std::vector {
+public:
+	Vector()
+		:
+		std::vector()
+	{
+	}
+
+	Vector(const std::vector& other)
+		:
+		std::vector(other)
+	{
+	}
+};
+
+
+BSolverPackageSpecifierList::BSolverPackageSpecifierList()
+	:
+	fSpecifiers(NULL)
+{
+}
+
+	
+BSolverPackageSpecifierList::BSolverPackageSpecifierList(
+	const BSolverPackageSpecifierList& other)
+	:
+	fSpecifiers(NULL)
+{
+	*this = other;
+}
+
+
+BSolverPackageSpecifierList::~BSolverPackageSpecifierList()
+{
+	delete fSpecifiers;
+}
+
+
+bool
+BSolverPackageSpecifierList::IsEmpty() const
+{
+	return fSpecifiers == NULL || fSpecifiers->empty();
+}
+
+
+int32
+BSolverPackageSpecifierList::CountSpecifiers() const
+{
+	return fSpecifiers != NULL ? fSpecifiers->size() : 0;
+}
+
+
+const BSolverPackageSpecifier*
+BSolverPackageSpecifierList::SpecifierAt(int32 index) const
+{
+	if (fSpecifiers == NULL || index < 0
+		|| (size_t)index >= fSpecifiers->size()) {
+		return NULL;
+	}
+
+	return &(*fSpecifiers)[index];
+}
+
+
+bool
+BSolverPackageSpecifierList::AppendSpecifier(
+	const BSolverPackageSpecifier& specifier)
+{
+	try {
+		if (fSpecifiers == NULL) {
+			fSpecifiers = new(std::nothrow) Vector;
+			if (fSpecifiers == NULL)
+				return false;
+		}
+
+		fSpecifiers->push_back(specifier);
+		return true;
+	} catch (std::bad_alloc&) {
+		return false;
+	}
+}
+
+
+BSolverPackageSpecifierList&
+BSolverPackageSpecifierList::operator=(const BSolverPackageSpecifierList& other)
+{
+	if (this == &other)
+		return *this;
+
+	delete fSpecifiers;
+	fSpecifiers = NULL;
+
+	if (other.fSpecifiers == NULL)
+		return *this;
+
+	try {
+		fSpecifiers = new(std::nothrow) Vector(*other.fSpecifiers);
+	} catch (std::bad_alloc&) {
+	}
+
+	return *this;
+}
+
+
+}	// namespace BPackageKit
diff --git a/src/kits/package/solver/SolverRepository.cpp b/src/kits/package/solver/SolverRepository.cpp
new file mode 100644
index 0000000000..93c2f78707
--- /dev/null
+++ b/src/kits/package/solver/SolverRepository.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+
+namespace BPackageKit {
+
+
+BSolverRepository::BSolverRepository()
+	:
+	fName(),
+	fPriority(0),
+	fIsInstalled(false),
+	fPackages()
+{
+}
+
+
+BSolverRepository::BSolverRepository(const BString& name)
+	:
+	fName(),
+	fPriority(0),
+	fIsInstalled(false),
+	fPackages()
+{
+	SetTo(name);
+}
+
+
+BSolverRepository::BSolverRepository(BPackageInstallationLocation location)
+	:
+	fName(),
+	fPriority(0),
+	fIsInstalled(false),
+	fPackages()
+{
+	SetTo(location);
+}
+
+
+BSolverRepository::BSolverRepository(BAllInstallationLocations)
+	:
+	fName(),
+	fPriority(0),
+	fIsInstalled(false),
+	fPackages()
+{
+	SetTo(B_ALL_INSTALLATION_LOCATIONS);
+}
+
+
+BSolverRepository::BSolverRepository(const BRepositoryConfig& config)
+	:
+	fName(),
+	fPriority(0),
+	fIsInstalled(false),
+	fPackages()
+{
+	SetTo(config);
+}
+
+
+BSolverRepository::~BSolverRepository()
+{
+}
+
+
+status_t
+BSolverRepository::SetTo(const BString& name)
+{
+	Unset();
+
+	fName = name;
+	return fName.IsEmpty() ? B_BAD_VALUE : B_OK;
+}
+
+
+status_t
+BSolverRepository::SetTo(BPackageInstallationLocation location)
+{
+	Unset();
+
+	fName = "Installed";
+
+	status_t error = AddPackages(location);
+	if (error != B_OK) {
+		Unset();
+		return error;
+	}
+
+	fIsInstalled = true;
+	return B_OK;
+}
+
+
+status_t
+BSolverRepository::SetTo(BAllInstallationLocations)
+{
+	status_t error = SetTo(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM);
+	if (error != B_OK)
+		return error;
+
+	error = AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON);
+	if (error != B_OK) {
+		Unset();
+		return error;
+	}
+
+	error = AddPackages(B_PACKAGE_INSTALLATION_LOCATION_HOME);
+	if (error != B_OK) {
+		Unset();
+		return error;
+	}
+
+	return B_OK;
+}
+
+
+status_t
+BSolverRepository::SetTo(const BRepositoryConfig& config)
+{
+	Unset();
+
+	if (config.InitCheck() != B_OK)
+		return B_BAD_VALUE;
+
+	fName = config.Name();
+	fPriority = config.Priority();
+
+	BPackageRoster roster;
+	BRepositoryCache cache;
+	status_t error = roster.GetRepositoryCache(config.Name(), &cache);
+	if (error != B_OK) {
+		Unset();
+		return error;
+	}
+
+	BRepositoryCache::Iterator it = cache.GetIterator();
+	while (const BPackageInfo* packageInfo = it.Next()) {
+		error = AddPackage(*packageInfo);
+		if (error != B_OK) {
+			Unset();
+			return error;
+		}
+	}
+
+	return B_OK;
+}
+
+
+void
+BSolverRepository::Unset()
+{
+	fName = BString();
+	fPriority = 0;
+	fIsInstalled = false;
+	fPackages.MakeEmpty();
+}
+
+
+status_t
+BSolverRepository::InitCheck()
+{
+	return fName.IsEmpty() ? B_NO_INIT : B_OK;
+}
+
+
+bool
+BSolverRepository::IsInstalled() const
+{
+	return fIsInstalled;
+}
+
+
+BString
+BSolverRepository::Name() const
+{
+	return fName;
+}
+
+
+uint8
+BSolverRepository::Priority() const
+{
+	return fPriority;
+}
+
+
+status_t
+BSolverRepository::AddPackage(const BPackageInfo& info)
+{
+	return fPackages.AddInfo(info);
+}
+
+
+status_t
+BSolverRepository::AddPackages(BPackageInstallationLocation location)
+{
+	BPackageRoster roster;
+	BPackageInfoSet packageInfos;
+	status_t error = roster.GetActivePackages(location, packageInfos);
+	if (error != B_OK)
+		return error;
+
+	BRepositoryCache::Iterator it = packageInfos.GetIterator();
+	while (const BPackageInfo* packageInfo = it.Next()) {
+		error = fPackages.AddInfo(*packageInfo);
+		if (error != B_OK)
+			return error;
+	}
+
+	return B_OK;
+}
+
+
+BSolverRepository::Iterator
+BSolverRepository::GetIterator() const
+{
+	return fPackages.GetIterator();
+}
+
+
+}	// namespace BPackageKit

From 0816749e41c0757e4e3269e18ffc333b64deb1c8 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 1 Apr 2013 23:06:33 +0000
Subject: [PATCH 0327/1170] package_repo: Removes dependency to package

* Move StandardErrorOutput to libpackage and into proper namespace to
  avoid "package_repo" having to reuse the "package" source file.
* package_repo: Fix incorrect includes of "package.h".
---
 headers/os/package/hpkg/StandardErrorOutput.h | 29 +++++++++++++++++++
 src/bin/package/Jamfile                       |  1 -
 src/bin/package/StandardErrorOutput.cpp       | 16 ----------
 src/bin/package/StandardErrorOutput.h         | 21 --------------
 src/bin/package/command_add.cpp               |  1 -
 src/bin/package/command_create.cpp            |  1 -
 src/bin/package/command_dump.cpp              |  4 +--
 src/bin/package/command_extract.cpp           |  4 +--
 src/bin/package/command_list.cpp              |  4 +--
 src/bin/package_repo/Jamfile                  |  3 --
 src/bin/package_repo/command_create.cpp       |  3 +-
 src/bin/package_repo/command_list.cpp         |  6 ++--
 src/kits/package/Jamfile                      |  4 +++
 src/kits/package/hpkg/StandardErrorOutput.cpp | 26 +++++++++++++++++
 14 files changed, 69 insertions(+), 54 deletions(-)
 create mode 100644 headers/os/package/hpkg/StandardErrorOutput.h
 delete mode 100644 src/bin/package/StandardErrorOutput.cpp
 delete mode 100644 src/bin/package/StandardErrorOutput.h
 create mode 100644 src/kits/package/hpkg/StandardErrorOutput.cpp

diff --git a/headers/os/package/hpkg/StandardErrorOutput.h b/headers/os/package/hpkg/StandardErrorOutput.h
new file mode 100644
index 0000000000..c2ffa31bab
--- /dev/null
+++ b/headers/os/package/hpkg/StandardErrorOutput.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2009-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__HPKG__STANDARD_ERROR_OUTPUT_H_
+#define _PACKAGE__HPKG__STANDARD_ERROR_OUTPUT_H_
+
+
+#include 
+
+
+namespace BPackageKit {
+
+namespace BHPKG {
+
+
+class BStandardErrorOutput : public BErrorOutput {
+public:
+	virtual	void				PrintErrorVarArgs(const char* format,
+									va_list args);
+};
+
+
+}	// namespace BHPKG
+
+}	// namespace BPackageKit
+
+
+#endif	// _PACKAGE__HPKG__STANDARD_ERROR_OUTPUT_H_
diff --git a/src/bin/package/Jamfile b/src/bin/package/Jamfile
index 0ee72e967a..7f34919c05 100644
--- a/src/bin/package/Jamfile
+++ b/src/bin/package/Jamfile
@@ -11,7 +11,6 @@ BinCommand package :
 	package.cpp
 	PackageWriterListener.cpp
 	PackageWritingUtils.cpp
-	StandardErrorOutput.cpp
 
 	:
 	package be
diff --git a/src/bin/package/StandardErrorOutput.cpp b/src/bin/package/StandardErrorOutput.cpp
deleted file mode 100644
index 133e633914..0000000000
--- a/src/bin/package/StandardErrorOutput.cpp
+++ /dev/null
@@ -1,16 +0,0 @@
-/*
- * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
- * Distributed under the terms of the MIT License.
- */
-
-
-#include "StandardErrorOutput.h"
-
-#include 
-
-
-void
-StandardErrorOutput::PrintErrorVarArgs(const char* format, va_list args)
-{
-	vfprintf(stderr, format, args);
-}
diff --git a/src/bin/package/StandardErrorOutput.h b/src/bin/package/StandardErrorOutput.h
deleted file mode 100644
index c619443180..0000000000
--- a/src/bin/package/StandardErrorOutput.h
+++ /dev/null
@@ -1,21 +0,0 @@
-/*
- * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
- * Distributed under the terms of the MIT License.
- */
-#ifndef STANDARD_ERROR_OUTPUT_H
-#define STANDARD_ERROR_OUTPUT_H
-
-
-#include 
-
-
-using BPackageKit::BHPKG::BErrorOutput;
-
-
-class StandardErrorOutput : public BErrorOutput {
-	virtual	void				PrintErrorVarArgs(const char* format,
-									va_list args);
-};
-
-
-#endif	// STANDARD_ERROR_OUTPUT_H
diff --git a/src/bin/package/command_add.cpp b/src/bin/package/command_add.cpp
index 36336842d3..601624c8b5 100644
--- a/src/bin/package/command_add.cpp
+++ b/src/bin/package/command_add.cpp
@@ -22,7 +22,6 @@
 #include "package.h"
 #include "PackageWriterListener.h"
 #include "PackageWritingUtils.h"
-#include "StandardErrorOutput.h"
 
 
 using namespace BPackageKit::BHPKG;
diff --git a/src/bin/package/command_create.cpp b/src/bin/package/command_create.cpp
index 1062185b5a..ff8ad02c9e 100644
--- a/src/bin/package/command_create.cpp
+++ b/src/bin/package/command_create.cpp
@@ -22,7 +22,6 @@
 #include "package.h"
 #include "PackageWriterListener.h"
 #include "PackageWritingUtils.h"
-#include "StandardErrorOutput.h"
 
 
 using BPackageKit::BHPKG::BPackageWriterListener;
diff --git a/src/bin/package/command_dump.cpp b/src/bin/package/command_dump.cpp
index fdf55d2d31..c25437e63b 100644
--- a/src/bin/package/command_dump.cpp
+++ b/src/bin/package/command_dump.cpp
@@ -17,9 +17,9 @@
 #include 
 #include 
 #include 
+#include 
 
 #include "package.h"
-#include "StandardErrorOutput.h"
 
 
 using namespace BPackageKit::BHPKG;
@@ -182,7 +182,7 @@ command_dump(int argc, const char* const* argv)
 	const char* packageFileName = argv[optind++];
 
 	// open package
-	StandardErrorOutput errorOutput;
+	BStandardErrorOutput errorOutput;
 	BPackageReader packageReader(&errorOutput);
 	status_t error = packageReader.Init(packageFileName);
 	if (error != B_OK)
diff --git a/src/bin/package/command_extract.cpp b/src/bin/package/command_extract.cpp
index a4cc3e903d..25311b6152 100644
--- a/src/bin/package/command_extract.cpp
+++ b/src/bin/package/command_extract.cpp
@@ -30,10 +30,10 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include "package.h"
-#include "StandardErrorOutput.h"
 
 
 using namespace BPackageKit::BHPKG;
@@ -688,7 +688,7 @@ command_extract(int argc, const char* const* argv)
 	const char* packageFileName = argv[optind++];
 
 	// open package
-	StandardErrorOutput errorOutput;
+	BStandardErrorOutput errorOutput;
 	BPackageReader packageReader(&errorOutput);
 	status_t error = packageReader.Init(packageFileName);
 	if (error != B_OK)
diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp
index 317cec68fd..1cadda7c82 100644
--- a/src/bin/package/command_list.cpp
+++ b/src/bin/package/command_list.cpp
@@ -17,11 +17,11 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 
 #include "package.h"
-#include "StandardErrorOutput.h"
 
 
 using namespace BPackageKit::BHPKG;
@@ -320,7 +320,7 @@ command_list(int argc, const char* const* argv)
 	const char* packageFileName = argv[optind++];
 
 	// open package
-	StandardErrorOutput errorOutput;
+	BStandardErrorOutput errorOutput;
 	BPackageReader packageReader(&errorOutput);
 	status_t error = packageReader.Init(packageFileName);
 	if (error != B_OK)
diff --git a/src/bin/package_repo/Jamfile b/src/bin/package_repo/Jamfile
index 4563254d22..fe07930b58 100644
--- a/src/bin/package_repo/Jamfile
+++ b/src/bin/package_repo/Jamfile
@@ -5,13 +5,10 @@ UsePrivateHeaders kernel shared ;
 DEFINES += B_ENABLE_INCOMPLETE_POSIX_AT_SUPPORT ;
 	# TODO: Remove when it is complete!
 
-SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src bin package ] ;
-
 BinCommand package_repo :
 	command_create.cpp
 	command_list.cpp
 	package_repo.cpp
-	StandardErrorOutput.cpp
 	:
 	package be
 	$(TARGET_LIBSUPC++)
diff --git a/src/bin/package_repo/command_create.cpp b/src/bin/package_repo/command_create.cpp
index ab245c7aa3..d4bf2ba694 100644
--- a/src/bin/package_repo/command_create.cpp
+++ b/src/bin/package_repo/command_create.cpp
@@ -19,8 +19,7 @@
 #include 
 #include 
 
-#include "package.h"
-#include "StandardErrorOutput.h"
+#include "package_repo.h"
 
 
 using BPackageKit::BHPKG::BRepositoryWriterListener;
diff --git a/src/bin/package_repo/command_list.cpp b/src/bin/package_repo/command_list.cpp
index 0745b59fe2..ba2fe35af9 100644
--- a/src/bin/package_repo/command_list.cpp
+++ b/src/bin/package_repo/command_list.cpp
@@ -14,11 +14,11 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 
-#include "package.h"
-#include "StandardErrorOutput.h"
+#include "package_repo.h"
 
 
 using namespace BPackageKit::BHPKG;
@@ -287,7 +287,7 @@ command_list(int argc, const char* const* argv)
 	const char* repositoryFileName = argv[optind++];
 
 	// open repository
-	StandardErrorOutput errorOutput;
+	BStandardErrorOutput errorOutput;
 	BRepositoryReader repositoryReader(&errorOutput);
 	status_t error = repositoryReader.Init(repositoryFileName);
 	if (error != B_OK)
diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile
index 207e6a1aa7..185a6b9949 100644
--- a/src/kits/package/Jamfile
+++ b/src/kits/package/Jamfile
@@ -71,6 +71,10 @@ SharedLibrary libpackage.so
 	ValidateChecksumJob.cpp
 
 	$(HPKG_SOURCES)
+
+	# hpkg, but only libpackage
+	StandardErrorOutput.cpp
+
 	:
 	libshared.a be z $(TARGET_LIBSTDC++)
 ;
diff --git a/src/kits/package/hpkg/StandardErrorOutput.cpp b/src/kits/package/hpkg/StandardErrorOutput.cpp
new file mode 100644
index 0000000000..3caed6cde8
--- /dev/null
+++ b/src/kits/package/hpkg/StandardErrorOutput.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2009-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include 
+
+#include 
+
+
+namespace BPackageKit {
+
+namespace BHPKG {
+
+
+void
+BStandardErrorOutput::PrintErrorVarArgs(const char* format, va_list args)
+{
+	vfprintf(stderr, format, args);
+}
+
+
+}	// namespace BHPKG
+
+}	// namespace BPackageKit

From df65c3118a17089b20f3f9bf22b59988ddf7bc1c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 1 Apr 2013 23:17:25 +0000
Subject: [PATCH 0328/1170] Add BNoErrorOutput to package kit

---
 headers/os/package/hpkg/NoErrorOutput.h | 29 +++++++++++++++++++++++++
 src/kits/package/Jamfile                |  1 +
 src/kits/package/hpkg/NoErrorOutput.cpp | 26 ++++++++++++++++++++++
 3 files changed, 56 insertions(+)
 create mode 100644 headers/os/package/hpkg/NoErrorOutput.h
 create mode 100644 src/kits/package/hpkg/NoErrorOutput.cpp

diff --git a/headers/os/package/hpkg/NoErrorOutput.h b/headers/os/package/hpkg/NoErrorOutput.h
new file mode 100644
index 0000000000..5d5537ffea
--- /dev/null
+++ b/headers/os/package/hpkg/NoErrorOutput.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__HPKG__NO_ERROR_OUTPUT_H_
+#define _PACKAGE__HPKG__NO_ERROR_OUTPUT_H_
+
+
+#include 
+
+
+namespace BPackageKit {
+
+namespace BHPKG {
+
+
+class BNoErrorOutput : public BErrorOutput {
+public:
+	virtual	void				PrintErrorVarArgs(const char* format,
+									va_list args);
+};
+
+
+}	// namespace BHPKG
+
+}	// namespace BPackageKit
+
+
+#endif	// _PACKAGE__HPKG__NO_ERROR_OUTPUT_H_
diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile
index 185a6b9949..5059d6f193 100644
--- a/src/kits/package/Jamfile
+++ b/src/kits/package/Jamfile
@@ -73,6 +73,7 @@ SharedLibrary libpackage.so
 	$(HPKG_SOURCES)
 
 	# hpkg, but only libpackage
+	NoErrorOutput.cpp
 	StandardErrorOutput.cpp
 
 	:
diff --git a/src/kits/package/hpkg/NoErrorOutput.cpp b/src/kits/package/hpkg/NoErrorOutput.cpp
new file mode 100644
index 0000000000..151fa554cf
--- /dev/null
+++ b/src/kits/package/hpkg/NoErrorOutput.cpp
@@ -0,0 +1,26 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+
+namespace BPackageKit {
+
+namespace BHPKG {
+
+
+void
+BNoErrorOutput::PrintErrorVarArgs(const char* format, va_list args)
+{
+}
+
+
+}	// namespace BHPKG
+
+}	// namespace BPackageKit

From dfb5fa8ba3da4fe01df1cab7a233b9ce145c06ac Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 1 Apr 2013 23:18:16 +0000
Subject: [PATCH 0329/1170] Add convenience methods
 BPackageInfo::ReadFromPackageFile()

---
 headers/os/package/PackageInfo.h |  7 ++++---
 src/kits/package/PackageInfo.cpp | 31 +++++++++++++++++++++++++++++++
 2 files changed, 35 insertions(+), 3 deletions(-)

diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h
index 9554a209f9..aad8b13ac8 100644
--- a/headers/os/package/PackageInfo.h
+++ b/headers/os/package/PackageInfo.h
@@ -28,9 +28,8 @@ namespace BPackageKit {
 /*
  * Keeps a list of package info elements (e.g. name, version, vendor, ...) which
  * will be converted to package attributes when creating a package. Usually,
- * these elements have been parsed from a ".PackageInfo"-file.
- * Alternatively, the package reader populates a BPackageInfo object by
- * collecting package attributes from an existing package.
+ * these elements have been parsed from a ".PackageInfo" file.
+ * Alternatively, they can be read from an existing package file.
  */
 class BPackageInfo {
 public:
@@ -52,6 +51,8 @@ public:
 			status_t			ReadFromConfigString(
 									const BString& packageInfoString,
 									ParseErrorListener* listener = NULL);
+			status_t			ReadFromPackageFile(const char* path);
+			status_t			ReadFromPackageFile(int fd);
 
 			status_t			InitCheck() const;
 
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index f24bd9201f..42da18ec90 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -14,6 +14,9 @@
 
 #include 
 #include 
+#include 
+#include 
+#include 
 
 
 namespace BPackageKit {
@@ -903,6 +906,34 @@ BPackageInfo::ReadFromConfigString(const BString& packageInfoString,
 }
 
 
+status_t
+BPackageInfo::ReadFromPackageFile(const char* path)
+{
+	BHPKG::BNoErrorOutput errorOutput;
+	BHPKG::BPackageReader packageReader(&errorOutput);
+	status_t error = packageReader.Init(path);
+	if (error != B_OK)
+		return error;
+	
+	BPackageInfoContentHandler handler(*this);
+	return packageReader.ParseContent(&handler);
+}
+
+
+status_t
+BPackageInfo::ReadFromPackageFile(int fd)
+{
+	BHPKG::BNoErrorOutput errorOutput;
+	BHPKG::BPackageReader packageReader(&errorOutput);
+	status_t error = packageReader.Init(fd, false);
+	if (error != B_OK)
+		return error;
+	
+	BPackageInfoContentHandler handler(*this);
+	return packageReader.ParseContent(&handler);
+}
+
+
 status_t
 BPackageInfo::InitCheck() const
 {

From 7c293958240a164ff48f2f0b5f3641ffe7e2eee9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 2 Apr 2013 17:06:56 +0000
Subject: [PATCH 0330/1170] Add some missing build headers

---
 headers/build/os/package/hpkg/NoErrorOutput.h       | 1 +
 headers/build/os/package/hpkg/StandardErrorOutput.h | 1 +
 headers/build/private/shared/OpenHashTable.h        | 1 +
 3 files changed, 3 insertions(+)
 create mode 100644 headers/build/os/package/hpkg/NoErrorOutput.h
 create mode 100644 headers/build/os/package/hpkg/StandardErrorOutput.h
 create mode 100644 headers/build/private/shared/OpenHashTable.h

diff --git a/headers/build/os/package/hpkg/NoErrorOutput.h b/headers/build/os/package/hpkg/NoErrorOutput.h
new file mode 100644
index 0000000000..c9cbfa9587
--- /dev/null
+++ b/headers/build/os/package/hpkg/NoErrorOutput.h
@@ -0,0 +1 @@
+#include <../os/package/hpkg/NoErrorOutput.h>
diff --git a/headers/build/os/package/hpkg/StandardErrorOutput.h b/headers/build/os/package/hpkg/StandardErrorOutput.h
new file mode 100644
index 0000000000..b5a347a953
--- /dev/null
+++ b/headers/build/os/package/hpkg/StandardErrorOutput.h
@@ -0,0 +1 @@
+#include <../os/package/hpkg/StandardErrorOutput.h>
diff --git a/headers/build/private/shared/OpenHashTable.h b/headers/build/private/shared/OpenHashTable.h
new file mode 100644
index 0000000000..8cc05d91ac
--- /dev/null
+++ b/headers/build/private/shared/OpenHashTable.h
@@ -0,0 +1 @@
+#include <../private/shared/OpenHashTable.h>

From bcdf4924048db31db99f55626fd4ce735cc1fff1 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 2 Apr 2013 17:17:46 +0000
Subject: [PATCH 0331/1170] Simplify/fix the ExtractArchive rule and friends

* The call to the dummy actions isn't needed
* The calls to Extract{Zip,Tar,HPKG}Archive1 couldn't work like that.
  The directory has to be the main target, since ExtractArchive is
  potentially invoked multiple times with different extracted file
  targets and the Extract*Archive1 is only invoked the first time.
  Tested only with the HPKG actions, but they others should work as
  well.
---
 build/jam/FileRules | 31 ++++++++++++-------------------
 1 file changed, 12 insertions(+), 19 deletions(-)

diff --git a/build/jam/FileRules b/build/jam/FileRules
index 054c916e56..ccb883d205 100644
--- a/build/jam/FileRules
+++ b/build/jam/FileRules
@@ -236,15 +236,15 @@ rule ExtractArchive directory : entries : archiveFile : grist
 		switch $(archiveFile:S)
 		{
 			case .zip :
-				ExtractZipArchive1 $(targets) : $(directory) $(archiveFile) ;
+				ExtractZipArchive1 $(directory) : $(archiveFile) ;
 
 			case .tgz :
-				ExtractTarArchive1 $(targets) : $(directory) $(archiveFile) ;
+				ExtractTarArchive1 $(directory) : $(archiveFile) ;
 
 			case .hpkg :
-				Depends $(targets) : package ;
-				ExtractHPKGArchive1 $(targets)
-					: package $(directory) $(archiveFile) ;
+				Depends $(directory) : package ;
+				ExtractHPKGArchive1 $(directory)
+					: package $(archiveFile) ;
 
 			case * :
 				Exit "ExtractArchive: Unhandled archive extension:"
@@ -253,39 +253,32 @@ rule ExtractArchive directory : entries : archiveFile : grist
 		INITIALIZED on $(directory) = 1 ;
 	}
 
-	# Use a dummy rule so that it looks to jam like the targets are actually
-	# built from the directory target.
-	ExtractArchiveDummy $(targets) : $(directory) ;
-
 	return $(targets) ;
 }
 
 
 actions ExtractZipArchive1
 {
-	mkdir -p $(2[1])
-	unzip -q -u -o -d $(2[1]) $(2[2])
+	mkdir -p $(1)
+	unzip -q -u -o -d $(1) $(2)
 }
 
+
 actions ExtractTarArchive1
 {
-	mkdir -p $(2[1])
-	tar -C $(2[1]) -xf $(2[2])
+	mkdir -p $(1)
+	tar -C $(1) -xf $(2)
 }
 
 
 actions ExtractHPKGArchive1
 {
-	mkdir -p "$(2[2])"
+	mkdir -p "$(1)"
 	$(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR)
-	$(2[1]) extract -C "$(2[2])" "$(2[3])"
+	$(2[1]) extract -C "$(1)" "$(2[2])"
 }
 
 
-actions ExtractArchiveDummy
-{
-}
-
 rule ObjectReference
 {
 	# ObjectReference  : 

From 04d1edefe25bfa40ba2360e596189281739bd649 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 2 Apr 2013 17:24:22 +0000
Subject: [PATCH 0332/1170] Fix the libpackage_build build

* The recently introduced {No,Standard}ErrorOutput.cpp were still
  missing.
* Add hack to allow building more correctly on Haiku. We were using
  the installed package kit headers, not the ones from the working
  directory.
---
 src/build/libpackage/Jamfile | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)

diff --git a/src/build/libpackage/Jamfile b/src/build/libpackage/Jamfile
index 7b7d56f72f..58ce24b42e 100644
--- a/src/build/libpackage/Jamfile
+++ b/src/build/libpackage/Jamfile
@@ -1,6 +1,15 @@
 SubDir HAIKU_TOP src build libpackage ;
 
-UsePrivateBuildHeaders kernel shared ;
+# TODO: Hack to make things build on Haiku. The right solution is to build
+# libbe_build and friends on Haiku as well and use the exact same build
+# environment as on other systems.
+if $(HOST_PLATFORM) = haiku_host {
+	UseHeaders [ FDirName $(HAIKU_TOP) headers build ] : true ;
+	UseHeaders [ FDirName $(HAIKU_TOP) headers build os ] : true ;
+	UsePrivateBuildHeaders . ;
+}
+
+UsePrivateBuildHeaders kernel package shared ;
 
 SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package ] ;
 SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
@@ -84,6 +93,11 @@ BuildPlatformSharedLibrary libpackage_build.so
 	ValidateChecksumJob.cpp
 
 	$(HPKG_SOURCES)
+
+	# hpkg, but only libpackage
+	NoErrorOutput.cpp
+	StandardErrorOutput.cpp
+
 	:
 	libshared_build.a $(HOST_LIBBE) z $(HOST_LIBSTDC++)
 ;

From fc75f2df0c666dcc61be83c4facdd3132340c2fb Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 2 Apr 2013 17:27:29 +0000
Subject: [PATCH 0333/1170] package: Fix build

* StandardErrorOutput.cpp no longer exists (respectively has been moved
  to libpackage).
* Add hack to allow building more correctly on Haiku. We were using
  the installed package kit headers, not the ones from the working
  directory.
---
 src/tools/package/Jamfile | 9 ++++++++-
 1 file changed, 8 insertions(+), 1 deletion(-)

diff --git a/src/tools/package/Jamfile b/src/tools/package/Jamfile
index 2609ede7ad..8c72d378fa 100644
--- a/src/tools/package/Jamfile
+++ b/src/tools/package/Jamfile
@@ -1,5 +1,13 @@
 SubDir HAIKU_TOP src tools package ;
 
+# TODO: Hack to make things build on Haiku. The right solution is to build
+# libbe_build and friends on Haiku as well and use the exact same build
+# environment as on other systems.
+if $(HOST_PLATFORM) = haiku_host {
+	UseHeaders [ FDirName $(HAIKU_TOP) headers build ] : true ;
+	UseHeaders [ FDirName $(HAIKU_TOP) headers build os ] : true ;
+}
+
 UsePrivateBuildHeaders shared kernel ;
 
 SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src bin package ] ;
@@ -15,7 +23,6 @@ BuildPlatformMain package :
 	package.cpp
 	PackageWriterListener.cpp
 	PackageWritingUtils.cpp
-	StandardErrorOutput.cpp
 
 	:
 	libpackage_build.so $(HOST_LIBBE) $(HOST_LIBSUPC++)

From dd6ec1de82028af2d1a7bd0d8d2c7a6ba5cbbb34 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 2 Apr 2013 17:31:06 +0000
Subject: [PATCH 0334/1170] Add libsolv build feature

---
 build/jam/OptionalBuildFeatures | 34 +++++++++++++++++++++++++++++++++
 1 file changed, 34 insertions(+)

diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures
index 7b8c1903ab..ee549b0d31 100644
--- a/build/jam/OptionalBuildFeatures
+++ b/build/jam/OptionalBuildFeatures
@@ -214,3 +214,37 @@ if $(HAIKU_BUILD_FEATURE_TAGLIB) {
 	}
 }
 
+
+# libsolv
+
+if $(TARGET_ARCH) != x86 {
+	Echo "Libsolv not available for $(TARGET_ARCH)." ;
+} else if $(HAIKU_GCC_VERSION[1]) = 2 {
+	HAIKU_LIBSOLV_PACKAGE
+		= libsolv-0.3.0_haiku_2013_04_01-1-x86_gcc2.hpkg ;
+} else {
+	Echo "Libsolv not available for gcc4." ;
+}
+
+if $(HAIKU_LIBSOLV_PACKAGE) {
+	# download package
+	HAIKU_LIBSOLV_PACKAGE_FILE = [ DownloadFile $(HAIKU_LIBSOLV_PACKAGE)
+			: $(hpkgBaseURL)/$(HAIKU_LIBSOLV_PACKAGE) ] ;
+	HAIKU_LIBSOLV_DIR = [ FDirName $(HAIKU_OPTIONAL_BUILD_PACKAGES_DIR)
+		$(HAIKU_LIBSOLV_PACKAGE:B) ] ;
+
+	# extract headers and libraries
+	HAIKU_LIBSOLV_HEADERS_DEPENDENCY = [ ExtractArchive $(HAIKU_LIBSOLV_DIR)
+		: include/ : $(HAIKU_LIBSOLV_PACKAGE_FILE) : extracted-libsolv
+	] ;
+
+	HAIKU_LIBSOLV_LIBS = [ ExtractArchive $(HAIKU_LIBSOLV_DIR)
+		:
+		lib/libsolv.so
+		lib/libsolvext.so
+		: $(HAIKU_LIBSOLV_PACKAGE_FILE)
+		: extracted-libsolv
+	] ;
+
+	HAIKU_LIBSOLV_HEADERS = [ FDirName $(HAIKU_LIBSOLV_DIR) include ] ;
+}

From a3dd6caf55b8862747542069f3bf116e92723eab Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 02:06:26 +0000
Subject: [PATCH 0335/1170] Add public package version parsing API

* BPackageVersion: Add respective constructor and SetTo().
* BPackageInfo: Add static ParseVersionString() utility method. It's
  only there because the parser lives in the BPackageInfo
  implementation.
---
 headers/os/package/PackageInfo.h    |  6 ++++
 headers/os/package/PackageVersion.h |  4 +++
 src/kits/package/PackageInfo.cpp    | 49 +++++++++++++++++++++++++++++
 src/kits/package/PackageVersion.cpp | 17 ++++++++++
 4 files changed, 76 insertions(+)

diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h
index aad8b13ac8..25383886fe 100644
--- a/headers/os/package/PackageInfo.h
+++ b/headers/os/package/PackageInfo.h
@@ -141,6 +141,12 @@ public:
 	static	status_t			GetArchitectureByName(const BString& name,
 									BPackageArchitecture& _architecture);
 
+	static	status_t			ParseVersionString(const BString& string,
+									bool releaseIsOptional,
+									BPackageVersion& _version,
+									ParseErrorListener* listener = NULL);
+
+public:
 	static	const char*			kElementNames[];
 	static	const char*			kArchitectureNames[];
 
diff --git a/headers/os/package/PackageVersion.h b/headers/os/package/PackageVersion.h
index e571b64757..12a80d198b 100644
--- a/headers/os/package/PackageVersion.h
+++ b/headers/os/package/PackageVersion.h
@@ -23,6 +23,8 @@ public:
 								BPackageVersion();
 								BPackageVersion(
 									const BPackageVersionData& data);
+								BPackageVersion(const BString& versionString,
+									bool releaseIsOptional = true);
 								BPackageVersion(const BString& major,
 									const BString& minor, const BString& micro,
 									const BString& preRelease, uint8 release);
@@ -41,6 +43,8 @@ public:
 			void				SetTo(const BString& major,
 									const BString& minor, const BString& micro,
 									const BString& preRelease, uint8 release);
+			status_t			SetTo(const BString& versionString,
+									bool releaseIsOptional = true);
 			void				Clear();
 
 			int					Compare(const BPackageVersion& other) const;
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 42da18ec90..41f39b4e94 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -68,6 +68,10 @@ public:
 			status_t			Parse(const BString& packageInfoString,
 									BPackageInfo* packageInfo);
 
+			status_t			ParseVersion(const BString& versionString,
+									bool releaseIsOptional,
+									BPackageVersion& _version);
+
 private:
 			struct Token;
 			struct ListElementParser;
@@ -82,6 +86,9 @@ private:
 									BPackageArchitecture* value);
 			void				_ParseVersionValue(BPackageVersion* value,
 									bool releaseIsOptional);
+	static	void				_ParseVersionValue(Token& word,
+									BPackageVersion* value,
+									bool releaseIsOptional);
 			void				_ParseList(ListElementParser& elementParser,
 									bool allowSingleNonListElement);
 			void				_ParseStringList(BStringList* value,
@@ -206,6 +213,31 @@ BPackageInfo::Parser::Parse(const BString& packageInfoString,
 }
 
 
+status_t
+BPackageInfo::Parser::ParseVersion(const BString& versionString,
+	bool releaseIsOptional, BPackageVersion& _version)
+{
+	fPos = versionString.String();
+
+	try {
+		Token token(TOKEN_WORD, fPos, versionString.Length());
+		_ParseVersionValue(token, &_version, releaseIsOptional);
+	} catch (const ParseError& error) {
+		if (fListener != NULL) {
+			int32 offset = error.pos - versionString.String();
+			fListener->OnError(error.message, 1, offset);
+		}
+		return B_BAD_DATA;
+	} catch (const std::bad_alloc& e) {
+		if (fListener != NULL)
+			fListener->OnError("out of memory", 0, 0);
+		return B_NO_MEMORY;
+	}
+
+	return B_OK;
+}
+
+
 BPackageInfo::Parser::Token
 BPackageInfo::Parser::_NextToken()
 {
@@ -360,6 +392,14 @@ BPackageInfo::Parser::_ParseVersionValue(BPackageVersion* value,
 	bool releaseIsOptional)
 {
 	Token word = _NextToken();
+	_ParseVersionValue(word, value, releaseIsOptional);
+}
+
+
+/*static*/ void
+BPackageInfo::Parser::_ParseVersionValue(Token& word, BPackageVersion* value,
+	bool releaseIsOptional)
+{
 	if (word.type != TOKEN_WORD)
 		throw ParseError("expected word (a version)", word.pos);
 
@@ -1365,4 +1405,13 @@ BPackageInfo::GetArchitectureByName(const BString& name,
 	return B_NAME_NOT_FOUND;
 }
 
+
+/*static*/ status_t
+BPackageInfo::ParseVersionString(const BString& string, bool releaseIsOptional,
+	BPackageVersion& _version, ParseErrorListener* listener)
+{
+	return Parser(listener).ParseVersion(string, releaseIsOptional, _version);
+}
+
+
 }	// namespace BPackageKit
diff --git a/src/kits/package/PackageVersion.cpp b/src/kits/package/PackageVersion.cpp
index a4d1dd23dd..6b0de38a41 100644
--- a/src/kits/package/PackageVersion.cpp
+++ b/src/kits/package/PackageVersion.cpp
@@ -8,6 +8,7 @@
 
 #include 
 
+#include 
 #include 
 
 
@@ -30,6 +31,13 @@ BPackageVersion::BPackageVersion(const BPackageVersionData& data)
 }
 
 
+BPackageVersion::BPackageVersion(const BString& versionString,
+	bool releaseIsOptional)
+{
+	SetTo(versionString, releaseIsOptional);
+}
+
+
 BPackageVersion::BPackageVersion(const BString& major, const BString& minor,
 	const BString& micro, const BString& preRelease, uint8 release)
 {
@@ -151,6 +159,15 @@ BPackageVersion::SetTo(const BString& major, const BString& minor,
 }
 
 
+status_t
+BPackageVersion::SetTo(const BString& versionString, bool releaseIsOptional)
+{
+	Clear();
+	return BPackageInfo::ParseVersionString(versionString, releaseIsOptional,
+		*this);
+}
+
+
 void
 BPackageVersion::Clear()
 {

From 2d0563f357e1e6958b853d6bb90deefd1a266c54 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 02:09:23 +0000
Subject: [PATCH 0336/1170] Fix BPackageResolvableExpression::ToString()

The operator was inserted as a number.
---
 src/kits/package/PackageResolvableExpression.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/kits/package/PackageResolvableExpression.cpp b/src/kits/package/PackageResolvableExpression.cpp
index 430dda56cf..4d14e73822 100644
--- a/src/kits/package/PackageResolvableExpression.cpp
+++ b/src/kits/package/PackageResolvableExpression.cpp
@@ -95,7 +95,7 @@ BPackageResolvableExpression::ToString() const
 	BString string = fName;
 
 	if (fVersion.InitCheck() == B_OK)
-		string << fOperator << fVersion.ToString();
+		string << kOperatorNames[fOperator] << fVersion.ToString();
 
 	return string;
 }

From 1a4d020daf80d0b0c30062530cf735ce46dc7dba Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 02:15:57 +0000
Subject: [PATCH 0337/1170] Flesh out the package kit solver API quite a bit
 more

* Reorganize things a bit:
  - BSolver is now an abstract base class.
  - A libsolv based implementation, LibsolvSolver, lives in a new
    add-on, which is loaded lazily.
  - Get rid of libpackage_solver. Save for LibsolvSolver everything
    is moved to libpackage.
  - This is a nicer solution for the cyclic dependency caused by
    libsolv (libsolvext to be precise) using the package kit for
    reading repositories and package files.
* Add a solver result data structure and and an accessor the solver.
* Add problem reporting support to the solver. There aren't data
  structures for the problem solutions yet and support for selecting
  solutions and re-solving is missing as well.
---
 build/jam/HaikuImage                          |   1 +
 headers/os/package/solver/Solver.h            |  32 +-
 headers/os/package/solver/SolverPackage.h     |  42 ++
 .../solver/SolverPackageSpecifierList.h       |   1 +
 headers/os/package/solver/SolverProblem.h     |  69 ++
 headers/os/package/solver/SolverRepository.h  |  12 +-
 headers/os/package/solver/SolverResult.h      |  67 ++
 src/kits/package/Jamfile                      |   9 +
 src/kits/package/solver/Jamfile               |  21 +-
 src/kits/package/solver/LibsolvSolver.cpp     | 619 ++++++++++++++++++
 src/kits/package/solver/LibsolvSolver.h       |  77 +++
 src/kits/package/solver/Solver.cpp            | 340 +---------
 src/kits/package/solver/SolverPackage.cpp     |  78 +++
 .../solver/SolverPackageSpecifierList.cpp     |   7 +
 src/kits/package/solver/SolverProblem.cpp     | 118 ++++
 src/kits/package/solver/SolverRepository.cpp  |  59 +-
 src/kits/package/solver/SolverResult.cpp      | 120 ++++
 17 files changed, 1321 insertions(+), 351 deletions(-)
 create mode 100644 headers/os/package/solver/SolverPackage.h
 create mode 100644 headers/os/package/solver/SolverProblem.h
 create mode 100644 headers/os/package/solver/SolverResult.h
 create mode 100644 src/kits/package/solver/LibsolvSolver.cpp
 create mode 100644 src/kits/package/solver/LibsolvSolver.h
 create mode 100644 src/kits/package/solver/SolverPackage.cpp
 create mode 100644 src/kits/package/solver/SolverProblem.cpp
 create mode 100644 src/kits/package/solver/SolverResult.cpp

diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage
index ba7a81d788..835c1a7553 100644
--- a/build/jam/HaikuImage
+++ b/build/jam/HaikuImage
@@ -101,6 +101,7 @@ PRIVATE_SYSTEM_LIBS =
 	libfluidsynth.so
 	libilmimf.so
 	liblpsolve55.so
+	libpackage-add-on-libsolv.so
 	libroot-addon-icu.so
 ;
 SYSTEM_SERVERS = app_server cddb_daemon debug_server input_server mail_daemon
diff --git a/headers/os/package/solver/Solver.h b/headers/os/package/solver/Solver.h
index d52d73905c..97cee58a15 100644
--- a/headers/os/package/solver/Solver.h
+++ b/headers/os/package/solver/Solver.h
@@ -13,30 +13,42 @@ namespace BPackageKit {
 
 
 class BSolverPackageSpecifierList;
+class BSolverProblem;
 class BSolverRepository;
+class BSolverResult;
 
 
 class BSolver {
 public:
-								BSolver();
-								~BSolver();
+	virtual						~BSolver();
 
-			status_t			Init();
+	static	status_t			Create(BSolver*& _solver);
 
-			status_t			AddRepository(BSolverRepository* repository);
+	virtual	status_t			Init() = 0;
 
-			status_t			Install(
+	virtual	status_t			AddRepository(
+									BSolverRepository* repository) = 0;
+
+	virtual	status_t			Install(
 									const BSolverPackageSpecifierList&
-										packages);
+										packages) = 0;
 
-private:
-			class Implementation;
+			bool				HasProblems() const
+									{ return CountProblems() > 0; }
+	virtual	int32				CountProblems() const = 0;
+	virtual	BSolverProblem*		ProblemAt(int32 index) const = 0;
 
-private:
-			Implementation*		fImplementation;
+	virtual	status_t			GetResult(BSolverResult& _result) = 0;
+
+protected:
+								BSolver();
 };
 
 
+// function exported by the libsolv based add-on
+extern "C" BSolver* create_solver();
+
+
 }	// namespace BPackageKit
 
 
diff --git a/headers/os/package/solver/SolverPackage.h b/headers/os/package/solver/SolverPackage.h
new file mode 100644
index 0000000000..94e52a90ce
--- /dev/null
+++ b/headers/os/package/solver/SolverPackage.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__SOLVER_PACKAGE_H_
+#define _PACKAGE__SOLVER_PACKAGE_H_
+
+
+#include 
+
+
+namespace BPackageKit {
+
+
+class BSolverRepository;
+
+
+class BSolverPackage {
+public:
+								BSolverPackage(BSolverRepository* repository,
+									const BPackageInfo& packageInfo);
+								BSolverPackage(const BSolverPackage& other);
+								~BSolverPackage();
+
+			BSolverRepository*	Repository() const;
+			const BPackageInfo&	Info() const;
+
+			BString				Name() const;
+			BString				VersionedName() const;
+
+			BSolverPackage&		operator=(const BSolverPackage& other);
+
+private:
+			BSolverRepository*	fRepository;
+			BPackageInfo		fInfo;
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif // _PACKAGE__SOLVER_PACKAGE_H_
diff --git a/headers/os/package/solver/SolverPackageSpecifierList.h b/headers/os/package/solver/SolverPackageSpecifierList.h
index 0557dec065..7a2bf581e1 100644
--- a/headers/os/package/solver/SolverPackageSpecifierList.h
+++ b/headers/os/package/solver/SolverPackageSpecifierList.h
@@ -28,6 +28,7 @@ public:
 
 			bool				AppendSpecifier(
 									const BSolverPackageSpecifier& specifier);
+			void				MakeEmpty();
 
 			BSolverPackageSpecifierList& operator=(
 									const BSolverPackageSpecifierList& other);
diff --git a/headers/os/package/solver/SolverProblem.h b/headers/os/package/solver/SolverProblem.h
new file mode 100644
index 0000000000..f660837fbf
--- /dev/null
+++ b/headers/os/package/solver/SolverProblem.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__SOLVER_PROBLEM_H_
+#define _PACKAGE__SOLVER_PROBLEM_H_
+
+
+#include 
+
+
+namespace BPackageKit {
+
+
+class BSolverPackage;
+
+
+class BSolverProblem {
+public:
+			enum BType {
+				B_UNSPECIFIED,
+				B_NOT_IN_DISTUPGRADE_REPOSITORY,
+				B_INFERIOR_ARCHITECTURE,
+				B_INSTALLED_PACKAGE_PROBLEM,
+				B_CONFLICTING_REQUESTS,
+				B_REQUESTED_RESOLVABLE_NOT_PROVIDED,
+				B_REQUESTED_RESOLVABLE_PROVIDED_BY_SYSTEM,
+				B_DEPENDENCY_PROBLEM,
+				B_PACKAGE_NOT_INSTALLABLE,
+				B_DEPENDENCY_NOT_PROVIDED,
+				B_PACKAGE_NAME_CLASH,
+				B_PACKAGE_CONFLICT,
+				B_PACKAGE_OBSOLETES_RESOLVABLE,
+				B_INSTALLED_PACKAGE_OBSOLETES_RESOLVABLE,
+				B_PACKAGE_IMPLICITLY_OBSOLETES_RESOLVABLE,
+				B_DEPENDENCY_NOT_INSTALLABLE,
+				B_SELF_CONFLICT
+			};
+
+public:
+								BSolverProblem(BType type,
+									BSolverPackage* sourcePackage,
+									BSolverPackage* targetPackage = NULL);
+								BSolverProblem(BType type,
+									BSolverPackage* sourcePackage,
+									BSolverPackage* targetPackage,
+									const BPackageResolvableExpression&
+										dependency);
+								~BSolverProblem();
+
+			BType				Type() const;
+			BSolverPackage*		SourcePackage() const;
+			BSolverPackage*		TargetPackage() const;
+			const BPackageResolvableExpression& Dependency() const;
+
+			BString				ToString() const;
+
+private:
+			BType				fType;
+			BSolverPackage*		fSourcePackage;
+			BSolverPackage*		fTargetPackage;
+			BPackageResolvableExpression fDependency;
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif // _PACKAGE__SOLVER_PROBLEM_H_
diff --git a/headers/os/package/solver/SolverRepository.h b/headers/os/package/solver/SolverRepository.h
index 579512dda0..187a3db95a 100644
--- a/headers/os/package/solver/SolverRepository.h
+++ b/headers/os/package/solver/SolverRepository.h
@@ -6,6 +6,7 @@
 #define _PACKAGE__SOLVER_REPOSITORY_H_
 
 
+#include 
 #include 
 #include 
 #include 
@@ -16,6 +17,7 @@ namespace BPackageKit {
 
 class BPackageInfo;
 class BRepositoryConfig;
+class BSolverPackage;
 
 
 class BSolverRepository {
@@ -45,21 +47,27 @@ public:
 			status_t			InitCheck();
 
 			bool				IsInstalled() const;
+			void				SetInstalled(bool isInstalled);
 
 			BString				Name() const;
 			uint8				Priority() const;
 
+			bool				IsEmpty() const;
+			int32				CountPackages() const;
+			BSolverPackage*		PackageAt(int32 index) const;
+
 			status_t			AddPackage(const BPackageInfo& info);
 			status_t			AddPackages(
 									BPackageInstallationLocation location);
 
-			Iterator			GetIterator() const;
+private:
+			typedef BObjectList PackageList;
 
 private:
 			BString				fName;
 			uint8				fPriority;
 			bool				fIsInstalled;
-			BPackageInfoSet		fPackages;
+			PackageList			fPackages;
 };
 
 
diff --git a/headers/os/package/solver/SolverResult.h b/headers/os/package/solver/SolverResult.h
new file mode 100644
index 0000000000..c14b691649
--- /dev/null
+++ b/headers/os/package/solver/SolverResult.h
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__SOLVER_RESULT_H_
+#define _PACKAGE__SOLVER_RESULT_H_
+
+
+#include 
+
+
+namespace BPackageKit {
+
+
+class BSolverPackage;
+
+
+class BSolverResultElement {
+public:
+			enum BType {
+				B_TYPE_INSTALL,
+				B_TYPE_UNINSTALL
+			};
+
+public:
+								BSolverResultElement(BType type,
+									BSolverPackage* package);
+								BSolverResultElement(
+									const BSolverResultElement& other);
+								~BSolverResultElement();
+
+			BType				Type() const;
+			BSolverPackage*		Package() const;
+
+			BSolverResultElement& operator=(const BSolverResultElement& other);
+
+private:
+			BType				fType;
+			BSolverPackage*		fPackage;
+};
+
+
+class BSolverResult {
+public:
+								BSolverResult();
+								~BSolverResult();
+
+			bool				IsEmpty() const;
+			int32				CountElements() const;
+			const BSolverResultElement* ElementAt(int32 index) const;
+
+			void				MakeEmpty();
+			bool				AppendElement(
+									const BSolverResultElement& element);
+
+private:
+			typedef BObjectList ElementList;
+
+private:
+			ElementList			fElements;
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif // _PACKAGE__SOLVER_RESULT_H_
diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile
index 5059d6f193..6eb0ac4468 100644
--- a/src/kits/package/Jamfile
+++ b/src/kits/package/Jamfile
@@ -7,6 +7,7 @@ UsePrivateHeaders
 	shared ;
 
 SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package hpkg ] ;
+SEARCH_SOURCE += [ FDirName $(HAIKU_TOP) src kits package solver ] ;
 
 HPKG_SOURCES =
 	AttributeDataReader.cpp
@@ -76,6 +77,14 @@ SharedLibrary libpackage.so
 	NoErrorOutput.cpp
 	StandardErrorOutput.cpp
 
+	# solver
+	Solver.cpp
+	SolverPackage.cpp
+	SolverPackageSpecifier.cpp
+	SolverPackageSpecifierList.cpp
+	SolverProblem.cpp
+	SolverRepository.cpp
+	SolverResult.cpp
 	:
 	libshared.a be z $(TARGET_LIBSTDC++)
 ;
diff --git a/src/kits/package/solver/Jamfile b/src/kits/package/solver/Jamfile
index 06ea5a5db2..5109fad226 100644
--- a/src/kits/package/solver/Jamfile
+++ b/src/kits/package/solver/Jamfile
@@ -1,23 +1,20 @@
 SubDir HAIKU_TOP src kits package solver ;
 
-UsePrivateHeaders shared ;
-
-# TODO: Add properly to BuildFeatures and remove here!
-HAIKU_LIBSOLV_INSTALL_DIR ?= /Transfer/ports/libsolv-install/boot/common ;
-HAIKU_LIBSOLV_HEADERS ?= $(HAIKU_LIBSOLV_INSTALL_DIR)/include ;
-HAIKU_LIBSOLV_LIBS ?= $(HAIKU_LIBSOLV_INSTALL_DIR)/lib/libsolv.so
-	$(HAIKU_LIBSOLV_INSTALL_DIR)/lib/libsolvext.so ;
+# add-on implementing a libsolv based BSolver
 
 SubDirSysHdrs $(HAIKU_LIBSOLV_HEADERS) ;
 SubDirHdrs $(HAIKU_LIBSOLV_HEADERS)/solv ;
 
+UsePrivateHeaders shared ;
 
-SharedLibrary libpackage_solver.so
+
+SharedLibrary libpackage-add-on-libsolv.so
 	:
-	Solver.cpp
-	SolverPackageSpecifier.cpp
-	SolverPackageSpecifierList.cpp
-	SolverRepository.cpp
+	LibsolvSolver.cpp
 	:
 	package $(HAIKU_LIBSOLV_LIBS) be $(TARGET_LIBSTDC++)
 ;
+
+
+Includes [ FGristFiles LibsolvSolver.cpp ]
+	: $(HAIKU_LIBSOLV_HEADERS_DEPENDENCY) ;
diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
new file mode 100644
index 0000000000..19aa15b3b4
--- /dev/null
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -0,0 +1,619 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include "LibsolvSolver.h"
+
+#include 
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+
+// TODO: libsolv doesn't have any helpful out-of-memory handling. It just just
+// abort()s. Obviously that isn't good behavior for a library.
+
+
+BSolver*
+BPackageKit::create_solver()
+{
+	return new(std::nothrow) LibsolvSolver;
+}
+
+
+struct LibsolvSolver::SolvQueue : Queue {
+	SolvQueue()
+	{
+		queue_init(this);
+	}
+
+	~SolvQueue()
+	{
+		queue_free(this);
+	}
+};
+
+
+struct LibsolvSolver::RepositoryInfo {
+	RepositoryInfo(BSolverRepository* repository)
+		:
+		fRepository(repository),
+		fSolvRepo(NULL)
+	{
+	}
+
+	BSolverRepository* Repository() const
+	{
+		return fRepository;
+	}
+
+	Repo* SolvRepo()
+	{
+		return fSolvRepo;
+	}
+
+	void SetSolvRepo(Repo* repo)
+	{
+		fSolvRepo = repo;
+	}
+
+private:
+	BSolverRepository*	fRepository;
+	Repo*				fSolvRepo;
+};
+
+
+// #pragma mark - LibsolvSolver
+
+
+LibsolvSolver::LibsolvSolver()
+	:
+	fPool(NULL),
+	fSolver(NULL),
+	fRepositoryInfos(10, true),
+	fInstalledRepository(NULL),
+	fProblems(10, true)
+{
+}
+
+
+LibsolvSolver::~LibsolvSolver()
+{
+	_Cleanup();
+}
+
+
+status_t
+LibsolvSolver::Init()
+{
+	_Cleanup();
+
+	fPool = pool_create();
+
+	// Set the system architecture. We use what uname() returns unless we're on
+	// x86 gcc2.
+	{
+		const char* arch;
+		#ifdef __HAIKU_ARCH_X86
+			#if (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2
+				arch = "x86_gcc2";
+			#else
+				arch = "x86";
+			#endif
+		#else
+			struct utsname info;
+			if (uname(&info) != 0)
+				return errno;
+			arch = info.machine;
+		#endif
+
+		pool_setarchpolicy(fPool, arch);
+	}
+
+	return B_OK;
+}
+
+
+status_t
+LibsolvSolver::AddRepository(BSolverRepository* repository)
+{
+	if (repository == NULL || repository->InitCheck() != B_OK)
+		return B_BAD_VALUE;
+
+	// If the repository represents installed packages, check, if we already
+	// have such a repository.
+	if (repository->IsInstalled() && fInstalledRepository != NULL)
+		return B_BAD_VALUE;
+
+	// add the repository info
+	RepositoryInfo* info = new(std::nothrow) RepositoryInfo(repository);
+	if (info == NULL)
+		return B_NO_MEMORY;
+
+	if (!fRepositoryInfos.AddItem(info)) {
+		delete info;
+		return B_NO_MEMORY;
+	}
+
+	if (repository->IsInstalled())
+		fInstalledRepository = info;
+
+	return B_OK;
+}
+
+
+status_t
+LibsolvSolver::Install(const BSolverPackageSpecifierList& packages)
+{
+	if (packages.IsEmpty())
+		return B_BAD_VALUE;
+
+// TODO: Clean up first?
+
+	// add repositories to pool
+	status_t error = _AddRepositories();
+	if (error != B_OK)
+		return error;
+
+	// prepare pool for solving
+	pool_createwhatprovides(fPool);
+
+	// add the packages to install to the job queue
+	SolvQueue jobs;
+
+	int32 packageCount = packages.CountSpecifiers();
+	for (int32 i = 0; i < packageCount; i++) {
+		const BSolverPackageSpecifier& specifier = *packages.SpecifierAt(i);
+
+		// find matching packages
+		SolvQueue matchingPackages;
+
+		int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB
+			| SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL;
+// TODO: All flags needed/useful?
+		/*int matchFlags =*/ selection_make(fPool, &matchingPackages,
+			specifier.Expression().Name(), flags);
+// TODO: Don't just match the name, but also the version, if given!
+		if (matchingPackages.count == 0)
+			return B_NAME_NOT_FOUND;
+
+		// restrict to the matching repository
+		if (BSolverRepository* repository = specifier.Repository()) {
+			RepositoryInfo* repositoryInfo = _GetRepositoryInfo(repository);
+			if (repositoryInfo == NULL)
+				return B_BAD_VALUE;
+
+			SolvQueue repoFilter;
+			queue_push2(&repoFilter,
+				SOLVER_SOLVABLE_REPO/* | SOLVER_SETREPO | SOLVER_SETVENDOR*/,
+				repositoryInfo->SolvRepo()->repoid);
+
+			selection_filter(fPool, &matchingPackages, &repoFilter);
+
+			if (matchingPackages.count == 0)
+				return B_NAME_NOT_FOUND;
+		}
+
+		for (int j = 0; j < matchingPackages.count; j++)
+			queue_push(&jobs, matchingPackages.elements[j]);
+	}
+
+	// add solver mode to job queue elements
+	int solverMode = SOLVER_INSTALL;
+	for (int i = 0; i < jobs.count; i += 2) {
+		jobs.elements[i] |= solverMode;
+//		if (cleandeps)
+//			jobs.elements[i] |= SOLVER_CLEANDEPS;
+//		if (forcebest)
+//			jobs.elements[i] |= SOLVER_FORCEBEST;
+	}
+
+	// create the solver and solve
+	fSolver = solver_create(fPool);
+	solver_set_flag(fSolver, SOLVER_FLAG_SPLITPROVIDES, 1);
+	solver_set_flag(fSolver, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
+
+	// get the problems (if any)
+	fProblems.MakeEmpty();
+
+	int problemCount = solver_solve(fSolver, &jobs);
+	for (Id problemId = 1; problemId <= problemCount; problemId++) {
+		error = _AddProblem(problemId);
+		if (error != B_OK)
+			return error;
+	}
+
+	return B_OK;
+}
+
+
+int32
+LibsolvSolver::CountProblems() const
+{
+	return fProblems.CountItems();
+}
+
+
+BSolverProblem*
+LibsolvSolver::ProblemAt(int32 index) const
+{
+	return fProblems.ItemAt(index);
+}
+
+
+status_t
+LibsolvSolver::GetResult(BSolverResult& _result)
+{
+	if (HasProblems())
+		return B_BAD_VALUE;
+
+	_result.MakeEmpty();
+
+	Transaction* transaction = solver_create_transaction(fSolver);
+	CObjectDeleter transactionDeleter(transaction,
+		&transaction_free);
+
+	if (transaction->steps.count == 0)
+		return B_OK;
+
+	// Get the packages that end up in the installation. The result queue
+	// contains newPackageCount new packages to install first, followed by the
+	// kept packages.
+	SolvQueue installedPackages;
+	int newPackageCount = transaction_installedresult(transaction,
+		&installedPackages);
+
+	transaction_order(transaction, 0);
+
+	for (int i = 0; i < transaction->steps.count; i++) {
+		Id solvableId = transaction->steps.elements[i];
+		Solvable* solvable = pool_id2solvable(fPool, solvableId);
+		switch (transaction_type(transaction, solvableId,
+				SOLVER_TRANSACTION_RPM_ONLY)) {
+			case SOLVER_TRANSACTION_ERASE:
+			{
+				BSolverPackage* package = _GetPackage(solvable);
+				if (package == NULL)
+					return B_ERROR;
+
+				status_t error = _result.AppendElement(
+					BSolverResultElement(BSolverResultElement::B_TYPE_UNINSTALL,
+						package));
+				if (error != B_OK)
+					return error;
+				break;
+			}
+
+			case SOLVER_TRANSACTION_INSTALL:
+			case SOLVER_TRANSACTION_MULTIINSTALL:
+			{
+				// check, if it really is a new package
+// TODO: Is this check really necessary?
+				bool foundPackage = false;
+				for (int j = 0; j < newPackageCount; j++) {
+					if (installedPackages.elements[j] == solvableId) {
+						foundPackage = true;
+						break;
+					}
+				}
+
+				if (!foundPackage)
+					continue;
+
+				BSolverPackage* package = _GetPackage(solvable);
+				if (package == NULL)
+					return B_ERROR;
+
+				if (!_result.AppendElement(
+						BSolverResultElement(
+							BSolverResultElement::B_TYPE_INSTALL, package))) {
+					return B_NO_MEMORY;
+				}
+				break;
+			}
+
+			default:
+				break;
+		}
+	}
+
+	return B_OK;
+}
+
+
+void
+LibsolvSolver::_Cleanup()
+{
+	fProblems.MakeEmpty();
+	fSolvablePackages.clear();
+	fInstalledRepository = NULL;
+	fRepositoryInfos.MakeEmpty();
+
+	if (fSolver != NULL) {
+		solver_free(fSolver);
+		fSolver = NULL;
+	}
+
+	if (fPool != NULL) {
+		pool_free(fPool);
+		fPool = NULL;
+	}
+}
+
+
+status_t
+LibsolvSolver::_AddRepositories()
+{
+	int32 repositoryCount = fRepositoryInfos.CountItems();
+	for (int32 i = 0; i < repositoryCount; i++) {
+		RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
+		BSolverRepository* repository = repositoryInfo->Repository();
+		Repo* repo = repo_create(fPool, repository->Name());
+		repositoryInfo->SetSolvRepo(repo);
+
+		repo->priority = 256 - repository->Priority();
+		repo->appdata = (void*)repositoryInfo;
+
+		int32 packageCount = repository->CountPackages();
+		for (int32 k = 0; k < packageCount; k++) {
+			BSolverPackage* package = repository->PackageAt(k);
+			Id solvableId = repo_add_haiku_package_info(repo, package->Info(),
+				REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE);
+			Solvable* solvable = pool_id2solvable(fPool, solvableId);
+
+			try {
+				fSolvablePackages[solvable] = package;
+			} catch (std::bad_alloc&) {
+				return B_NO_MEMORY;
+			}
+		}
+
+		repo_internalize(repo);
+
+		if (repository->IsInstalled())
+			pool_set_installed(fPool, repo);
+	}
+
+	return B_OK;
+}
+
+
+LibsolvSolver::RepositoryInfo*
+LibsolvSolver::_GetRepositoryInfo(BSolverRepository* repository) const
+{
+	int32 repositoryCount = fRepositoryInfos.CountItems();
+	for (int32 i = 0; i < repositoryCount; i++) {
+		RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
+		if (repository == repositoryInfo->Repository())
+			return repositoryInfo;
+	}
+
+	return NULL;
+}
+
+
+BSolverPackage*
+LibsolvSolver::_GetPackage(Solvable* solvable) const
+{
+	SolvableMap::const_iterator it = fSolvablePackages.find(solvable);
+	return it != fSolvablePackages.end() ? it->second : NULL;
+}
+
+
+BSolverPackage*
+LibsolvSolver::_GetPackage(Id solvableId) const
+{
+	Solvable* solvable = pool_id2solvable(fPool, solvableId);
+	return solvable != NULL ? _GetPackage(solvable) : NULL;
+}
+
+
+status_t
+LibsolvSolver::_AddProblem(Id problemId)
+{
+	enum {
+		NEED_SOURCE		= 0x1,
+		NEED_TARGET		= 0x2,
+		NEED_DEPENDENCY	= 0x4
+	};
+
+	Id ruleId = solver_findproblemrule(fSolver, problemId);
+	Id sourceId;
+	Id targetId;
+	Id dependencyId;
+	BSolverProblem::BType problemType = BSolverProblem::B_UNSPECIFIED;
+	uint32 needed = 0;
+
+	switch (solver_ruleinfo(fSolver, ruleId, &sourceId, &targetId,
+			&dependencyId)) {
+		case SOLVER_RULE_DISTUPGRADE:
+			problemType = BSolverProblem::B_NOT_IN_DISTUPGRADE_REPOSITORY;
+			needed = NEED_SOURCE;
+			break;
+		case SOLVER_RULE_INFARCH:
+			problemType = BSolverProblem::B_INFERIOR_ARCHITECTURE;
+			needed = NEED_SOURCE;
+			break;
+		case SOLVER_RULE_UPDATE:
+			problemType = BSolverProblem::B_INSTALLED_PACKAGE_PROBLEM;
+			needed = NEED_SOURCE;
+			break;
+		case SOLVER_RULE_JOB:
+			problemType = BSolverProblem::B_CONFLICTING_REQUESTS;
+			break;
+		case SOLVER_RULE_JOB_NOTHING_PROVIDES_DEP:
+			problemType = BSolverProblem::B_REQUESTED_RESOLVABLE_NOT_PROVIDED;
+			needed = NEED_DEPENDENCY;
+			break;
+		case SOLVER_RULE_JOB_PROVIDED_BY_SYSTEM:
+			problemType
+				= BSolverProblem::B_REQUESTED_RESOLVABLE_PROVIDED_BY_SYSTEM;
+			needed = NEED_DEPENDENCY;
+			break;
+		case SOLVER_RULE_RPM:
+			problemType = BSolverProblem::B_DEPENDENCY_PROBLEM;
+			break;
+		case SOLVER_RULE_RPM_NOT_INSTALLABLE:
+			problemType = BSolverProblem::B_PACKAGE_NOT_INSTALLABLE;
+			needed = NEED_SOURCE;
+			break;
+		case SOLVER_RULE_RPM_NOTHING_PROVIDES_DEP:
+			problemType = BSolverProblem::B_DEPENDENCY_NOT_PROVIDED;
+			needed = NEED_SOURCE | NEED_DEPENDENCY;
+			break;
+		case SOLVER_RULE_RPM_SAME_NAME:
+			problemType = BSolverProblem::B_PACKAGE_NAME_CLASH;
+			needed = NEED_SOURCE | NEED_TARGET;
+			break;
+		case SOLVER_RULE_RPM_PACKAGE_CONFLICT:
+			problemType = BSolverProblem::B_PACKAGE_CONFLICT;
+			needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY;
+			break;
+		case SOLVER_RULE_RPM_PACKAGE_OBSOLETES:
+			problemType = BSolverProblem::B_PACKAGE_OBSOLETES_RESOLVABLE;
+			needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY;
+			break;
+		case SOLVER_RULE_RPM_INSTALLEDPKG_OBSOLETES:
+			problemType
+				= BSolverProblem::B_INSTALLED_PACKAGE_OBSOLETES_RESOLVABLE;
+			needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY;
+			break;
+		case SOLVER_RULE_RPM_IMPLICIT_OBSOLETES:
+			problemType
+				= BSolverProblem::B_PACKAGE_IMPLICITLY_OBSOLETES_RESOLVABLE;
+			needed = NEED_SOURCE | NEED_TARGET | NEED_DEPENDENCY;
+			break;
+		case SOLVER_RULE_RPM_PACKAGE_REQUIRES:
+			problemType = BSolverProblem::B_DEPENDENCY_NOT_INSTALLABLE;
+			needed = NEED_SOURCE | NEED_DEPENDENCY;
+			break;
+		case SOLVER_RULE_RPM_SELF_CONFLICT:
+			problemType = BSolverProblem::B_SELF_CONFLICT;
+			needed = NEED_SOURCE | NEED_DEPENDENCY;
+			break;
+		case SOLVER_RULE_UNKNOWN:
+		case SOLVER_RULE_FEATURE:
+		case SOLVER_RULE_LEARNT:
+		case SOLVER_RULE_CHOICE:
+		case SOLVER_RULE_BEST:
+			problemType = BSolverProblem::B_UNSPECIFIED;
+			break;
+	}
+
+	BSolverPackage* sourcePackage = NULL;
+	if ((needed & NEED_SOURCE) != 0) {
+		sourcePackage = _GetPackage(sourceId);
+		if (sourcePackage == NULL)
+			return B_ERROR;
+	}
+
+	BSolverPackage* targetPackage = NULL;
+	if ((needed & NEED_TARGET) != 0) {
+		targetPackage = _GetPackage(targetId);
+		if (targetPackage == NULL)
+			return B_ERROR;
+	}
+
+	BPackageResolvableExpression dependency;
+	if ((needed & NEED_DEPENDENCY) != 0) {
+		status_t error = _GetResolvableExpression(dependencyId, dependency);
+		if (error != B_OK)
+			return error;
+	}
+
+	BSolverProblem* problem = new(std::nothrow) BSolverProblem(problemType,
+		sourcePackage, targetPackage, dependency);
+	if (problem == NULL || !fProblems.AddItem(problem)) {
+		delete problem;
+		return B_NO_MEMORY;
+	}
+
+	return B_OK;
+}
+
+
+status_t
+LibsolvSolver::_GetResolvableExpression(Id id,
+	BPackageResolvableExpression& _expression) const
+{
+	// Try to translate the libsolv ID to a resolvable expression. Generally
+	// that doesn't work, since libsolv is more expressive, but all the stuff
+	// we feed libsolv we should be able to translate back.
+
+	if (!ISRELDEP(id)) {
+		// just a string
+		_expression.SetTo(pool_id2str(fPool, id));
+		return B_OK;
+	}
+
+	// a composite -- analyze it
+	Reldep* reldep = GETRELDEP(fPool, id);
+
+	// No support for more than one level, so both name and evr must be strings.
+	if (ISRELDEP(reldep->name) || ISRELDEP(reldep->evr))
+		return B_NOT_SUPPORTED;
+
+	const char* name = pool_id2str(fPool, reldep->name);
+	const char* versionString = pool_id2str(fPool, reldep->evr);
+	if (name == NULL || versionString == NULL)
+		return B_NOT_SUPPORTED;
+
+	// get the operator -- we don't support all libsolv supports
+	BPackageResolvableOperator op;
+	switch (reldep->flags) {
+		case 1:
+			op = B_PACKAGE_RESOLVABLE_OP_GREATER;
+			break;
+		case 2:
+			op = B_PACKAGE_RESOLVABLE_OP_EQUAL;
+			break;
+		case 3:
+			op = B_PACKAGE_RESOLVABLE_OP_GREATER_EQUAL;
+			break;
+		case 4:
+			op = B_PACKAGE_RESOLVABLE_OP_LESS;
+			break;
+		case 5:
+			op = B_PACKAGE_RESOLVABLE_OP_NOT_EQUAL;
+			break;
+		case 6:
+			op = B_PACKAGE_RESOLVABLE_OP_LESS_EQUAL;
+			break;
+		default:
+			return B_NOT_SUPPORTED;
+	}
+
+	// get the version (cut off the empty epoch)
+	if (versionString[0] == ':')
+		versionString++;
+
+	BPackageVersion version;
+	status_t error = version.SetTo(versionString, true);
+	if (error != B_OK)
+		return error == B_BAD_DATA ? B_NOT_SUPPORTED : error;
+
+	_expression.SetTo(name, op, version);
+	return B_OK;
+}
diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h
new file mode 100644
index 0000000000..1f4c30198e
--- /dev/null
+++ b/src/kits/package/solver/LibsolvSolver.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef HAIKU_LIBSOLV_SOLVER_H
+#define HAIKU_LIBSOLV_SOLVER_H
+
+
+#include 
+
+#include 
+#include 
+
+#include 
+#include 
+
+
+using namespace BPackageKit;
+
+
+namespace BPackageKit {
+	class BPackageResolvableExpression;
+	class BSolverPackage;
+}
+
+
+class LibsolvSolver : public BSolver {
+public:
+								LibsolvSolver();
+	virtual						~LibsolvSolver();
+
+	virtual	status_t			Init();
+
+	virtual	status_t			AddRepository(BSolverRepository* repository);
+
+	virtual	status_t			Install(
+									const BSolverPackageSpecifierList&
+										packages);
+
+	virtual	int32				CountProblems() const;
+	virtual	BSolverProblem*		ProblemAt(int32 index) const;
+
+	virtual	status_t			GetResult(BSolverResult& _result);
+
+private:
+			struct SolvQueue;
+			struct RepositoryInfo;
+
+			typedef BObjectList RepositoryInfoList;
+			typedef BObjectList ProblemList;
+			typedef std::map SolvableMap;
+
+private:
+			void				_Cleanup();
+
+			status_t			_AddRepositories();
+			RepositoryInfo*		_GetRepositoryInfo(
+									BSolverRepository* repository) const;
+			BSolverPackage*		_GetPackage(Solvable* solvable) const;
+			BSolverPackage*		_GetPackage(Id solvableId) const;
+
+			status_t			_AddProblem(Id problemId);
+			status_t			_GetResolvableExpression(Id id,
+									BPackageResolvableExpression& _expression)
+									const;
+
+private:
+			Pool*				fPool;
+			Solver*				fSolver;
+			RepositoryInfoList	fRepositoryInfos;
+			RepositoryInfo*		fInstalledRepository;
+			SolvableMap			fSolvablePackages;
+			ProblemList			fProblems;
+};
+
+
+#endif // HAIKU_LIBSOLV_SOLVER_H
diff --git a/src/kits/package/solver/Solver.cpp b/src/kits/package/solver/Solver.cpp
index 10ff02d2d4..52f2ba691c 100644
--- a/src/kits/package/solver/Solver.cpp
+++ b/src/kits/package/solver/Solver.cpp
@@ -9,348 +9,62 @@
 
 #include 
 
-#include 
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include 
-#include 
-#include 
-#include 
-
-#include 
-
-
-// TODO: libsolv doesn't have any helpful out-of-memory handling. It just just
-// abort()s. Obviously that isn't good behavior for a library.
+#include 
+#include 
 
 
 namespace BPackageKit {
 
 
-// #pragma mark - BSolver::Implementation
+typedef BSolver* CreateSolverFunction();
+static CreateSolverFunction* sCreateSolver = NULL;
+
+static pthread_once_t sLoadLibsolvSolverAddOnInitOnce = PTHREAD_ONCE_INIT;
 
 
-class BSolver::Implementation {
-public:
-								Implementation();
-								~Implementation();
+static void
+load_libsolv_solver_add_on()
+{
+	void* imageHandle = dlopen("libpackage-add-on-libsolv.so", 0);
+	if (imageHandle == NULL)
+		return;
 
-			status_t			Init();
-
-			status_t			AddRepository(BSolverRepository* repository);
-
-			status_t			Install(
-									const BSolverPackageSpecifierList&
-										packages);
-
-private:
-			struct SolvQueue;
-			struct RepositoryInfo;
-
-			typedef BObjectList RepositoryInfoList;
-
-private:
-			status_t			_AddRepositories();
-			RepositoryInfo*		_GetRepositoryInfo(
-									BSolverRepository* repository) const;
-
-private:
-			Pool*				fPool;
-			RepositoryInfoList	fRepositoryInfos;
-			RepositoryInfo*		fInstalledRepository;
-};
-
-
-struct BSolver::Implementation::SolvQueue : Queue {
-	SolvQueue()
-	{
-		queue_init(this);
-	}
-
-	~SolvQueue()
-	{
-		queue_free(this);
-	}
-};
-
-
-struct BSolver::Implementation::RepositoryInfo {
-	RepositoryInfo(BSolverRepository* repository)
-		:
-		fRepository(repository),
-		fSolvRepo(NULL)
-	{
-	}
-
-	BSolverRepository* Repository() const
-	{
-		return fRepository;
-	}
-
-	Repo* SolvRepo()
-	{
-		return fSolvRepo;
-	}
-
-	void SetSolvRepo(Repo* repo)
-	{
-		fSolvRepo = repo;
-	}
-
-private:
-	BSolverRepository*	fRepository;
-	Repo*				fSolvRepo;
-};
-
-
-// #pragma mark - BSolver
+	sCreateSolver = (CreateSolverFunction*)dlsym(imageHandle, "create_solver");
+	if (sCreateSolver == NULL)
+		dlclose(imageHandle);
+}
 
 
 BSolver::BSolver()
-	:
-	fImplementation(new(std::nothrow) Implementation)
 {
 }
 
 
 BSolver::~BSolver()
 {
-	delete fImplementation;
 }
 
 
-status_t
-BSolver::Init()
+/*static*/ status_t
+BSolver::Create(BSolver*& _solver)
 {
-	return fImplementation != NULL ? fImplementation->Init() : B_NO_MEMORY;
-}
+	pthread_once(&sLoadLibsolvSolverAddOnInitOnce, &load_libsolv_solver_add_on);
+	if (sCreateSolver == NULL)
+		return B_NOT_SUPPORTED;
 
-
-status_t
-BSolver::AddRepository(BSolverRepository* repository)
-{
-	return fImplementation != NULL
-		? fImplementation->AddRepository(repository) : B_NO_MEMORY;
-}
-
-
-status_t
-BSolver::Install(const BSolverPackageSpecifierList& packages)
-{
-	return fImplementation != NULL
-		? fImplementation->Install(packages) : B_NO_MEMORY;
-}
-
-
-// #pragma mark - BSolver::Implementation
-
-
-BSolver::Implementation::Implementation()
-	:
-	fPool(NULL),
-	fRepositoryInfos(),
-	fInstalledRepository(NULL)
-{
-}
-
-
-BSolver::Implementation::~Implementation()
-{
-	if (fPool != NULL)
-		pool_free(fPool);
-}
-
-
-status_t
-BSolver::Implementation::Init()
-{
-	// already initialized?
-	if (fPool != NULL)
-		return B_BAD_VALUE;
-
-	fPool = pool_create();
-
-	// Set the system architecture. We use what uname() returns unless we're on
-	// x86 gcc2.
-	{
-		const char* arch;
-		#ifdef __HAIKU_ARCH_X86
-			#if (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2
-				arch = "x86_gcc2";
-			#else
-				arch = "x86";
-			#endif
-		#else
-			struct utsname info;
-			if (uname(&info) != 0)
-				return errno;
-			arch = info.machine;
-		#endif
-
-		pool_setarchpolicy(fPool, arch);
-	}
-
-	return B_OK;
-}
-
-
-status_t
-BSolver::Implementation::AddRepository(BSolverRepository* repository)
-{
-	if (repository == NULL || repository->InitCheck() != B_OK)
-		return B_BAD_VALUE;
-
-	// If the repository represents installed packages, check, if we already
-	// have such a repository.
-	if (repository->IsInstalled() && fInstalledRepository != NULL)
-		return B_BAD_VALUE;
-
-	// add the repository info
-	RepositoryInfo* info = new(std::nothrow) RepositoryInfo(repository);
-	if (info == NULL)
+	BSolver* solver = sCreateSolver();
+	if (solver == NULL)
 		return B_NO_MEMORY;
 
-	if (!fRepositoryInfos.AddItem(info)) {
-		delete info;
-		return B_NO_MEMORY;
-	}
-
-	if (repository->IsInstalled())
-		fInstalledRepository = info;
-
-	return B_OK;
-}
-
-
-status_t
-BSolver::Implementation::Install(const BSolverPackageSpecifierList& packages)
-{
-	if (packages.IsEmpty())
-		return B_BAD_VALUE;
-
-// TODO: Clean up first?
-
-	// add repositories to pool
-	status_t error = _AddRepositories();
-	if (error != B_OK)
+	status_t error = solver->Init();
+	if (error != B_OK) {
+		delete solver;
 		return error;
-
-	// prepare pool for solving
-	pool_createwhatprovides(fPool);
-
-	// add the packages to install to the job queue
-	SolvQueue jobs;
-
-	int32 packageCount = packages.CountSpecifiers();
-	for (int32 i = 0; i < packageCount; i++) {
-		const BSolverPackageSpecifier& specifier = *packages.SpecifierAt(i);
-
-		// find matching packages
-		SolvQueue matchingPackages;
-
-		int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB
-			| SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL;
-// TODO: All flags needed/useful?
-		/*int matchFlags =*/ selection_make(fPool, &matchingPackages,
-			specifier.Expression().Name(), flags);
-// TODO: Don't just match the name, but also the version, if given!
-		if (matchingPackages.count == 0)
-			return B_NAME_NOT_FOUND;
-
-		// restrict to the matching repository
-		if (BSolverRepository* repository = specifier.Repository()) {
-			RepositoryInfo* repositoryInfo = _GetRepositoryInfo(repository);
-			if (repositoryInfo == NULL)
-				return B_BAD_VALUE;
-
-			SolvQueue repoFilter;
-			queue_push2(&repoFilter,
-				SOLVER_SOLVABLE_REPO/* | SOLVER_SETREPO | SOLVER_SETVENDOR*/,
-				repositoryInfo->SolvRepo()->repoid);
-
-			selection_filter(fPool, &matchingPackages, &repoFilter);
-
-			if (matchingPackages.count == 0)
-				return B_NAME_NOT_FOUND;
-		}
-
-		for (int j = 0; j < matchingPackages.count; j++)
-			queue_push(&jobs, matchingPackages.elements[j]);
-	}
-
-	// add solver mode to job queue elements
-	int solverMode = SOLVER_INSTALL;
-	for (int i = 0; i < jobs.count; i += 2) {
-		jobs.elements[i] |= solverMode;
-//		if (cleandeps)
-//			jobs.elements[i] |= SOLVER_CLEANDEPS;
-//		if (forcebest)
-//			jobs.elements[i] |= SOLVER_FORCEBEST;
-	}
-
-	// create the solver and solve
-	Solver* solver = solver_create(fPool);
-	solver_set_flag(solver, SOLVER_FLAG_SPLITPROVIDES, 1);
-	solver_set_flag(solver, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
-
-	int problemCount = solver_solve(solver, &jobs);
-	solver_free(solver);
-
-// TODO: Problem support!
-	return problemCount == 0 ? B_OK : B_BAD_VALUE;
-}
-
-
-status_t
-BSolver::Implementation::_AddRepositories()
-{
-	if (fInstalledRepository == NULL)
-		return B_BAD_VALUE;
-
-	int32 repositoryCount = fRepositoryInfos.CountItems();
-	for (int32 i = 0; i < repositoryCount; i++) {
-		RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
-		BSolverRepository* repository = repositoryInfo->Repository();
-		Repo* repo = repo_create(fPool, repository->Name());
-		repositoryInfo->SetSolvRepo(repo);
-
-		repo->priority = 256 - repository->Priority();
-		repo->appdata = (void*)repositoryInfo;
-
-		BRepositoryCache::Iterator it = repository->GetIterator();
-		while (const BPackageInfo* packageInfo = it.Next()) {
-			repo_add_haiku_package_info(repo, *packageInfo,
-				REPO_REUSE_REPODATA | REPO_NO_INTERNALIZE);
-		}
-
-		repo_internalize(repo);
-
-		if (repository->IsInstalled())
-			pool_set_installed(fPool, repo);
 	}
 
+	_solver = solver;
 	return B_OK;
 }
 
 
-BSolver::Implementation::RepositoryInfo*
-BSolver::Implementation::_GetRepositoryInfo(BSolverRepository* repository) const
-{
-	int32 repositoryCount = fRepositoryInfos.CountItems();
-	for (int32 i = 0; i < repositoryCount; i++) {
-		RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
-		if (repository == repositoryInfo->Repository())
-			return repositoryInfo;
-	}
-
-	return NULL;
-}
-
-
 }	// namespace BPackageKit
diff --git a/src/kits/package/solver/SolverPackage.cpp b/src/kits/package/solver/SolverPackage.cpp
new file mode 100644
index 0000000000..23dfba75ea
--- /dev/null
+++ b/src/kits/package/solver/SolverPackage.cpp
@@ -0,0 +1,78 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+
+namespace BPackageKit {
+
+
+BSolverPackage::BSolverPackage(BSolverRepository* repository,
+	const BPackageInfo& packageInfo)
+	:
+	fRepository(repository),
+	fInfo(packageInfo)
+{
+}
+
+
+BSolverPackage::BSolverPackage(const BSolverPackage& other)
+	:
+	fRepository(other.fRepository),
+	fInfo(other.fInfo)
+{
+}
+
+
+BSolverPackage::~BSolverPackage()
+{
+}
+
+
+BSolverRepository*
+BSolverPackage::Repository() const
+{
+	return fRepository;
+}
+
+
+const BPackageInfo&
+BSolverPackage::Info() const
+{
+	return fInfo;
+}
+
+
+BString
+BSolverPackage::Name() const
+{
+	return fInfo.Name();
+}
+
+
+BString
+BSolverPackage::VersionedName() const
+{
+	if (fInfo.Version().InitCheck() != B_OK)
+		return Name();
+	BString result = Name();
+	return result << '-' << fInfo.Version().ToString();
+}
+
+
+BSolverPackage&
+BSolverPackage::operator=(const BSolverPackage& other)
+{
+	fRepository = other.fRepository;
+	fInfo = other.fInfo;
+	return *this;
+}
+
+
+}	// namespace BPackageKit
diff --git a/src/kits/package/solver/SolverPackageSpecifierList.cpp b/src/kits/package/solver/SolverPackageSpecifierList.cpp
index b15c776a5f..6544179079 100644
--- a/src/kits/package/solver/SolverPackageSpecifierList.cpp
+++ b/src/kits/package/solver/SolverPackageSpecifierList.cpp
@@ -101,6 +101,13 @@ BSolverPackageSpecifierList::AppendSpecifier(
 }
 
 
+void
+BSolverPackageSpecifierList::MakeEmpty()
+{
+	fSpecifiers->clear();
+}
+
+
 BSolverPackageSpecifierList&
 BSolverPackageSpecifierList::operator=(const BSolverPackageSpecifierList& other)
 {
diff --git a/src/kits/package/solver/SolverProblem.cpp b/src/kits/package/solver/SolverProblem.cpp
new file mode 100644
index 0000000000..034f3d2ad6
--- /dev/null
+++ b/src/kits/package/solver/SolverProblem.cpp
@@ -0,0 +1,118 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+#include 
+
+#include 
+
+
+static const char* const kToStringTexts[] = {
+	"unspecified problem",
+	"%source% does not belong to a distupgrade repository",
+	"%source% has inferior architecture",
+	"problem with installed package %source%",
+	"conflicting requests",
+	"nothing provides requested %dependency%",
+	"%dependency% is provided by the system",
+	"dependency problem",
+	"package %source% is not installable",
+	"nothing provides %dependency% needed by %source%",
+	"cannot install both %source% and %target%",
+	"package %source% conflicts with %dependency% provided by %target%",
+	"package %source% obsoletes %dependency% provided by %target%",
+	"installed package %source% obsoletes %dependency% provided by %target%",
+	"package %source% implicitly obsoletes %dependency% provided by %target%",
+	"package %source% requires %dependency%, but none of the providers can be "
+		"installed",
+	"package %source% conflicts with %dependency% provided by itself"
+};
+
+
+namespace BPackageKit {
+
+
+BSolverProblem::BSolverProblem(BType type, BSolverPackage* sourcePackage,
+	BSolverPackage* targetPackage)
+	:
+	fType(type),
+	fSourcePackage(sourcePackage),
+	fTargetPackage(targetPackage),
+	fDependency()
+{
+}
+
+
+BSolverProblem::BSolverProblem(BType type, BSolverPackage* sourcePackage,
+	BSolverPackage* targetPackage,
+	const BPackageResolvableExpression& dependency)
+	:
+	fType(type),
+	fSourcePackage(sourcePackage),
+	fTargetPackage(targetPackage),
+	fDependency(dependency)
+{
+}
+
+
+BSolverProblem::~BSolverProblem()
+{
+}
+
+
+BSolverProblem::BType
+BSolverProblem::Type() const
+{
+	return fType;
+}
+
+
+BSolverPackage*
+BSolverProblem::SourcePackage() const
+{
+	return fSourcePackage;
+}
+
+
+BSolverPackage*
+BSolverProblem::TargetPackage() const
+{
+	return fTargetPackage;
+}
+
+
+const BPackageResolvableExpression&
+BSolverProblem::Dependency() const
+{
+	return fDependency;
+}
+
+
+BString
+BSolverProblem::ToString() const
+{
+	size_t index = fType;
+	if (index >= sizeof(kToStringTexts) / sizeof(kToStringTexts[0]))
+		index = 0;
+
+	return BString(kToStringTexts[index])
+		.ReplaceAll("%source%",
+			fSourcePackage != NULL 
+				? fSourcePackage->VersionedName().String() : "?")
+		.ReplaceAll("%target%",
+			fTargetPackage != NULL
+				? fTargetPackage->VersionedName().String() : "?")
+		.ReplaceAll("%dependency%",
+			fDependency.InitCheck() == B_OK
+				? fDependency.ToString().String() : "?");
+}
+
+
+}	// namespace BPackageKit
diff --git a/src/kits/package/solver/SolverRepository.cpp b/src/kits/package/solver/SolverRepository.cpp
index 93c2f78707..d3bd4dd141 100644
--- a/src/kits/package/solver/SolverRepository.cpp
+++ b/src/kits/package/solver/SolverRepository.cpp
@@ -13,6 +13,10 @@
 #include 
 #include 
 #include 
+#include 
+
+
+static const int32 kInitialPackageListSize = 40;
 
 
 namespace BPackageKit {
@@ -23,7 +27,7 @@ BSolverRepository::BSolverRepository()
 	fName(),
 	fPriority(0),
 	fIsInstalled(false),
-	fPackages()
+	fPackages(kInitialPackageListSize, true)
 {
 }
 
@@ -33,7 +37,7 @@ BSolverRepository::BSolverRepository(const BString& name)
 	fName(),
 	fPriority(0),
 	fIsInstalled(false),
-	fPackages()
+	fPackages(kInitialPackageListSize, true)
 {
 	SetTo(name);
 }
@@ -44,7 +48,7 @@ BSolverRepository::BSolverRepository(BPackageInstallationLocation location)
 	fName(),
 	fPriority(0),
 	fIsInstalled(false),
-	fPackages()
+	fPackages(kInitialPackageListSize, true)
 {
 	SetTo(location);
 }
@@ -55,7 +59,7 @@ BSolverRepository::BSolverRepository(BAllInstallationLocations)
 	fName(),
 	fPriority(0),
 	fIsInstalled(false),
-	fPackages()
+	fPackages(kInitialPackageListSize, true)
 {
 	SetTo(B_ALL_INSTALLATION_LOCATIONS);
 }
@@ -66,7 +70,7 @@ BSolverRepository::BSolverRepository(const BRepositoryConfig& config)
 	fName(),
 	fPriority(0),
 	fIsInstalled(false),
-	fPackages()
+	fPackages(kInitialPackageListSize, true)
 {
 	SetTo(config);
 }
@@ -184,6 +188,13 @@ BSolverRepository::IsInstalled() const
 }
 
 
+void
+BSolverRepository::SetInstalled(bool isInstalled)
+{
+	fIsInstalled = isInstalled;
+}
+
+
 BString
 BSolverRepository::Name() const
 {
@@ -198,10 +209,37 @@ BSolverRepository::Priority() const
 }
 
 
+bool
+BSolverRepository::IsEmpty() const
+{
+	return fPackages.IsEmpty();
+}
+
+
+int32
+BSolverRepository::CountPackages() const
+{
+	return fPackages.CountItems();
+}
+
+
+BSolverPackage*
+BSolverRepository::PackageAt(int32 index) const
+{
+	return fPackages.ItemAt(index);
+}
+
+
 status_t
 BSolverRepository::AddPackage(const BPackageInfo& info)
 {
-	return fPackages.AddInfo(info);
+	BSolverPackage* package = new(std::nothrow) BSolverPackage(this, info);
+	if (package == NULL || !fPackages.AddItem(package)) {
+		delete package;
+		return B_NO_MEMORY;
+	}
+
+	return B_OK;
 }
 
 
@@ -216,7 +254,7 @@ BSolverRepository::AddPackages(BPackageInstallationLocation location)
 
 	BRepositoryCache::Iterator it = packageInfos.GetIterator();
 	while (const BPackageInfo* packageInfo = it.Next()) {
-		error = fPackages.AddInfo(*packageInfo);
+		error = AddPackage(*packageInfo);
 		if (error != B_OK)
 			return error;
 	}
@@ -225,11 +263,4 @@ BSolverRepository::AddPackages(BPackageInstallationLocation location)
 }
 
 
-BSolverRepository::Iterator
-BSolverRepository::GetIterator() const
-{
-	return fPackages.GetIterator();
-}
-
-
 }	// namespace BPackageKit
diff --git a/src/kits/package/solver/SolverResult.cpp b/src/kits/package/solver/SolverResult.cpp
new file mode 100644
index 0000000000..581233969a
--- /dev/null
+++ b/src/kits/package/solver/SolverResult.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+
+namespace BPackageKit {
+
+
+// #pragma mark - BSolverResultElement
+
+
+BSolverResultElement::BSolverResultElement(BType type, BSolverPackage* package)
+	:
+	fType(type),
+	fPackage(package)
+{
+}
+
+
+BSolverResultElement::BSolverResultElement(const BSolverResultElement& other)
+	:
+	fType(other.fType),
+	fPackage(other.fPackage)
+{
+}
+
+
+BSolverResultElement::~BSolverResultElement()
+{
+}
+
+
+BSolverResultElement::BType
+BSolverResultElement::Type() const
+{
+	return fType;
+}
+
+
+BSolverPackage*
+BSolverResultElement::Package() const
+{
+	return fPackage;
+}
+
+
+BSolverResultElement&
+BSolverResultElement::operator=(const BSolverResultElement& other)
+{
+	fType = other.fType;
+	fPackage = other.fPackage;
+	return *this;
+}
+
+
+// #pragma mark - BSolverResult
+
+
+BSolverResult::BSolverResult()
+	:
+	fElements(20, true)
+{
+}
+
+
+BSolverResult::~BSolverResult()
+{
+}
+
+
+bool
+BSolverResult::IsEmpty() const
+{
+	return fElements.IsEmpty();
+}
+
+
+int32
+BSolverResult::CountElements() const
+{
+	return fElements.CountItems();
+}
+
+
+const BSolverResultElement*
+BSolverResult::ElementAt(int32 index) const
+{
+	return fElements.ItemAt(index);
+}
+
+
+void
+BSolverResult::MakeEmpty()
+{
+	fElements.MakeEmpty();
+}
+
+
+bool
+BSolverResult::AppendElement(const BSolverResultElement& element)
+{
+	BSolverResultElement* newElement
+		= new(std::nothrow) BSolverResultElement(element);
+	if (newElement == NULL || !fElements.AddItem(newElement)) {
+		delete newElement;
+		return false;
+	}
+
+	return true;
+}
+
+
+}	// namespace BPackageKit

From 1acf2be80dd9d6409fd3a4f6d304896fb9aeb286 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 02:32:50 +0000
Subject: [PATCH 0338/1170] pkgman: Add command resolve-build-dependencies

This is a service command for haikuporter. It resolves the dependencies
for a package to be built and lists them, so that haikuporter can
prepare the build environment accordingly.

The implementation isn't quite finished yet. Currently the packages are
printed only with name and version, while it would probably be more
helpful to print the path of the package file. Also, the package itself
(respectively a dummy package) is printed as well.
---
 src/bin/pkgman/Jamfile                        |   3 +-
 .../command_resolve_build_dependencies.cpp    | 413 ++++++++++++++++++
 src/bin/pkgman/pkgman.cpp                     |   7 +
 src/bin/pkgman/pkgman.h                       |   2 +-
 4 files changed, 423 insertions(+), 2 deletions(-)
 create mode 100644 src/bin/pkgman/command_resolve_build_dependencies.cpp

diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile
index f8f93155e8..b752c4a6b6 100644
--- a/src/bin/pkgman/Jamfile
+++ b/src/bin/pkgman/Jamfile
@@ -1,10 +1,11 @@
 SubDir HAIKU_TOP src bin pkgman ;
 
-UsePrivateHeaders support ;
+UsePrivateHeaders shared support ;
 
 BinCommand pkgman :
 	command_add_repo.cpp
 	command_drop_repo.cpp
+	command_resolve_build_dependencies.cpp
 	command_list_repos.cpp
 	command_refresh.cpp
 	DecisionProvider.cpp
diff --git a/src/bin/pkgman/command_resolve_build_dependencies.cpp b/src/bin/pkgman/command_resolve_build_dependencies.cpp
new file mode 100644
index 0000000000..2ebbb59494
--- /dev/null
+++ b/src/bin/pkgman/command_resolve_build_dependencies.cpp
@@ -0,0 +1,413 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+//#include "DecisionProvider.h"
+//#include "JobStateListener.h"
+#include "pkgman.h"
+
+
+using namespace BPackageKit;
+
+
+// TODO: internationalization!
+
+
+struct PackageInfoErrorListener : public BPackageInfo::ParseErrorListener {
+public:
+	PackageInfoErrorListener(const BString& errorContext)
+		:
+		fErrorContext(errorContext)
+	{
+	}
+
+	virtual void OnError(const BString& message, int line, int column)
+	{
+		fprintf(stderr, "%s: Parse error in line %d:%d: %s\n",
+			fErrorContext.String(), line, column, message.String());
+	}
+
+private:
+	BString	fErrorContext;
+};
+
+
+struct RepositoryBuilder {
+	RepositoryBuilder(BSolverRepository& repository, const BString& name,
+		const BString& errorName = BString())
+		:
+		fRepository(repository),
+		fErrorName(errorName.IsEmpty() ? name : errorName)
+	{
+		status_t error = fRepository.SetTo(name);
+		if (error != B_OK)
+			DIE(error, "failed to init %s repository", fErrorName.String());
+	}
+
+	RepositoryBuilder& AddPackage(const BPackageInfo& info,
+		const char* packageErrorName = NULL)
+	{
+		status_t error = fRepository.AddPackage(info);
+		if (error != B_OK) {
+			DIE(error, "failed to add %s to %s repository",
+				packageErrorName != NULL
+					? packageErrorName
+					: (BString("package ") << info.Name()).String(),
+				fErrorName.String());
+		}
+		return *this;
+	}
+
+	RepositoryBuilder& AddPackages(BPackageInstallationLocation location,
+		const char* locationErrorName)
+	{
+		status_t error = fRepository.AddPackages(location);
+		if (error != B_OK) {
+			DIE(error, "failed to add %s packages to %s repository",
+				locationErrorName, fErrorName.String());
+		}
+		return *this;
+	}
+
+	RepositoryBuilder& AddPackagesDirectory(const char* path)
+	{
+		// open directory
+		DIR* dir = opendir(path);
+		if (dir == NULL)
+			DIE(errno, "failed to open package directory \"%s\"", path);
+		CObjectDeleter dirCloser(dir, &closedir);
+
+		// iterate through directory entries
+		while (dirent* entry = readdir(dir)) {
+			// skip "." and ".."
+			const char* name = entry->d_name;
+			if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+				continue;
+
+			// stat() the entry and skip any non-file
+			BPath entryPath;
+			status_t error = entryPath.SetTo(path, name);
+			if (error != B_OK)
+				DIE(errno, "failed to construct path");
+
+			struct stat st;
+			if (lstat(entryPath.Path(), &st) != 0)
+				DIE(errno, "failed to stat() %s", entryPath.Path());
+
+			if (!S_ISREG(st.st_mode))
+				continue;
+
+			// read a package info from the (HPKG or package info) file
+			BPackageInfo packageInfo;
+
+			size_t nameLength = strlen(name);
+			if (nameLength > 5 && strcmp(name + nameLength - 5, ".hpkg") == 0) {
+				// a package file
+				error = packageInfo.ReadFromPackageFile(entryPath.Path());
+			} else {
+				// a package info file (supposedly)
+				PackageInfoErrorListener errorListener("reading package info");
+				error = packageInfo.ReadFromConfigFile(BEntry(entryPath.Path()),
+					&errorListener);
+			}
+
+			if (error != B_OK) {
+				DIE(errno, "failed to read package info from \"%s\"",
+					entryPath.Path());
+			}
+
+			AddPackage(packageInfo, entryPath.Path());
+		}
+
+		return *this;
+	}
+
+	RepositoryBuilder& AddToSolver(BSolver* solver, bool isInstalled = false)
+	{
+		fRepository.SetInstalled(isInstalled);
+
+		status_t error = solver->AddRepository(&fRepository);
+		if (error != B_OK) {
+			DIE(error, "failed to add %s repository to solver",
+				fErrorName.String());
+		}
+		return *this;
+	}
+
+private:
+	BSolverRepository&	fRepository;
+	BString				fErrorName;
+};
+
+
+static const char* kCommandUsage =
+	"Usage: %s resolve-build-dependencies  \n"
+	"   [  ... ]\n"
+	"Resolves and lists all packages needed for building a package. Fails, if\n"
+	"not all dependencies could be resolved.\n"
+	"\n"
+	"\n"
+	"  The package info for the package to be built, requiring all build\n"
+	"  requisites.\n"
+	"\n"
+	"  A text file listing the package's build prerequisites, i.e. the\n"
+	"  requisites that must be installed from the host environment.\n"
+	"\n"
+	"  Path to a directory containing package infos for all the packages that\n"
+	"  can be built. This repository is used to resolve the build requisites\n"
+	"  the package to build.\n"
+	"\n"
+	"  Path to a directory containing packages from which the package's\n"
+	"  prerequisites shall be resolved. Multiple directories can be\n"
+	"  specified. If none is given, the system's installed packages are used.\n"
+	"\n"
+;
+
+static const char* kPrerequisitesPackageInfoTemplate =
+	"name			_build_prerequisites_\n"
+	"version		1.0.0-1\n"
+	"architecture	%s\n"
+	"summary		none\n"
+	"description	none\n"
+	"packager		none\n"
+	"vendor			\"%s\"\n"
+	"licenses {\n"
+	"	MIT\n"
+	"}\n"
+	"copyrights {\n"
+	"	none\n"
+	"}\n"
+	"provides {\n"
+	"	_build_prerequisites_ = 1.0.0\n"
+	"}\n"
+	"requires {\n %s }\n";
+
+
+static void
+print_command_usage_and_exit(bool error)
+{
+    fprintf(error ? stderr : stdout, kCommandUsage, kProgramName);
+    exit(error ? 1 : 0);
+}
+
+
+static void
+resolve_packages(BSolver* solver, const BPackageInfo& packageInfo,
+	bool isPrerequisitePhase, BSolverResult& _result)
+{
+	const char* requisitesString = isPrerequisitePhase
+		? "prerequisites" :"requisites";
+
+	// add a repository with the build package resolvable
+	BSolverRepository dummyRepository;
+	RepositoryBuilder(dummyRepository, "dummy", "build package")
+		.AddPackage(packageInfo, "package to install")
+		.AddToSolver(solver);
+
+	// resolve
+	BSolverPackageSpecifierList packagesToInstall;
+	if (!packagesToInstall.AppendSpecifier(
+			BSolverPackageSpecifier(&dummyRepository,
+				BPackageResolvableExpression(packageInfo.Name())))) {
+		DIE(B_NO_MEMORY, "failed to add package to install");
+	}
+
+	status_t error = solver->Install(packagesToInstall);
+	if (error != B_OK)
+		DIE(error, "failed to resolve %s", requisitesString);
+
+	if (solver->HasProblems()) {
+		fprintf(stderr, "Encountered problems resolving %s:\n",
+			requisitesString);
+
+		int32 problemCount = solver->CountProblems();
+		for (int32 i = 0; i < problemCount; i++) {
+			printf("  %" B_PRId32 ": %s\n", i + 1,
+				solver->ProblemAt(i)->ToString().String());
+		}
+		exit(1);
+	}
+
+	BSolverResult& result = _result;
+	error = solver->GetResult(result);
+	if (error != B_OK)
+		DIE(error, "failed to resolve %s", requisitesString);
+
+	// print packages
+	printf("[%s]\n", requisitesString);
+	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
+			i++) {
+// TODO: Print the path to the package/package info!
+		printf("%s-%s\n",
+			element->Package()->Info().Name().String(),
+			element->Package()->Info().Version().ToString().String());
+// TODO: Filter out the given package!
+	}
+}
+
+
+int
+command_resolve_build_dependencies(int argc, const char* const* argv)
+{
+	while (true) {
+		static struct option sLongOptions[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ 0, 0, 0, 0 }
+		};
+
+		opterr = 0; // don't print errors
+		int c = getopt_long(argc, (char**)argv, "hu", sLongOptions, NULL);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'h':
+				print_command_usage_and_exit(false);
+				break;
+
+			default:
+				print_command_usage_and_exit(true);
+				break;
+		}
+	}
+
+	// The remaining arguments are the build package info, the prerequisites file,
+	// the build requisites directory, and zero or more prerequisites
+	// directories.
+	if (argc < optind + 3)
+		print_command_usage_and_exit(true);
+
+	const char* buildPackagePath = argv[optind++];
+	const char* prerequisitesPath = argv[optind++];
+	const char* requisitesDirectoryPath = argv[optind++];
+	int prerequisitesDirectoryPathCount = argc - optind;
+	const char* const* prerequisitesDirectoryPaths
+		= prerequisitesDirectoryPathCount > 0 ? argv + optind : NULL;
+
+	if (prerequisitesDirectoryPaths != NULL) {
+		DIE(B_NOT_SUPPORTED,
+			"sorry, prerequisite directory repositories not supported yet");
+// TODO: Support prerequisite directory repositories!
+	}
+
+	// read build package info
+	BEntry buildPackageEntry(buildPackagePath);
+	BPackageInfo buildPackageInfo;
+	PackageInfoErrorListener buildPackageInfoErrorListener(
+		"Error: Failed to parse package info");
+	status_t error = buildPackageInfo.ReadFromConfigFile(buildPackageEntry,
+		&buildPackageInfoErrorListener);
+	if (error != B_OK)
+		DIE(error, "failed to read build package info file");
+
+	// read the prerequisites file into a string
+	BString prerequisitesString;
+	BFile prerequisitesFile;
+	error = prerequisitesFile.SetTo(prerequisitesPath, B_READ_ONLY);
+	if (error != B_OK)
+		DIE(error, "failed to open prerequisites file");
+
+	off_t fileSize;
+	error = prerequisitesFile.GetSize(&fileSize);
+	if (error != B_OK)
+		DIE(error, "failed to get prerequisites file size");
+
+	if (char* buffer = prerequisitesString.LockBuffer(fileSize)) {
+		ssize_t bytesRead = prerequisitesFile.Read(buffer, fileSize);
+		if (bytesRead != fileSize) {
+			DIE(bytesRead < 0 ? (status_t)bytesRead :B_ERROR,
+				"failed to read prerequisites");
+		}
+	} else
+		DIE(B_NO_MEMORY, "failed to read prerequisites");
+
+	prerequisitesString.UnlockBuffer();
+	prerequisitesFile.Unset();
+
+	// create a package info that contains the build prerequisites
+	BPackageInfo prerequisitesPackageInfo;
+	PackageInfoErrorListener buildPrerequisitesPackageInfoErrorListener(
+		"Error: Failed to parse prerequisites package info");
+	error = prerequisitesPackageInfo.ReadFromConfigString(
+		BString().SetToFormat(kPrerequisitesPackageInfoTemplate,
+			BPackageInfo::kArchitectureNames[buildPackageInfo.Architecture()],
+			buildPackageInfo.Vendor().String(),
+			prerequisitesString.String()),
+		&buildPrerequisitesPackageInfoErrorListener);
+	if (error != B_OK)
+		DIE(error, "failed to create prerequisites package info");
+
+	// resolve the prerequisites
+
+	// create the solver
+	BSolver* solver;
+	error = BSolver::Create(solver);
+	if (error != B_OK)
+		DIE(error, "failed to create solver");
+
+	// add prerequisite repository
+	BSolverRepository prerequisiteRepository;
+	RepositoryBuilder(prerequisiteRepository, "prerequisites")
+		.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, "system")
+		.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common")
+		.AddToSolver(solver);
+
+	BSolverResult result;
+	resolve_packages(solver, prerequisitesPackageInfo, true, result);
+
+	// resolve the requisites
+
+	// reset the solver
+	error = solver->Init();
+	if (error != B_OK)
+		DIE(error, "failed to re-init solver");
+
+	// add an installation repository with the resolved prerequisites
+	BSolverRepository installationRepository;
+	RepositoryBuilder installationRepositoryBuilder(installationRepository,
+		"installation");
+	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
+			i++) {
+		installationRepositoryBuilder.AddPackage(element->Package()->Info());
+	}
+	installationRepositoryBuilder.AddToSolver(solver, true);
+
+	// add requisite repository
+	BSolverRepository requisiteRepository;
+	RepositoryBuilder(requisiteRepository, "requisites")
+		.AddPackagesDirectory(requisitesDirectoryPath)
+		.AddToSolver(solver);
+
+	resolve_packages(solver, buildPackageInfo, false, result);
+// TODO: We need to make sure that the package isn't part of a cyclic
+// dependency.
+
+	return 0;
+}
diff --git a/src/bin/pkgman/pkgman.cpp b/src/bin/pkgman/pkgman.cpp
index dc2f9c8912..bfa50d11a1 100644
--- a/src/bin/pkgman/pkgman.cpp
+++ b/src/bin/pkgman/pkgman.cpp
@@ -33,6 +33,10 @@ static const char* kUsage =
 	"  refresh [ ...]\n"
 	"    Refreshes all or just the given repositories.\n"
 	"\n"
+	"  resolve-build-dependencies  \n"
+	"       [  ... ]\n"
+	"    Resolves all packages needed for building a package.\n"
+	"\n"
 	"Common Options:\n"
 	"  -h, --help   - Print this usage info.\n"
 ;
@@ -56,6 +60,9 @@ main(int argc, const char* const* argv)
 	if (strncmp(command, "add-r", 5) == 0)
 		return command_add_repo(argc - 1, argv + 1);
 
+	if (strcmp(command, "list-build-dependency-packages") == 0)
+		return command_resolve_build_dependencies(argc - 1, argv + 1);
+
 	if (strncmp(command, "drop-r", 6) == 0)
 		return command_drop_repo(argc - 1, argv + 1);
 
diff --git a/src/bin/pkgman/pkgman.h b/src/bin/pkgman/pkgman.h
index c5641d2586..088cd23271 100644
--- a/src/bin/pkgman/pkgman.h
+++ b/src/bin/pkgman/pkgman.h
@@ -34,8 +34,8 @@ do {																\
 
 
 void	print_usage_and_exit(bool error);
-
 int		command_add_repo(int argc, const char* const* argv);
+int		command_resolve_build_dependencies(int argc, const char* const* argv);
 int		command_drop_repo(int argc, const char* const* argv);
 int		command_list_repos(int argc, const char* const* argv);
 int		command_refresh(int argc, const char* const* argv);

From 07a4d4e370d8edcd84e8c36b8f7eee1c88d60858 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 15:57:16 +0000
Subject: [PATCH 0339/1170] BSolverRepository: Add SetPriority()

---
 headers/os/package/solver/SolverRepository.h | 2 ++
 src/kits/package/solver/SolverRepository.cpp | 7 +++++++
 2 files changed, 9 insertions(+)

diff --git a/headers/os/package/solver/SolverRepository.h b/headers/os/package/solver/SolverRepository.h
index 187a3db95a..afca10b445 100644
--- a/headers/os/package/solver/SolverRepository.h
+++ b/headers/os/package/solver/SolverRepository.h
@@ -50,7 +50,9 @@ public:
 			void				SetInstalled(bool isInstalled);
 
 			BString				Name() const;
+
 			uint8				Priority() const;
+			void				SetPriority(uint8 priority);
 
 			bool				IsEmpty() const;
 			int32				CountPackages() const;
diff --git a/src/kits/package/solver/SolverRepository.cpp b/src/kits/package/solver/SolverRepository.cpp
index d3bd4dd141..f10360bea8 100644
--- a/src/kits/package/solver/SolverRepository.cpp
+++ b/src/kits/package/solver/SolverRepository.cpp
@@ -209,6 +209,13 @@ BSolverRepository::Priority() const
 }
 
 
+void
+BSolverRepository::SetPriority(uint8 priority)
+{
+	fPriority = priority;
+}
+
+
 bool
 BSolverRepository::IsEmpty() const
 {

From 19f3eaaee692a5edc59cb453540489a132c43b69 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 15:58:27 +0000
Subject: [PATCH 0340/1170] pkgman: Simplify and rename
 resolve-build-dependencies

* Now it only gets a package (info) file and a single list of
  repository directories, optionally with priority, and resolves the
  package's dependencies. The more complex two resolving steps it did
  before can just as well be done by haikuporter, and this way the
  command is more flexible.
* Rename to resolve-dependencies.
* Some TODOs still remain.
---
 src/bin/pkgman/Jamfile                        |   2 +-
 .../command_resolve_build_dependencies.cpp    | 413 ------------------
 .../pkgman/command_resolve_dependencies.cpp   | 311 +++++++++++++
 src/bin/pkgman/pkgman.cpp                     |  11 +-
 src/bin/pkgman/pkgman.h                       |   2 +-
 5 files changed, 318 insertions(+), 421 deletions(-)
 delete mode 100644 src/bin/pkgman/command_resolve_build_dependencies.cpp
 create mode 100644 src/bin/pkgman/command_resolve_dependencies.cpp

diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile
index b752c4a6b6..f6dfa06b37 100644
--- a/src/bin/pkgman/Jamfile
+++ b/src/bin/pkgman/Jamfile
@@ -5,7 +5,7 @@ UsePrivateHeaders shared support ;
 BinCommand pkgman :
 	command_add_repo.cpp
 	command_drop_repo.cpp
-	command_resolve_build_dependencies.cpp
+	command_resolve_dependencies.cpp
 	command_list_repos.cpp
 	command_refresh.cpp
 	DecisionProvider.cpp
diff --git a/src/bin/pkgman/command_resolve_build_dependencies.cpp b/src/bin/pkgman/command_resolve_build_dependencies.cpp
deleted file mode 100644
index 2ebbb59494..0000000000
--- a/src/bin/pkgman/command_resolve_build_dependencies.cpp
+++ /dev/null
@@ -1,413 +0,0 @@
-/*
- * Copyright 2013, Haiku, Inc. All Rights Reserved.
- * Distributed under the terms of the MIT License.
- *
- * Authors:
- *		Ingo Weinhold 
- */
-
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include 
-#include 
-#include 
-
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include 
-
-//#include "DecisionProvider.h"
-//#include "JobStateListener.h"
-#include "pkgman.h"
-
-
-using namespace BPackageKit;
-
-
-// TODO: internationalization!
-
-
-struct PackageInfoErrorListener : public BPackageInfo::ParseErrorListener {
-public:
-	PackageInfoErrorListener(const BString& errorContext)
-		:
-		fErrorContext(errorContext)
-	{
-	}
-
-	virtual void OnError(const BString& message, int line, int column)
-	{
-		fprintf(stderr, "%s: Parse error in line %d:%d: %s\n",
-			fErrorContext.String(), line, column, message.String());
-	}
-
-private:
-	BString	fErrorContext;
-};
-
-
-struct RepositoryBuilder {
-	RepositoryBuilder(BSolverRepository& repository, const BString& name,
-		const BString& errorName = BString())
-		:
-		fRepository(repository),
-		fErrorName(errorName.IsEmpty() ? name : errorName)
-	{
-		status_t error = fRepository.SetTo(name);
-		if (error != B_OK)
-			DIE(error, "failed to init %s repository", fErrorName.String());
-	}
-
-	RepositoryBuilder& AddPackage(const BPackageInfo& info,
-		const char* packageErrorName = NULL)
-	{
-		status_t error = fRepository.AddPackage(info);
-		if (error != B_OK) {
-			DIE(error, "failed to add %s to %s repository",
-				packageErrorName != NULL
-					? packageErrorName
-					: (BString("package ") << info.Name()).String(),
-				fErrorName.String());
-		}
-		return *this;
-	}
-
-	RepositoryBuilder& AddPackages(BPackageInstallationLocation location,
-		const char* locationErrorName)
-	{
-		status_t error = fRepository.AddPackages(location);
-		if (error != B_OK) {
-			DIE(error, "failed to add %s packages to %s repository",
-				locationErrorName, fErrorName.String());
-		}
-		return *this;
-	}
-
-	RepositoryBuilder& AddPackagesDirectory(const char* path)
-	{
-		// open directory
-		DIR* dir = opendir(path);
-		if (dir == NULL)
-			DIE(errno, "failed to open package directory \"%s\"", path);
-		CObjectDeleter dirCloser(dir, &closedir);
-
-		// iterate through directory entries
-		while (dirent* entry = readdir(dir)) {
-			// skip "." and ".."
-			const char* name = entry->d_name;
-			if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
-				continue;
-
-			// stat() the entry and skip any non-file
-			BPath entryPath;
-			status_t error = entryPath.SetTo(path, name);
-			if (error != B_OK)
-				DIE(errno, "failed to construct path");
-
-			struct stat st;
-			if (lstat(entryPath.Path(), &st) != 0)
-				DIE(errno, "failed to stat() %s", entryPath.Path());
-
-			if (!S_ISREG(st.st_mode))
-				continue;
-
-			// read a package info from the (HPKG or package info) file
-			BPackageInfo packageInfo;
-
-			size_t nameLength = strlen(name);
-			if (nameLength > 5 && strcmp(name + nameLength - 5, ".hpkg") == 0) {
-				// a package file
-				error = packageInfo.ReadFromPackageFile(entryPath.Path());
-			} else {
-				// a package info file (supposedly)
-				PackageInfoErrorListener errorListener("reading package info");
-				error = packageInfo.ReadFromConfigFile(BEntry(entryPath.Path()),
-					&errorListener);
-			}
-
-			if (error != B_OK) {
-				DIE(errno, "failed to read package info from \"%s\"",
-					entryPath.Path());
-			}
-
-			AddPackage(packageInfo, entryPath.Path());
-		}
-
-		return *this;
-	}
-
-	RepositoryBuilder& AddToSolver(BSolver* solver, bool isInstalled = false)
-	{
-		fRepository.SetInstalled(isInstalled);
-
-		status_t error = solver->AddRepository(&fRepository);
-		if (error != B_OK) {
-			DIE(error, "failed to add %s repository to solver",
-				fErrorName.String());
-		}
-		return *this;
-	}
-
-private:
-	BSolverRepository&	fRepository;
-	BString				fErrorName;
-};
-
-
-static const char* kCommandUsage =
-	"Usage: %s resolve-build-dependencies  \n"
-	"   [  ... ]\n"
-	"Resolves and lists all packages needed for building a package. Fails, if\n"
-	"not all dependencies could be resolved.\n"
-	"\n"
-	"\n"
-	"  The package info for the package to be built, requiring all build\n"
-	"  requisites.\n"
-	"\n"
-	"  A text file listing the package's build prerequisites, i.e. the\n"
-	"  requisites that must be installed from the host environment.\n"
-	"\n"
-	"  Path to a directory containing package infos for all the packages that\n"
-	"  can be built. This repository is used to resolve the build requisites\n"
-	"  the package to build.\n"
-	"\n"
-	"  Path to a directory containing packages from which the package's\n"
-	"  prerequisites shall be resolved. Multiple directories can be\n"
-	"  specified. If none is given, the system's installed packages are used.\n"
-	"\n"
-;
-
-static const char* kPrerequisitesPackageInfoTemplate =
-	"name			_build_prerequisites_\n"
-	"version		1.0.0-1\n"
-	"architecture	%s\n"
-	"summary		none\n"
-	"description	none\n"
-	"packager		none\n"
-	"vendor			\"%s\"\n"
-	"licenses {\n"
-	"	MIT\n"
-	"}\n"
-	"copyrights {\n"
-	"	none\n"
-	"}\n"
-	"provides {\n"
-	"	_build_prerequisites_ = 1.0.0\n"
-	"}\n"
-	"requires {\n %s }\n";
-
-
-static void
-print_command_usage_and_exit(bool error)
-{
-    fprintf(error ? stderr : stdout, kCommandUsage, kProgramName);
-    exit(error ? 1 : 0);
-}
-
-
-static void
-resolve_packages(BSolver* solver, const BPackageInfo& packageInfo,
-	bool isPrerequisitePhase, BSolverResult& _result)
-{
-	const char* requisitesString = isPrerequisitePhase
-		? "prerequisites" :"requisites";
-
-	// add a repository with the build package resolvable
-	BSolverRepository dummyRepository;
-	RepositoryBuilder(dummyRepository, "dummy", "build package")
-		.AddPackage(packageInfo, "package to install")
-		.AddToSolver(solver);
-
-	// resolve
-	BSolverPackageSpecifierList packagesToInstall;
-	if (!packagesToInstall.AppendSpecifier(
-			BSolverPackageSpecifier(&dummyRepository,
-				BPackageResolvableExpression(packageInfo.Name())))) {
-		DIE(B_NO_MEMORY, "failed to add package to install");
-	}
-
-	status_t error = solver->Install(packagesToInstall);
-	if (error != B_OK)
-		DIE(error, "failed to resolve %s", requisitesString);
-
-	if (solver->HasProblems()) {
-		fprintf(stderr, "Encountered problems resolving %s:\n",
-			requisitesString);
-
-		int32 problemCount = solver->CountProblems();
-		for (int32 i = 0; i < problemCount; i++) {
-			printf("  %" B_PRId32 ": %s\n", i + 1,
-				solver->ProblemAt(i)->ToString().String());
-		}
-		exit(1);
-	}
-
-	BSolverResult& result = _result;
-	error = solver->GetResult(result);
-	if (error != B_OK)
-		DIE(error, "failed to resolve %s", requisitesString);
-
-	// print packages
-	printf("[%s]\n", requisitesString);
-	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
-			i++) {
-// TODO: Print the path to the package/package info!
-		printf("%s-%s\n",
-			element->Package()->Info().Name().String(),
-			element->Package()->Info().Version().ToString().String());
-// TODO: Filter out the given package!
-	}
-}
-
-
-int
-command_resolve_build_dependencies(int argc, const char* const* argv)
-{
-	while (true) {
-		static struct option sLongOptions[] = {
-			{ "help", no_argument, 0, 'h' },
-			{ 0, 0, 0, 0 }
-		};
-
-		opterr = 0; // don't print errors
-		int c = getopt_long(argc, (char**)argv, "hu", sLongOptions, NULL);
-		if (c == -1)
-			break;
-
-		switch (c) {
-			case 'h':
-				print_command_usage_and_exit(false);
-				break;
-
-			default:
-				print_command_usage_and_exit(true);
-				break;
-		}
-	}
-
-	// The remaining arguments are the build package info, the prerequisites file,
-	// the build requisites directory, and zero or more prerequisites
-	// directories.
-	if (argc < optind + 3)
-		print_command_usage_and_exit(true);
-
-	const char* buildPackagePath = argv[optind++];
-	const char* prerequisitesPath = argv[optind++];
-	const char* requisitesDirectoryPath = argv[optind++];
-	int prerequisitesDirectoryPathCount = argc - optind;
-	const char* const* prerequisitesDirectoryPaths
-		= prerequisitesDirectoryPathCount > 0 ? argv + optind : NULL;
-
-	if (prerequisitesDirectoryPaths != NULL) {
-		DIE(B_NOT_SUPPORTED,
-			"sorry, prerequisite directory repositories not supported yet");
-// TODO: Support prerequisite directory repositories!
-	}
-
-	// read build package info
-	BEntry buildPackageEntry(buildPackagePath);
-	BPackageInfo buildPackageInfo;
-	PackageInfoErrorListener buildPackageInfoErrorListener(
-		"Error: Failed to parse package info");
-	status_t error = buildPackageInfo.ReadFromConfigFile(buildPackageEntry,
-		&buildPackageInfoErrorListener);
-	if (error != B_OK)
-		DIE(error, "failed to read build package info file");
-
-	// read the prerequisites file into a string
-	BString prerequisitesString;
-	BFile prerequisitesFile;
-	error = prerequisitesFile.SetTo(prerequisitesPath, B_READ_ONLY);
-	if (error != B_OK)
-		DIE(error, "failed to open prerequisites file");
-
-	off_t fileSize;
-	error = prerequisitesFile.GetSize(&fileSize);
-	if (error != B_OK)
-		DIE(error, "failed to get prerequisites file size");
-
-	if (char* buffer = prerequisitesString.LockBuffer(fileSize)) {
-		ssize_t bytesRead = prerequisitesFile.Read(buffer, fileSize);
-		if (bytesRead != fileSize) {
-			DIE(bytesRead < 0 ? (status_t)bytesRead :B_ERROR,
-				"failed to read prerequisites");
-		}
-	} else
-		DIE(B_NO_MEMORY, "failed to read prerequisites");
-
-	prerequisitesString.UnlockBuffer();
-	prerequisitesFile.Unset();
-
-	// create a package info that contains the build prerequisites
-	BPackageInfo prerequisitesPackageInfo;
-	PackageInfoErrorListener buildPrerequisitesPackageInfoErrorListener(
-		"Error: Failed to parse prerequisites package info");
-	error = prerequisitesPackageInfo.ReadFromConfigString(
-		BString().SetToFormat(kPrerequisitesPackageInfoTemplate,
-			BPackageInfo::kArchitectureNames[buildPackageInfo.Architecture()],
-			buildPackageInfo.Vendor().String(),
-			prerequisitesString.String()),
-		&buildPrerequisitesPackageInfoErrorListener);
-	if (error != B_OK)
-		DIE(error, "failed to create prerequisites package info");
-
-	// resolve the prerequisites
-
-	// create the solver
-	BSolver* solver;
-	error = BSolver::Create(solver);
-	if (error != B_OK)
-		DIE(error, "failed to create solver");
-
-	// add prerequisite repository
-	BSolverRepository prerequisiteRepository;
-	RepositoryBuilder(prerequisiteRepository, "prerequisites")
-		.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, "system")
-		.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common")
-		.AddToSolver(solver);
-
-	BSolverResult result;
-	resolve_packages(solver, prerequisitesPackageInfo, true, result);
-
-	// resolve the requisites
-
-	// reset the solver
-	error = solver->Init();
-	if (error != B_OK)
-		DIE(error, "failed to re-init solver");
-
-	// add an installation repository with the resolved prerequisites
-	BSolverRepository installationRepository;
-	RepositoryBuilder installationRepositoryBuilder(installationRepository,
-		"installation");
-	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
-			i++) {
-		installationRepositoryBuilder.AddPackage(element->Package()->Info());
-	}
-	installationRepositoryBuilder.AddToSolver(solver, true);
-
-	// add requisite repository
-	BSolverRepository requisiteRepository;
-	RepositoryBuilder(requisiteRepository, "requisites")
-		.AddPackagesDirectory(requisitesDirectoryPath)
-		.AddToSolver(solver);
-
-	resolve_packages(solver, buildPackageInfo, false, result);
-// TODO: We need to make sure that the package isn't part of a cyclic
-// dependency.
-
-	return 0;
-}
diff --git a/src/bin/pkgman/command_resolve_dependencies.cpp b/src/bin/pkgman/command_resolve_dependencies.cpp
new file mode 100644
index 0000000000..42f9a801c9
--- /dev/null
+++ b/src/bin/pkgman/command_resolve_dependencies.cpp
@@ -0,0 +1,311 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include "pkgman.h"
+
+
+using namespace BPackageKit;
+
+
+// TODO: internationalization!
+
+
+static const char* kCommandUsage =
+	"Usage: %s resolve-dependencies   [  ] ...\n"
+	"Resolves and lists all packages a given package depends on. Fails, if\n"
+	"not all dependencies could be resolved.\n"
+	"\n"
+	"\n"
+	"  The HPKG or package info file of the package for which the\n"
+	"  dependencies shall be resolved.\n"
+	"\n"
+	"  Path to a directory containing packages from which the package's\n"
+	"  dependencies shall be resolved. Multiple directories can be specified.\n"
+	"\n"
+	"  Can follow a  to specify the priority of that repository.\n"
+	"  The default priority is 0.\n"
+	"\n"
+;
+
+
+static void
+print_command_usage_and_exit(bool error)
+{
+    fprintf(error ? stderr : stdout, kCommandUsage, kProgramName);
+    exit(error ? 1 : 0);
+}
+
+
+struct PackageInfoErrorListener : public BPackageInfo::ParseErrorListener {
+public:
+	PackageInfoErrorListener(const BString& errorContext)
+		:
+		fErrorContext(errorContext)
+	{
+	}
+
+	virtual void OnError(const BString& message, int line, int column)
+	{
+		fprintf(stderr, "%s: Parse error in line %d:%d: %s\n",
+			fErrorContext.String(), line, column, message.String());
+	}
+
+private:
+	BString	fErrorContext;
+};
+
+
+struct RepositoryBuilder {
+	RepositoryBuilder(BSolverRepository& repository, const BString& name,
+		const BString& errorName = BString())
+		:
+		fRepository(repository),
+		fErrorName(errorName.IsEmpty() ? name : errorName)
+	{
+		status_t error = fRepository.SetTo(name);
+		if (error != B_OK)
+			DIE(error, "failed to init %s repository", fErrorName.String());
+	}
+
+	RepositoryBuilder& AddPackage(const BPackageInfo& info,
+		const char* packageErrorName = NULL)
+	{
+		status_t error = fRepository.AddPackage(info);
+		if (error != B_OK) {
+			DIE(error, "failed to add %s to %s repository",
+				packageErrorName != NULL
+					? packageErrorName
+					: (BString("package ") << info.Name()).String(),
+				fErrorName.String());
+		}
+		return *this;
+	}
+
+	RepositoryBuilder& AddPackage(const char* path)
+	{
+		// read a package info from the (HPKG or package info) file
+		BPackageInfo packageInfo;
+
+		size_t pathLength = strlen(path);
+		status_t error;
+		if (pathLength > 5 && strcmp(path + pathLength - 5, ".hpkg") == 0) {
+			// a package file
+			error = packageInfo.ReadFromPackageFile(path);
+		} else {
+			// a package info file (supposedly)
+			PackageInfoErrorListener errorListener(
+				"Error: failed to read package info");
+			error = packageInfo.ReadFromConfigFile(BEntry(path),
+				&errorListener);
+		}
+
+		if (error != B_OK)
+			DIE(errno, "failed to read package info from \"%s\"", path);
+
+		return AddPackage(packageInfo, path);
+	}
+
+	RepositoryBuilder& AddPackages(BPackageInstallationLocation location,
+		const char* locationErrorName)
+	{
+		status_t error = fRepository.AddPackages(location);
+		if (error != B_OK) {
+			DIE(error, "failed to add %s packages to %s repository",
+				locationErrorName, fErrorName.String());
+		}
+		return *this;
+	}
+
+	RepositoryBuilder& AddPackagesDirectory(const char* path)
+	{
+		// open directory
+		DIR* dir = opendir(path);
+		if (dir == NULL)
+			DIE(errno, "failed to open package directory \"%s\"", path);
+		CObjectDeleter dirCloser(dir, &closedir);
+
+		// iterate through directory entries
+		while (dirent* entry = readdir(dir)) {
+			// skip "." and ".."
+			const char* name = entry->d_name;
+			if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+				continue;
+
+			// stat() the entry and skip any non-file
+			BPath entryPath;
+			status_t error = entryPath.SetTo(path, name);
+			if (error != B_OK)
+				DIE(errno, "failed to construct path");
+
+			struct stat st;
+			if (lstat(entryPath.Path(), &st) != 0)
+				DIE(errno, "failed to stat() %s", entryPath.Path());
+
+			if (!S_ISREG(st.st_mode))
+				continue;
+
+			AddPackage(entryPath.Path());
+		}
+
+		return *this;
+	}
+
+	RepositoryBuilder& AddToSolver(BSolver* solver, bool isInstalled = false)
+	{
+		fRepository.SetInstalled(isInstalled);
+
+		status_t error = solver->AddRepository(&fRepository);
+		if (error != B_OK) {
+			DIE(error, "failed to add %s repository to solver",
+				fErrorName.String());
+		}
+		return *this;
+	}
+
+private:
+	BSolverRepository&	fRepository;
+	BString				fErrorName;
+};
+
+
+int
+command_resolve_dependencies(int argc, const char* const* argv)
+{
+	while (true) {
+		static struct option sLongOptions[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ 0, 0, 0, 0 }
+		};
+
+		opterr = 0; // don't print errors
+		int c = getopt_long(argc, (char**)argv, "hu", sLongOptions, NULL);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'h':
+				print_command_usage_and_exit(false);
+				break;
+
+			default:
+				print_command_usage_and_exit(true);
+				break;
+		}
+	}
+
+	// The remaining arguments are the package (info) file and the repository
+	// directories (at least one), optionally with priorities.
+	if (argc < optind + 2)
+		print_command_usage_and_exit(true);
+
+	const char* packagePath = argv[optind++];
+	int repositoryDirectoryCount = argc - optind;
+	const char* const* repositoryDirectories = argv + optind;
+
+	// create the solver
+	BSolver* solver;
+	status_t error = BSolver::Create(solver);
+	if (error != B_OK)
+		DIE(error, "failed to create solver");
+
+	// add repositories
+	BObjectList repositories(10, true);
+	int32 repositoryIndex = 0;
+	for (int i = 0; i < repositoryDirectoryCount; i++, repositoryIndex++) {
+		const char* directoryPath = repositoryDirectories[i];
+
+		BSolverRepository* repository = new(std::nothrow) BSolverRepository;
+		if (repository == NULL || !repositories.AddItem(repository))
+			DIE(B_NO_MEMORY, "failed to create repository");
+
+
+		if (i + 1 < repositoryDirectoryCount) {
+			char* end;
+			long priority = strtol(repositoryDirectories[i + 1], &end, 0);
+			if (*end == '\0') {
+				repository->SetPriority((uint8)priority);
+				i++;
+			}
+		}
+
+		RepositoryBuilder(*repository, BString("repository") << repositoryIndex)
+			.AddPackagesDirectory(directoryPath)
+			.AddToSolver(solver);
+	}
+
+	// add a repository with only the specified package
+	BSolverRepository dummyRepository;
+	RepositoryBuilder(dummyRepository, "dummy", "specified package")
+		.AddPackage(packagePath)
+		.AddToSolver(solver);
+	BSolverPackage* package = dummyRepository.PackageAt(0);
+
+	// resolve
+	BSolverPackageSpecifierList packagesToInstall;
+	if (!packagesToInstall.AppendSpecifier(
+			BSolverPackageSpecifier(&dummyRepository,
+				BPackageResolvableExpression(package->Info().Name())))) {
+		DIE(B_NO_MEMORY, "failed to add specified package");
+	}
+
+	error = solver->Install(packagesToInstall);
+	if (error != B_OK)
+		DIE(error, "failed to resolve package dependencies");
+
+	if (solver->HasProblems()) {
+		fprintf(stderr,
+			"Encountered problems resolving package dependencies:\n");
+
+		int32 problemCount = solver->CountProblems();
+		for (int32 i = 0; i < problemCount; i++) {
+			printf("  %" B_PRId32 ": %s\n", i + 1,
+				solver->ProblemAt(i)->ToString().String());
+		}
+		exit(1);
+	}
+
+	BSolverResult result;
+	error = solver->GetResult(result);
+	if (error != B_OK)
+		DIE(error, "failed to resolve package dependencies");
+
+	// print packages
+	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
+			i++) {
+// TODO: Print the path to the package/package info!
+		printf("%s-%s\n",
+			element->Package()->Info().Name().String(),
+			element->Package()->Info().Version().ToString().String());
+// TODO: Filter out the given package!
+	}
+
+	return 0;
+}
diff --git a/src/bin/pkgman/pkgman.cpp b/src/bin/pkgman/pkgman.cpp
index bfa50d11a1..6942008f4b 100644
--- a/src/bin/pkgman/pkgman.cpp
+++ b/src/bin/pkgman/pkgman.cpp
@@ -33,9 +33,8 @@ static const char* kUsage =
 	"  refresh [ ...]\n"
 	"    Refreshes all or just the given repositories.\n"
 	"\n"
-	"  resolve-build-dependencies  \n"
-	"       [  ... ]\n"
-	"    Resolves all packages needed for building a package.\n"
+	"  resolve-dependencies   [  ] ...\n"
+	"    Resolves all packages a given package depends on.\n"
 	"\n"
 	"Common Options:\n"
 	"  -h, --help   - Print this usage info.\n"
@@ -60,9 +59,6 @@ main(int argc, const char* const* argv)
 	if (strncmp(command, "add-r", 5) == 0)
 		return command_add_repo(argc - 1, argv + 1);
 
-	if (strcmp(command, "list-build-dependency-packages") == 0)
-		return command_resolve_build_dependencies(argc - 1, argv + 1);
-
 	if (strncmp(command, "drop-r", 6) == 0)
 		return command_drop_repo(argc - 1, argv + 1);
 
@@ -72,6 +68,9 @@ main(int argc, const char* const* argv)
 	if (strncmp(command, "refr", 4) == 0)
 		return command_refresh(argc - 1, argv + 1);
 
+	if (strcmp(command, "resolve-dependencies") == 0)
+		return command_resolve_dependencies(argc - 1, argv + 1);
+
 //	if (strcmp(command, "search") == 0)
 //		return command_search(argc - 1, argv + 1);
 
diff --git a/src/bin/pkgman/pkgman.h b/src/bin/pkgman/pkgman.h
index 088cd23271..9808903fd3 100644
--- a/src/bin/pkgman/pkgman.h
+++ b/src/bin/pkgman/pkgman.h
@@ -35,7 +35,7 @@ do {																\
 
 void	print_usage_and_exit(bool error);
 int		command_add_repo(int argc, const char* const* argv);
-int		command_resolve_build_dependencies(int argc, const char* const* argv);
+int		command_resolve_dependencies(int argc, const char* const* argv);  
 int		command_drop_repo(int argc, const char* const* argv);
 int		command_list_repos(int argc, const char* const* argv);
 int		command_refresh(int argc, const char* const* argv);

From 65502bbe88c4686bdefbc5d646b9b681e1c49743 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 18:42:20 +0200
Subject: [PATCH 0341/1170] BSolver: Add VerifyInstallation()

... and implement it in LibsolvSolver.
---
 headers/os/package/solver/Solver.h        |  1 +
 src/kits/package/solver/LibsolvSolver.cpp | 83 +++++++++++++++++------
 src/kits/package/solver/LibsolvSolver.h   |  4 ++
 3 files changed, 66 insertions(+), 22 deletions(-)

diff --git a/headers/os/package/solver/Solver.h b/headers/os/package/solver/Solver.h
index 97cee58a15..2f1160b871 100644
--- a/headers/os/package/solver/Solver.h
+++ b/headers/os/package/solver/Solver.h
@@ -32,6 +32,7 @@ public:
 	virtual	status_t			Install(
 									const BSolverPackageSpecifierList&
 										packages) = 0;
+	virtual	status_t			VerifyInstallation() = 0;
 
 			bool				HasProblems() const
 									{ return CountProblems() > 0; }
diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index 19aa15b3b4..c12e8456f6 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -220,32 +220,35 @@ LibsolvSolver::Install(const BSolverPackageSpecifierList& packages)
 			queue_push(&jobs, matchingPackages.elements[j]);
 	}
 
-	// add solver mode to job queue elements
-	int solverMode = SOLVER_INSTALL;
-	for (int i = 0; i < jobs.count; i += 2) {
-		jobs.elements[i] |= solverMode;
-//		if (cleandeps)
-//			jobs.elements[i] |= SOLVER_CLEANDEPS;
-//		if (forcebest)
-//			jobs.elements[i] |= SOLVER_FORCEBEST;
-	}
+	// set jobs' solver mode and solve
+	_SetJobsSolverMode(jobs, SOLVER_INSTALL);
 
-	// create the solver and solve
-	fSolver = solver_create(fPool);
-	solver_set_flag(fSolver, SOLVER_FLAG_SPLITPROVIDES, 1);
-	solver_set_flag(fSolver, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
+	return _Solve(jobs);
+}
 
-	// get the problems (if any)
-	fProblems.MakeEmpty();
 
-	int problemCount = solver_solve(fSolver, &jobs);
-	for (Id problemId = 1; problemId <= problemCount; problemId++) {
-		error = _AddProblem(problemId);
-		if (error != B_OK)
-			return error;
-	}
+status_t
+LibsolvSolver::VerifyInstallation()
+{
+	if (fInstalledRepository == NULL)
+		return B_BAD_VALUE;
 
-	return B_OK;
+	// add repositories to pool
+	status_t error = _AddRepositories();
+	if (error != B_OK)
+		return error;
+
+	// prepare pool for solving
+	pool_createwhatprovides(fPool);
+
+	// add the verify job to the job queue
+	SolvQueue jobs;
+	queue_push2(&jobs, SOLVER_SOLVABLE_ALL, 0);
+
+	// set jobs' solver mode and solve
+	_SetJobsSolverMode(jobs, SOLVER_VERIFY);
+
+	return _Solve(jobs);
 }
 
 
@@ -617,3 +620,39 @@ LibsolvSolver::_GetResolvableExpression(Id id,
 	_expression.SetTo(name, op, version);
 	return B_OK;
 }
+
+
+status_t
+LibsolvSolver::_Solve(Queue& jobs)
+{
+	// create the solver and solve
+	fSolver = solver_create(fPool);
+	solver_set_flag(fSolver, SOLVER_FLAG_SPLITPROVIDES, 1);
+	solver_set_flag(fSolver, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
+
+	int problemCount = solver_solve(fSolver, &jobs);
+
+	// get the problems (if any)
+	fProblems.MakeEmpty();
+
+	for (Id problemId = 1; problemId <= problemCount; problemId++) {
+		status_t error = _AddProblem(problemId);
+		if (error != B_OK)
+			return error;
+	}
+
+	return B_OK;
+}
+
+
+void
+LibsolvSolver::_SetJobsSolverMode(Queue& jobs, int solverMode)
+{
+	for (int i = 0; i < jobs.count; i += 2) {
+		jobs.elements[i] |= solverMode;
+//		if (cleandeps)
+//			jobs.elements[i] |= SOLVER_CLEANDEPS;
+//		if (forcebest)
+//			jobs.elements[i] |= SOLVER_FORCEBEST;
+	}
+}
diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h
index 1f4c30198e..e31eeadca2 100644
--- a/src/kits/package/solver/LibsolvSolver.h
+++ b/src/kits/package/solver/LibsolvSolver.h
@@ -36,6 +36,7 @@ public:
 	virtual	status_t			Install(
 									const BSolverPackageSpecifierList&
 										packages);
+	virtual	status_t			VerifyInstallation();
 
 	virtual	int32				CountProblems() const;
 	virtual	BSolverProblem*		ProblemAt(int32 index) const;
@@ -64,6 +65,9 @@ private:
 									BPackageResolvableExpression& _expression)
 									const;
 
+			status_t			_Solve(Queue& jobs);
+			void				_SetJobsSolverMode(Queue& jobs, int solverMode);
+
 private:
 			Pool*				fPool;
 			Solver*				fSolver;

From 749884283a72b650748d830648d31eea78b6b7d3 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 18:44:14 +0200
Subject: [PATCH 0342/1170] pkgman resolve-dependencies: Verify result

* Make sure that the computed dependencies don't themselves depend on
  the specified package.
* Print only the actual dependencies, not the specified package.
---
 .../pkgman/command_resolve_dependencies.cpp   | 60 +++++++++++++++++--
 1 file changed, 55 insertions(+), 5 deletions(-)

diff --git a/src/bin/pkgman/command_resolve_dependencies.cpp b/src/bin/pkgman/command_resolve_dependencies.cpp
index 42f9a801c9..6542d3ce30 100644
--- a/src/bin/pkgman/command_resolve_dependencies.cpp
+++ b/src/bin/pkgman/command_resolve_dependencies.cpp
@@ -196,6 +196,47 @@ private:
 };
 
 
+static void
+verify_result(const BSolverResult& result, BSolverPackage* specifiedPackage)
+{
+	// create the solver
+	BSolver* solver;
+	status_t error = BSolver::Create(solver);
+	if (error != B_OK)
+		DIE(error, "failed to create solver");
+
+	// Add an installation repository and add all of the result packages save
+	// the specified package.
+	BSolverRepository installation;
+	RepositoryBuilder installationBuilder(installation, "installation");
+
+	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
+			i++) {
+		BSolverPackage* package = element->Package();
+		if (package != specifiedPackage)
+			installationBuilder.AddPackage(package->Info());
+	}
+	installationBuilder.AddToSolver(solver, true);
+
+	// resolve
+	error = solver->VerifyInstallation();
+	if (error != B_OK)
+		DIE(error, "failed to verify computed package dependencies");
+
+	if (solver->HasProblems()) {
+		fprintf(stderr,
+			"Encountered problems verifying computed package dependencies:\n");
+
+		int32 problemCount = solver->CountProblems();
+		for (int32 i = 0; i < problemCount; i++) {
+			printf("  %" B_PRId32 ": %s\n", i + 1,
+				solver->ProblemAt(i)->ToString().String());
+		}
+		exit(1);
+	}
+}
+
+
 int
 command_resolve_dependencies(int argc, const char* const* argv)
 {
@@ -266,13 +307,14 @@ command_resolve_dependencies(int argc, const char* const* argv)
 	RepositoryBuilder(dummyRepository, "dummy", "specified package")
 		.AddPackage(packagePath)
 		.AddToSolver(solver);
-	BSolverPackage* package = dummyRepository.PackageAt(0);
+	BSolverPackage* specifiedPackage = dummyRepository.PackageAt(0);
 
 	// resolve
 	BSolverPackageSpecifierList packagesToInstall;
 	if (!packagesToInstall.AppendSpecifier(
 			BSolverPackageSpecifier(&dummyRepository,
-				BPackageResolvableExpression(package->Info().Name())))) {
+				BPackageResolvableExpression(
+					specifiedPackage->Info().Name())))) {
 		DIE(B_NO_MEMORY, "failed to add specified package");
 	}
 
@@ -297,14 +339,22 @@ command_resolve_dependencies(int argc, const char* const* argv)
 	if (error != B_OK)
 		DIE(error, "failed to resolve package dependencies");
 
+	// Verify that the resolved packages don't depend on the specified package.
+	verify_result(result, specifiedPackage);
+
 	// print packages
 	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
 			i++) {
+		BSolverPackage* package = element->Package();
+
 // TODO: Print the path to the package/package info!
+		// skip the specified package
+		if (package == specifiedPackage)
+			continue;
+
 		printf("%s-%s\n",
-			element->Package()->Info().Name().String(),
-			element->Package()->Info().Version().ToString().String());
-// TODO: Filter out the given package!
+			package->Info().Name().String(),
+			package->Info().Version().ToString().String());
 	}
 
 	return 0;

From a8b832bf461cc0a4325302d929067c19f4e7aedf Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 19:06:47 +0200
Subject: [PATCH 0343/1170] BSolverRepository::AddPackage(): Add optional
 return parameter

... returning the added BSolverPackage object.
---
 headers/os/package/solver/SolverRepository.h | 3 ++-
 src/kits/package/solver/SolverRepository.cpp | 6 +++++-
 2 files changed, 7 insertions(+), 2 deletions(-)

diff --git a/headers/os/package/solver/SolverRepository.h b/headers/os/package/solver/SolverRepository.h
index afca10b445..24dc961784 100644
--- a/headers/os/package/solver/SolverRepository.h
+++ b/headers/os/package/solver/SolverRepository.h
@@ -58,7 +58,8 @@ public:
 			int32				CountPackages() const;
 			BSolverPackage*		PackageAt(int32 index) const;
 
-			status_t			AddPackage(const BPackageInfo& info);
+			status_t			AddPackage(const BPackageInfo& info,
+									BSolverPackage** _package = NULL);
 			status_t			AddPackages(
 									BPackageInstallationLocation location);
 
diff --git a/src/kits/package/solver/SolverRepository.cpp b/src/kits/package/solver/SolverRepository.cpp
index f10360bea8..b78cb6d415 100644
--- a/src/kits/package/solver/SolverRepository.cpp
+++ b/src/kits/package/solver/SolverRepository.cpp
@@ -238,7 +238,8 @@ BSolverRepository::PackageAt(int32 index) const
 
 
 status_t
-BSolverRepository::AddPackage(const BPackageInfo& info)
+BSolverRepository::AddPackage(const BPackageInfo& info,
+	BSolverPackage** _package = NULL)
 {
 	BSolverPackage* package = new(std::nothrow) BSolverPackage(this, info);
 	if (package == NULL || !fPackages.AddItem(package)) {
@@ -246,6 +247,9 @@ BSolverRepository::AddPackage(const BPackageInfo& info)
 		return B_NO_MEMORY;
 	}
 
+	if (_package != NULL)
+		*_package = package;
+
 	return B_OK;
 }
 

From 4b8aabfac92bcc9be71cf861df8ec83e1a84d944 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 19:09:38 +0200
Subject: [PATCH 0344/1170] pkgman resolve-dependencies: Print package paths

... instead of package name and version. The command should now
work as required by haikuporter.
---
 .../pkgman/command_resolve_dependencies.cpp   | 57 ++++++++++++++-----
 1 file changed, 44 insertions(+), 13 deletions(-)

diff --git a/src/bin/pkgman/command_resolve_dependencies.cpp b/src/bin/pkgman/command_resolve_dependencies.cpp
index 6542d3ce30..06d8aa309a 100644
--- a/src/bin/pkgman/command_resolve_dependencies.cpp
+++ b/src/bin/pkgman/command_resolve_dependencies.cpp
@@ -14,6 +14,8 @@
 #include 
 #include 
 
+#include 
+
 #include 
 #include 
 #include 
@@ -32,10 +34,13 @@
 #include "pkgman.h"
 
 
+// TODO: internationalization!
+
+
 using namespace BPackageKit;
 
 
-// TODO: internationalization!
+typedef std::map PackagePathMap;
 
 
 static const char* kCommandUsage =
@@ -88,17 +93,24 @@ struct RepositoryBuilder {
 		const BString& errorName = BString())
 		:
 		fRepository(repository),
-		fErrorName(errorName.IsEmpty() ? name : errorName)
+		fErrorName(errorName.IsEmpty() ? name : errorName),
+		fPackagePaths(NULL)
 	{
 		status_t error = fRepository.SetTo(name);
 		if (error != B_OK)
 			DIE(error, "failed to init %s repository", fErrorName.String());
 	}
 
-	RepositoryBuilder& AddPackage(const BPackageInfo& info,
-		const char* packageErrorName = NULL)
+	RepositoryBuilder& SetPackagePathMap(PackagePathMap* packagePaths)
 	{
-		status_t error = fRepository.AddPackage(info);
+		fPackagePaths = packagePaths;
+		return *this;
+	}
+
+	RepositoryBuilder& AddPackage(const BPackageInfo& info,
+		const char* packageErrorName = NULL, BSolverPackage** _package = NULL)
+	{
+		status_t error = fRepository.AddPackage(info, _package);
 		if (error != B_OK) {
 			DIE(error, "failed to add %s to %s repository",
 				packageErrorName != NULL
@@ -109,7 +121,8 @@ struct RepositoryBuilder {
 		return *this;
 	}
 
-	RepositoryBuilder& AddPackage(const char* path)
+	RepositoryBuilder& AddPackage(const char* path,
+		BSolverPackage** _package = NULL)
 	{
 		// read a package info from the (HPKG or package info) file
 		BPackageInfo packageInfo;
@@ -130,7 +143,18 @@ struct RepositoryBuilder {
 		if (error != B_OK)
 			DIE(errno, "failed to read package info from \"%s\"", path);
 
-		return AddPackage(packageInfo, path);
+		// add the package
+		BSolverPackage* package;
+		AddPackage(packageInfo, path, &package);
+
+		// enter the package path in the path map, if given
+		if (fPackagePaths != NULL)
+			(*fPackagePaths)[package] = path;
+
+		if (_package != NULL)
+			*_package = package;
+
+		return *this;
 	}
 
 	RepositoryBuilder& AddPackages(BPackageInstallationLocation location,
@@ -193,6 +217,7 @@ struct RepositoryBuilder {
 private:
 	BSolverRepository&	fRepository;
 	BString				fErrorName;
+	PackagePathMap*		fPackagePaths;
 };
 
 
@@ -278,6 +303,7 @@ command_resolve_dependencies(int argc, const char* const* argv)
 		DIE(error, "failed to create solver");
 
 	// add repositories
+	PackagePathMap packagePaths;
 	BObjectList repositories(10, true);
 	int32 repositoryIndex = 0;
 	for (int i = 0; i < repositoryDirectoryCount; i++, repositoryIndex++) {
@@ -298,6 +324,7 @@ command_resolve_dependencies(int argc, const char* const* argv)
 		}
 
 		RepositoryBuilder(*repository, BString("repository") << repositoryIndex)
+			.SetPackagePathMap(&packagePaths)
 			.AddPackagesDirectory(directoryPath)
 			.AddToSolver(solver);
 	}
@@ -345,16 +372,20 @@ command_resolve_dependencies(int argc, const char* const* argv)
 	// print packages
 	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
 			i++) {
-		BSolverPackage* package = element->Package();
-
-// TODO: Print the path to the package/package info!
 		// skip the specified package
+		BSolverPackage* package = element->Package();
 		if (package == specifiedPackage)
 			continue;
 
-		printf("%s-%s\n",
-			package->Info().Name().String(),
-			package->Info().Version().ToString().String());
+		// resolve and print the path
+		PackagePathMap::const_iterator it = packagePaths.find(package);
+		if (it == packagePaths.end()) {
+			DIE(B_ERROR, "ugh, no package %p (%s-%s) not in package path map",
+				package,  package->Info().Name().String(),
+				package->Info().Version().ToString().String());
+		}
+
+		printf("%s\n", it->second.String());
 	}
 
 	return 0;

From 046f1c437811594ba60a462b9d4e423f7fac5528 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 20:11:11 +0200
Subject: [PATCH 0345/1170] pkgman resolve-dependencies: Avoid code duplication

---
 .../pkgman/command_resolve_dependencies.cpp   | 41 +++++++++----------
 1 file changed, 19 insertions(+), 22 deletions(-)

diff --git a/src/bin/pkgman/command_resolve_dependencies.cpp b/src/bin/pkgman/command_resolve_dependencies.cpp
index 06d8aa309a..44d8854e1c 100644
--- a/src/bin/pkgman/command_resolve_dependencies.cpp
+++ b/src/bin/pkgman/command_resolve_dependencies.cpp
@@ -221,6 +221,23 @@ private:
 };
 
 
+static void
+check_problems(BSolver* solver, const char* errorContext)
+{
+	if (solver->HasProblems()) {
+		fprintf(stderr,
+			"Encountered problems %s:\n", errorContext);
+
+		int32 problemCount = solver->CountProblems();
+		for (int32 i = 0; i < problemCount; i++) {
+			printf("  %" B_PRId32 ": %s\n", i + 1,
+				solver->ProblemAt(i)->ToString().String());
+		}
+		exit(1);
+	}
+}
+
+
 static void
 verify_result(const BSolverResult& result, BSolverPackage* specifiedPackage)
 {
@@ -248,17 +265,7 @@ verify_result(const BSolverResult& result, BSolverPackage* specifiedPackage)
 	if (error != B_OK)
 		DIE(error, "failed to verify computed package dependencies");
 
-	if (solver->HasProblems()) {
-		fprintf(stderr,
-			"Encountered problems verifying computed package dependencies:\n");
-
-		int32 problemCount = solver->CountProblems();
-		for (int32 i = 0; i < problemCount; i++) {
-			printf("  %" B_PRId32 ": %s\n", i + 1,
-				solver->ProblemAt(i)->ToString().String());
-		}
-		exit(1);
-	}
+	check_problems(solver, "verifying computed package dependencies");
 }
 
 
@@ -349,17 +356,7 @@ command_resolve_dependencies(int argc, const char* const* argv)
 	if (error != B_OK)
 		DIE(error, "failed to resolve package dependencies");
 
-	if (solver->HasProblems()) {
-		fprintf(stderr,
-			"Encountered problems resolving package dependencies:\n");
-
-		int32 problemCount = solver->CountProblems();
-		for (int32 i = 0; i < problemCount; i++) {
-			printf("  %" B_PRId32 ": %s\n", i + 1,
-				solver->ProblemAt(i)->ToString().String());
-		}
-		exit(1);
-	}
+	check_problems(solver, "resolving package dependencies");
 
 	BSolverResult result;
 	error = solver->GetResult(result);

From 7216c8944d01a0800e11a2e9f8d04ef307957f91 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 20:14:54 +0200
Subject: [PATCH 0346/1170] pkgman resolve-dependencies: Improve usage text
 formatting

---
 .../pkgman/command_resolve_dependencies.cpp   | 20 ++++++++++---------
 1 file changed, 11 insertions(+), 9 deletions(-)

diff --git a/src/bin/pkgman/command_resolve_dependencies.cpp b/src/bin/pkgman/command_resolve_dependencies.cpp
index 44d8854e1c..d71aed657f 100644
--- a/src/bin/pkgman/command_resolve_dependencies.cpp
+++ b/src/bin/pkgman/command_resolve_dependencies.cpp
@@ -48,15 +48,17 @@ static const char* kCommandUsage =
 	"Resolves and lists all packages a given package depends on. Fails, if\n"
 	"not all dependencies could be resolved.\n"
 	"\n"
-	"\n"
-	"  The HPKG or package info file of the package for which the\n"
-	"  dependencies shall be resolved.\n"
-	"\n"
-	"  Path to a directory containing packages from which the package's\n"
-	"  dependencies shall be resolved. Multiple directories can be specified.\n"
-	"\n"
-	"  Can follow a  to specify the priority of that repository.\n"
-	"  The default priority is 0.\n"
+	"Arguments:\n"
+	"  \n"
+	"    The HPKG or package info file of the package for which the\n"
+	"    dependencies shall be resolved.\n"
+	"  \n"
+	"    Path to a directory containing packages from which the package's\n"
+	"    dependencies shall be resolved. Multiple directories can be\n"
+	"    specified.\n"
+	"  \n"
+	"    Can follow a  to specify the priority of that\n"
+	"    repository. The default priority is 0.\n"
 	"\n"
 ;
 

From 1add554a832a5fdd2bb26692115fd116afecf60c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 3 Apr 2013 21:04:55 +0200
Subject: [PATCH 0347/1170] Make LibSolv a mandatory package

... so it is actually installed on the image.
---
 build/jam/OptionalBuildFeatures       |  2 +-
 build/jam/OptionalPackageDependencies |  2 +-
 build/jam/OptionalPackages            | 13 +++++++++++++
 3 files changed, 15 insertions(+), 2 deletions(-)

diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures
index ee549b0d31..50ac91e77e 100644
--- a/build/jam/OptionalBuildFeatures
+++ b/build/jam/OptionalBuildFeatures
@@ -215,7 +215,7 @@ if $(HAIKU_BUILD_FEATURE_TAGLIB) {
 }
 
 
-# libsolv
+# LibSolv
 
 if $(TARGET_ARCH) != x86 {
 	Echo "Libsolv not available for $(TARGET_ARCH)." ;
diff --git a/build/jam/OptionalPackageDependencies b/build/jam/OptionalPackageDependencies
index 6604f39430..7a721eb5c2 100644
--- a/build/jam/OptionalPackageDependencies
+++ b/build/jam/OptionalPackageDependencies
@@ -36,4 +36,4 @@ OptionalPackageDependencies WebPositive : Curl LibXML2 SQLite ;
 OptionalPackageDependencies wpa_supplicant : OpenSSL ;
 OptionalPackageDependencies XZ-Utils : Tar ;
 
-OptionalPackageDependencies MandatoryPackages : ICU Sed Tar ;
+OptionalPackageDependencies MandatoryPackages : ICU LibSolv Sed Tar ;
diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 7865db5ad0..ee2c9abe4b 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -44,6 +44,7 @@
 #	LibIconv				- text encoding conversion library
 #	LibLayout				- GCC2 package needed by some BeOS apps to compile
 #	Libmng					- mng support library
+#	LibSolv					- package dependency solver library
 #	LibXML2					- the XML support library
 #	LibXSLT					- xslt library and utility
 #	Links					- the web browser
@@ -918,6 +919,18 @@ if [ IsOptionalHaikuImagePackageAdded Libmng ] {
 }
 
 
+# LibSolv
+if [ IsOptionalHaikuImagePackageAdded LibSolv ] {
+	if ! $(HAIKU_LIBSOLV_PACKAGE) {
+		Echo "No optional package LibSolv available for $(TARGET_ARCH)" ;
+	} else {
+		InstallOptionalHaikuImagePackage $(HAIKU_LIBSOLV_PACKAGE)
+			: $(hpkgBaseURL)/$(HAIKU_LIBSOLV_PACKAGE)
+			: system packages ;
+	}
+}
+
+
 # LibXML2
 if [ IsOptionalHaikuImagePackageAdded LibXML2 ] {
 	if $(TARGET_ARCH) != x86 {

From 6d04dfb7a999afa6da39dcfd4aeac6dc22e5311f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 4 Apr 2013 11:24:39 +0200
Subject: [PATCH 0348/1170] bindfs: Fix double deletion of root node on unmount

The VFS calls the FS's put_vnode() for all nodes, including the root
node, prior to calling unmount().
---
 src/add-ons/kernel/file_systems/bindfs/Volume.cpp | 1 -
 1 file changed, 1 deletion(-)

diff --git a/src/add-ons/kernel/file_systems/bindfs/Volume.cpp b/src/add-ons/kernel/file_systems/bindfs/Volume.cpp
index ec4f52db15..2c5013e92c 100644
--- a/src/add-ons/kernel/file_systems/bindfs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/bindfs/Volume.cpp
@@ -40,7 +40,6 @@ Volume::Volume(fs_volume* fsVolume)
 
 Volume::~Volume()
 {
-	delete fRootNode;
 }
 
 

From ce1d0481833eaa6aa22e1006e92602db3ed33f97 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 4 Apr 2013 22:25:23 +0200
Subject: [PATCH 0349/1170] packagefs: Fix adding package links twice to volume

PackageLinkDirectory::NotifyDirectoryAdded() first notified the listener
(Volume) about the directory itself, then about the links it contained.
Since Volume adds the nodes recursively, the latter were added twice,
resulting in a corrupted ID hash table.
---
 .../packagefs/PackageLinkDirectory.cpp        | 20 -------------------
 .../packagefs/PackageLinkDirectory.h          |  3 ---
 .../packagefs/PackageLinksDirectory.cpp       |  6 ++++--
 3 files changed, 4 insertions(+), 25 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
index ce14ceb957..48a11f54ac 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
@@ -149,26 +149,6 @@ PackageLinkDirectory::UpdatePackageDependencies(Package* package,
 }
 
 
-void
-PackageLinkDirectory::NotifyDirectoryAdded(PackageLinksListener* listener)
-{
-	NodeWriteLocker writeLocker(this);
-
-	listener->PackageLinkNodeAdded(this);
-
-	if (fSelfLink != NULL) {
-		NodeWriteLocker selfLinkLocker(fSelfLink);
-		listener->PackageLinkNodeAdded(fSelfLink);
-	}
-
-	for (FamilyDependencyList::Iterator it = fDependencyLinks.GetIterator();
-			DependencyLink* link = it.Next();) {
-		NodeWriteLocker linkLocker(link);
-		listener->PackageLinkNodeAdded(link);
-	}
-}
-
-
 status_t
 PackageLinkDirectory::_Update(PackageLinksListener* listener)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h
index c5adc7ff3d..798592c243 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h
@@ -32,9 +32,6 @@ public:
 			void				UpdatePackageDependencies(Package* package,
 									PackageLinksListener* listener);
 
-			void				NotifyDirectoryAdded(
-									PackageLinksListener* listener);
-
 			bool				IsEmpty() const
 									{ return fPackages.IsEmpty(); }
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp
index bbe09e9610..b283dc6af8 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinksDirectory.cpp
@@ -70,8 +70,10 @@ PackageLinksDirectory::AddPackage(Package* package)
 		// No entry is in the way, so just add the link directory.
 		AddChild(linkDirectory);
 
-		if (fListener != NULL)
-			linkDirectory->NotifyDirectoryAdded(fListener);
+		if (fListener != NULL) {
+			NodeWriteLocker writeLocker(linkDirectory);
+			fListener->PackageLinkNodeAdded(linkDirectory);
+		}
 	}
 
 	return B_OK;

From dedc1369e1d745b0a678df432d6131893290cfd2 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 5 Apr 2013 00:17:22 +0200
Subject: [PATCH 0350/1170] packagefs: Acquire missing reference for the root
 dir

We need one for the ID table and one for the volume itself.
---
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index f4be297e25..e7dd574b30 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -660,6 +660,8 @@ Volume::Mount(const char* parameterString)
 		RETURN_ERROR(B_NO_MEMORY);
 	fRootDirectory->Init(NULL, volumeName, 0);
 	fNodes.Insert(fRootDirectory);
+	fRootDirectory->AcquireReference();
+		// one reference for the table
 
 	// get our mount point
 	error = vfs_get_mount_point(fFSVolume->id, &fMountPoint.deviceID,

From c7382d4c9d83304e44e8672caaf71895715efd62 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 5 Apr 2013 00:20:32 +0200
Subject: [PATCH 0351/1170] packagefs: Acquire missing reference for
 shine-through dirs

Since we publish shine-through directories directly to the VFS, we need
to acquire an additional reference, because we release a reference when
a node is put.
---
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 2 ++
 1 file changed, 2 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index e7dd574b30..f39acd1b3e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -1805,8 +1805,10 @@ Volume::_PublishShineThroughDirectories()
 		}
 
 		// publish the vnode, so the VFS will find it without asking us
+		directory->AcquireReference();
 		error = PublishVNode(directory);
 		if (error != B_OK) {
+			directory->ReleaseReference();
 			_RemoveNode(directory);
 			RETURN_ERROR(error);
 		}

From 05940bc51417d34f7cb78bd1f2253d305320c563 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 5 Apr 2013 00:31:51 +0200
Subject: [PATCH 0352/1170] packagefs: Fix handling of package-links directory
 on unmount

* Volume::_RemovePackageLinksDirectory(): We don't want to call
  _RemovePackageLinksNode(). Besides that the ID hash table has already
  been emptied before and we would thus release a reference to the node
  erroneously, the method doesn't do anything we want anyway. We don't
  want any children to be removed, since we have unregistered the
  volume's packages already (which removes the respective package link
  directories); the remaining ones are from other volumes and not ours
  to remove.
* PackageFSRoot: Release a reference to the package links directory in
  the destructor. We create the directory in Init() after all and no one
  else takes over ownership.
---
 src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp | 3 +++
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp        | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp
index 1abac70b50..a5204164ef 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp
@@ -42,6 +42,9 @@ PackageFSRoot::PackageFSRoot(dev_t deviceID, ino_t nodeID)
 
 PackageFSRoot::~PackageFSRoot()
 {
+	if (fPackageLinksDirectory != NULL)
+		fPackageLinksDirectory->ReleaseReference();
+
 	rw_lock_destroy(&fLock);
 }
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index f39acd1b3e..37a08d49b4 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -1863,7 +1863,7 @@ Volume::_RemovePackageLinksDirectory()
 
 	if (packageLinksDirectory->Parent() == fRootDirectory) {
 		packageLinksDirectory->SetListener(NULL);
-		_RemovePackageLinksNode(packageLinksDirectory);
+		fRootDirectory->RemoveChild(packageLinksDirectory);
 		packageLinksDirectory->SetParent(NULL);
 	}
 }

From ce577d8db0580112cd8dcd60a1c6110f624a3d2a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 5 Apr 2013 16:50:20 +0200
Subject: [PATCH 0353/1170] packagefs: AttributeIndex: Support duplicates
 correctly

The tree comparisons didn't allow for different Nodes having the same
attribute value. Therefore only the first node would be added and later
we would try to remove a node not actually in the tree, leading to a
crash.

packagefs seems to finally unmount cleanly, now.
---
 .../file_systems/packagefs/AttributeIndex.cpp | 19 +++++++++++++++++--
 1 file changed, 17 insertions(+), 2 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp b/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp
index e93a43424a..1f6f62a819 100644
--- a/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/AttributeIndex.cpp
@@ -89,14 +89,29 @@ struct AttributeIndex::TreeDefinition {
 
 	int Compare(const Key& a, const Value* b) const
 	{
-		return QueryParser::compareKeys(fType, a.data, a.length, b->data,
+		int cmp = QueryParser::compareKeys(fType, a.data, a.length, b->data,
 			b->length);
+		if (cmp != 0)
+			return cmp;
+
+		// The attribute value is the same. Since the tree value is the tree
+		// node itself, we must not return 0, though. We consider a node-less
+		// key always less than an actual tree node with the same attribute
+		// value.
+		return -1;
 	}
 
 	int Compare(const Value* a, const Value* b) const
 	{
-		return QueryParser::compareKeys(fType, a->data, a->length, b->data,
+		if (a == b)
+			return 0;
+
+		int cmp = QueryParser::compareKeys(fType, a->data, a->length, b->data,
 			b->length);
+		if (cmp != 0)
+			return cmp;
+
+		return a < b ? -1 : 1;
 	}
 
 private:

From d4823423996b12ff7332be5dcf97c35c295129a2 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 5 Apr 2013 16:58:50 +0200
Subject: [PATCH 0354/1170] VM: Fix vm_block_address_range() area protection

B_ALREADY_WIRED, which was erroneously passed for the area protection
parameter to map_backing_store(), has the value 7 which implies user
readable and writable. Hence the address ranges around 0xdeadbeef and
0xcccccccc could actually be read and written from anywhere.
---
 src/system/kernel/vm/vm.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/system/kernel/vm/vm.cpp b/src/system/kernel/vm/vm.cpp
index 9d22d21634..120710c517 100644
--- a/src/system/kernel/vm/vm.cpp
+++ b/src/system/kernel/vm/vm.cpp
@@ -1005,8 +1005,8 @@ vm_block_address_range(const char* name, void* address, addr_t size)
 	addressRestrictions.address = address;
 	addressRestrictions.address_specification = B_EXACT_ADDRESS;
 	status = map_backing_store(addressSpace, cache, 0, name, size,
-		B_ALREADY_WIRED, B_ALREADY_WIRED, REGION_NO_PRIVATE_MAP, 0,
-		&addressRestrictions, true, &area, NULL);
+		B_ALREADY_WIRED, 0, REGION_NO_PRIVATE_MAP, 0, &addressRestrictions,
+		true, &area, NULL);
 	if (status != B_OK) {
 		cache->ReleaseRefAndUnlock();
 		return status;

From 259046a38810367985e7e9f89b90d769eb6380ce Mon Sep 17 00:00:00 2001
From: Oliver Tappe 
Date: Fri, 5 Apr 2013 18:31:58 +0200
Subject: [PATCH 0355/1170] Fix build without xattrs being used

* need to invoke fs_fopen_attr() instead of fs_open_attr()
---
 src/build/libroot/fs_attr_generic.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/build/libroot/fs_attr_generic.cpp b/src/build/libroot/fs_attr_generic.cpp
index ee18e65bb8..d35bd7d43d 100644
--- a/src/build/libroot/fs_attr_generic.cpp
+++ b/src/build/libroot/fs_attr_generic.cpp
@@ -380,7 +380,7 @@ fs_read_attr(int fd, const char *attribute, uint32 type, off_t pos,
 	void *buffer, size_t readBytes)
 {
 	// open the attribute
-	int attrFD = fs_open_attr(fd, attribute, type, O_RDONLY);
+	int attrFD = fs_fopen_attr(fd, attribute, type, O_RDONLY);
 	if (attrFD < 0)
 		return attrFD;
 
@@ -405,7 +405,7 @@ fs_write_attr(int fd, const char *attribute, uint32 type, off_t pos,
 	const void *buffer, size_t readBytes)
 {
 	// open the attribute
-	int attrFD = fs_open_attr(fd, attribute, type,
+	int attrFD = fs_fopen_attr(fd, attribute, type,
 		O_WRONLY | O_CREAT | O_TRUNC);
 	if (attrFD < 0)
 		return attrFD;

From daf7cb41c4973f4cd5108bd90bdffc0e6a33c91b Mon Sep 17 00:00:00 2001
From: Oliver Tappe 
Date: Fri, 5 Apr 2013 18:34:28 +0200
Subject: [PATCH 0356/1170] Bring back libroot_build.a for now.

* the corresponding TODO has to be dealt with at a later stage
---
 src/build/libroot/Jamfile | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/build/libroot/Jamfile b/src/build/libroot/Jamfile
index 34f947ed00..bb5e07d6c6 100644
--- a/src/build/libroot/Jamfile
+++ b/src/build/libroot/Jamfile
@@ -81,10 +81,10 @@ BuildPlatformSharedLibrary libroot_build.so :
 ;
 
 # TODO: This doesn't work with the function remapping.
-#BuildPlatformStaticLibrary libroot_build.a :
-#	:
-#	[ FGristFiles $(librootSources:S=$(SUFOBJ)) ]
-#;
+BuildPlatformStaticLibrary libroot_build.a :
+	:
+	[ FGristFiles $(librootSources:S=$(SUFOBJ)) ]
+;
 
 USES_BE_API on [ FGristFiles function_remapper$(SUFOBJ) ] = true ;
 

From 5b6fb78c407a1c15a6793e9009857d4dedfc331d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 5 Apr 2013 18:44:12 +0200
Subject: [PATCH 0357/1170] VFS: _kern_open_dir(): Fix NULL path case

It would create an empty path buffer and pass that on to dir_open(),
which accepts NULL, but not empty paths.
---
 src/system/kernel/fs/vfs.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp
index c44fba3bb5..cf2eb6dc96 100644
--- a/src/system/kernel/fs/vfs.cpp
+++ b/src/system/kernel/fs/vfs.cpp
@@ -8069,6 +8069,9 @@ _kern_open_dir_entry_ref(dev_t device, ino_t inode, const char* name)
 int
 _kern_open_dir(int fd, const char* path)
 {
+	if (path == NULL)
+		return dir_open(fd, NULL, true);;
+
 	KPath pathBuffer(path, false, B_PATH_NAME_LENGTH + 1);
 	if (pathBuffer.InitCheck() != B_OK)
 		return B_NO_MEMORY;

From 91586bd3b651574c9f0d3010567d4bcc40f4c092 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 5 Apr 2013 18:52:09 +0200
Subject: [PATCH 0358/1170] packagefs: Fix handling of package domain paths

* The package directory path specified when mounting must be interpreted
  in the caller's I/O context. We did always interpret it in the
  kernel's I/O context, so that a relative path or a path in a chroot
  environment wouldn't work correctly. Now opening the directory is done
  in PackageDomain::Init() where we can at least guess the path's
  origin.
* We also normalize the path, though merely to get more conclusive debug
  output, since after opening the directory the path isn't used for
  anything else anymore.
* Make the "packages" mount parameter optional. If not specified, use
  the "packages" folder at our mount point.
---
 .../file_systems/packagefs/PackageDomain.cpp  | 78 +++++++++++++++----
 .../file_systems/packagefs/PackageDomain.h    |  4 +-
 .../kernel/file_systems/packagefs/Volume.cpp  | 61 +++++++--------
 3 files changed, 94 insertions(+), 49 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp
index d2f4ceaa57..d3e48d021d 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp
@@ -15,10 +15,14 @@
 
 #include 
 
+#include 
 #include 
 #include 
+#include 
+#include 
 
 #include "DebugSupport.h"
+#include "Volume.h"
 
 
 PackageDomain::PackageDomain(::Volume* volume)
@@ -55,16 +59,71 @@ PackageDomain::~PackageDomain()
 
 
 status_t
-PackageDomain::Init(const char* path)
+PackageDomain::Init(const char* path, struct stat* _st)
 {
-	fPath = strdup(path);
+	// Open the directory. We want the path be interpreted depending on from
+	// where it came (kernel or userland), but we always want a FD in the kernel
+	// I/O context. There's no VFS service method to do that for us, so we need
+	// to do that ourselves.
+	bool calledFromKernel
+		= team_get_current_team_id() == team_get_kernel_team_id();
+		// Not entirely correct, but good enough for now. The only alternative
+		// is to have that information passed in as well.
+
+	struct vnode* vnode;
+	status_t error;
+	if (path != NULL) {
+		error = vfs_get_vnode_from_path(path, calledFromKernel, &vnode);
+	} else {
+		// No path given -- use the "packages" directory at our mount point.
+		error = vfs_entry_ref_to_vnode(fVolume->MountPointDeviceID(),
+			fVolume->MountPointNodeID(), "packages", &vnode);
+	}
+	if (error != B_OK) {
+		ERROR("Failed to open package domain \"%s\"\n", strerror(error));
+		RETURN_ERROR(error);
+	}
+
+	fDirFD = vfs_open_vnode(vnode, O_RDONLY, true);
+
+	if (fDirFD < 0) {
+		ERROR("Failed to open package domain \"%s\"\n", strerror(fDirFD));
+		vfs_put_vnode(vnode);
+		RETURN_ERROR(fDirFD);
+	}
+	// Our vnode reference has been transferred to the FD.
+
+	// Is it a directory at all?
+	struct stat st;
+	if (fstat(fDirFD, &st) < 0)
+		RETURN_ERROR(errno);
+
+	fDeviceID = st.st_dev;
+	fNodeID = st.st_ino;
+
+	// get a normalized path
+	KPath normalizedPath;
+	if (normalizedPath.InitCheck() != B_OK)
+		RETURN_ERROR(normalizedPath.InitCheck());
+
+	char* normalizedPathBuffer = normalizedPath.LockBuffer();
+	error = vfs_entry_ref_to_path(fDeviceID, fNodeID, NULL,
+		normalizedPathBuffer, normalizedPath.BufferSize());
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	fPath = strdup(normalizedPathBuffer);
 	if (fPath == NULL)
 		RETURN_ERROR(B_NO_MEMORY);
 
-	status_t error = fPackages.Init();
+	// init packages hash table
+	error = fPackages.Init();
 	if (error != B_OK)
 		return error;
 
+	if (_st != NULL)
+		*_st = st;
+
 	return B_OK;
 }
 
@@ -74,19 +133,6 @@ PackageDomain::Prepare(NotificationListener* listener)
 {
 	ObjectDeleter listenerDeleter(listener);
 
-	fDirFD = open(fPath, O_RDONLY);
-	if (fDirFD < 0) {
-		ERROR("Failed to open package domain \"%s\"\n", strerror(errno));
-		return errno;
-	}
-
-	struct stat st;
-	if (fstat(fDirFD, &st) < 0)
-		RETURN_ERROR(errno);
-
-	fDeviceID = st.st_dev;
-	fNodeID = st.st_ino;
-
 	status_t error = add_node_listener(fDeviceID, fNodeID, B_WATCH_DIRECTORY,
 		*listener);
 	if (error != B_OK)
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h
index 67c0354fd0..0442547b6c 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h
@@ -13,6 +13,8 @@
 #include "Package.h"
 
 
+struct stat;
+
 class NotificationListener;
 class Volume;
 
@@ -29,7 +31,7 @@ public:
 			dev_t				DeviceID()		{ return fDeviceID; }
 			ino_t				NodeID()		{ return fNodeID; }
 
-			status_t			Init(const char* path);
+			status_t			Init(const char* path, struct stat* _st);
 			status_t			Prepare(NotificationListener* listener);
 									// takes over ownership of the listener
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 37a08d49b4..1a4f1bc7b1 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -617,8 +617,8 @@ Volume::Mount(const char* parameterString)
 	CObjectDeleter parameterHandleDeleter(parameterHandle,
 		&delete_driver_settings);
 
-	if (packages == NULL || packages[0] == '\0') {
-		FATAL("need package folder ('packages' parameter)!\n");
+	if (packages != NULL && packages[0] == '\0') {
+		FATAL("invalid package folder ('packages' parameter)!\n");
 		RETURN_ERROR(B_BAD_VALUE);
 	}
 
@@ -628,11 +628,22 @@ Volume::Mount(const char* parameterString)
 		RETURN_ERROR(error);
 	}
 
+	// get our mount point
+	error = vfs_get_mount_point(fFSVolume->id, &fMountPoint.deviceID,
+		&fMountPoint.nodeID);
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	// create initial package domain
+	PackageDomain* packageDomain = new(std::nothrow) PackageDomain(this);
+	if (packageDomain == NULL)
+		RETURN_ERROR(B_NO_MEMORY);
+	BReference packageDomainReference(packageDomain, true);
+
 	struct stat st;
-	if (stat(packages, &st) < 0) {
-		FATAL("failed to stat: \"%s\": %s\n", packages, strerror(errno));
-		RETURN_ERROR(B_ERROR);
-	}
+	error = packageDomain->Init(packages, &st);
+	if (error != B_OK)
+		RETURN_ERROR(error);
 
 	// If no volume name is given, infer it from the mount type.
 	if (volumeName == NULL) {
@@ -663,12 +674,6 @@ Volume::Mount(const char* parameterString)
 	fRootDirectory->AcquireReference();
 		// one reference for the table
 
-	// get our mount point
-	error = vfs_get_mount_point(fFSVolume->id, &fMountPoint.deviceID,
-		&fMountPoint.nodeID);
-	if (error != B_OK)
-		RETURN_ERROR(error);
-
 	// register with packagefs root
 	error = ::PackageFSRoot::RegisterVolume(this);
 	if (error != B_OK)
@@ -685,8 +690,8 @@ Volume::Mount(const char* parameterString)
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
-	// create default package domain
-	error = _AddInitialPackageDomain(packages);
+	// add initial package domain
+	error = _AddPackageDomain(packageDomain, false);
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
@@ -823,7 +828,7 @@ Volume::AddPackageDomain(const char* path)
 		RETURN_ERROR(B_NO_MEMORY);
 	BReference packageDomainReference(packageDomain, true);
 
-	status_t error = packageDomain->Init(path);
+	status_t error = packageDomain->Init(path, NULL);
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
@@ -928,25 +933,11 @@ Volume::_PushJob(Job* job)
 }
 
 
-status_t
-Volume::_AddInitialPackageDomain(const char* path)
-{
-	PackageDomain* domain = new(std::nothrow) PackageDomain(this);
-	if (domain == NULL)
-		RETURN_ERROR(B_NO_MEMORY);
-	BReference domainReference(domain, true);
-
-	status_t error = domain->Init(path);
-	if (error != B_OK)
-		RETURN_ERROR(error);
-
-	return _AddPackageDomain(domain, false);
-}
-
-
 status_t
 Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
 {
+	dprintf("packagefs: Adding package domain \"%s\"\n", domain->Path());
+
 	// create a directory listener
 	DomainDirectoryListener* listener = new(std::nothrow)
 		DomainDirectoryListener(this, domain);
@@ -962,7 +953,13 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
 	}
 
 	// iterate through the dir and create packages
-	DIR* dir = opendir(domain->Path());
+	int fd = dup(domain->DirectoryFD());
+	if (fd < 0) {
+		ERROR("Failed to dup() package domain FD: %s\n", strerror(errno));
+		RETURN_ERROR(errno);
+	}
+
+	DIR* dir = fdopendir(fd);
 	if (dir == NULL) {
 		ERROR("Failed to open package domain directory \"%s\": %s\n",
 			domain->Path(), strerror(errno));

From 0c6927b5d7c8f73abd7663168f5f437b39661c6c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 6 Apr 2013 04:26:40 +0200
Subject: [PATCH 0359/1170] packagefs: Add ioctl to get basic volume
 information

Also rename the MountType enum and members, since they are no longer
packagefs private.
---
 headers/private/package/packagefs.h           | 38 +++++++++++++++
 .../kernel/file_systems/packagefs/Jamfile     |  2 +-
 .../file_systems/packagefs/PackageFSRoot.cpp  | 12 +++--
 .../packagefs/PackageLinkSymlink.cpp          |  8 ++--
 .../kernel/file_systems/packagefs/Volume.cpp  | 48 ++++++++++++++-----
 .../kernel/file_systems/packagefs/Volume.h    | 12 ++---
 .../packagefs/kernel_interface.cpp            | 18 ++++++-
 7 files changed, 108 insertions(+), 30 deletions(-)
 create mode 100644 headers/private/package/packagefs.h

diff --git a/headers/private/package/packagefs.h b/headers/private/package/packagefs.h
new file mode 100644
index 0000000000..790ac3a1ce
--- /dev/null
+++ b/headers/private/package/packagefs.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef _PACKAGE__PRIVATE__PACKAGE_FS_H_
+#define _PACKAGE__PRIVATE__PACKAGE_FS_H_
+
+
+#include 
+
+
+enum PackageFSMountType {
+	PACKAGE_FS_MOUNT_TYPE_SYSTEM,
+	PACKAGE_FS_MOUNT_TYPE_COMMON,
+	PACKAGE_FS_MOUNT_TYPE_HOME,
+	PACKAGE_FS_MOUNT_TYPE_CUSTOM
+};
+
+
+enum {
+	PACKAGE_FS_OPERATION_GET_VOLUME_INFO	= B_DEVICE_OP_CODES_END + 1
+};
+
+
+struct PackageFSVolumeInfo {
+	PackageFSMountType	mountType;
+
+	// device and node id of the respective package FS root scope (e.g. "/boot"
+	// for the three standard volumes)
+	dev_t				rootDeviceID;
+	ino_t				rootDirectoryID;
+};
+
+
+#endif	// _PACKAGE__PRIVATE__PACKAGE_FS_H_
diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile
index d0576a0423..93964979f5 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Jamfile
+++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile
@@ -3,7 +3,7 @@ SubDir HAIKU_TOP src add-ons kernel file_systems packagefs ;
 
 UseLibraryHeaders zlib ;
 UsePrivateKernelHeaders ;
-UsePrivateHeaders shared storage ;
+UsePrivateHeaders package shared storage ;
 
 
 HAIKU_PACKAGE_FS_SOURCES =
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp
index a5204164ef..74ee53b90c 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageFSRoot.cpp
@@ -96,14 +96,14 @@ PackageFSRoot::RegisterVolume(Volume* volume)
 	const char* relativeRootPath = NULL;
 
 	switch (volume->MountType()) {
-		case MOUNT_TYPE_SYSTEM:
-		case MOUNT_TYPE_COMMON:
+		case PACKAGE_FS_MOUNT_TYPE_SYSTEM:
+		case PACKAGE_FS_MOUNT_TYPE_COMMON:
 			relativeRootPath = "..";
 			break;
-		case MOUNT_TYPE_HOME:
+		case PACKAGE_FS_MOUNT_TYPE_HOME:
 			relativeRootPath = "../..";
 			break;
-		case MOUNT_TYPE_CUSTOM:
+		case PACKAGE_FS_MOUNT_TYPE_CUSTOM:
 		default:
 			break;
 	}
@@ -217,8 +217,10 @@ PackageFSRoot::_AddVolume(Volume* volume)
 	fVolumes.Add(volume);
 		// TODO: Correct order?
 
-	if (fSystemVolume == NULL && volume->MountType() == MOUNT_TYPE_SYSTEM)
+	if (fSystemVolume == NULL && volume->MountType()
+			== PACKAGE_FS_MOUNT_TYPE_SYSTEM) {
 		fSystemVolume = volume;
+	}
 
 	return B_OK;
 }
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
index ca3e83e667..ed674e2785 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
@@ -28,13 +28,13 @@ static const char*
 link_path_for_mount_type(MountType type)
 {
 	switch (type) {
-		case MOUNT_TYPE_SYSTEM:
+		case PACKAGE_FS_MOUNT_TYPE_SYSTEM:
 			return kSystemLinkPath;
-		case MOUNT_TYPE_COMMON:
+		case PACKAGE_FS_MOUNT_TYPE_COMMON:
 			return kCommonLinkPath;
-		case MOUNT_TYPE_HOME:
+		case PACKAGE_FS_MOUNT_TYPE_HOME:
 			return kHomeLinkPath;
-		case MOUNT_TYPE_CUSTOM:
+		case PACKAGE_FS_MOUNT_TYPE_CUSTOM:
 		default:
 			return "?";
 	}
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 1a4f1bc7b1..6d89b4e04d 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -648,16 +648,16 @@ Volume::Mount(const char* parameterString)
 	// If no volume name is given, infer it from the mount type.
 	if (volumeName == NULL) {
 		switch (fMountType) {
-			case MOUNT_TYPE_SYSTEM:
+			case PACKAGE_FS_MOUNT_TYPE_SYSTEM:
 				volumeName = "system";
 				break;
-			case MOUNT_TYPE_COMMON:
+			case PACKAGE_FS_MOUNT_TYPE_COMMON:
 				volumeName = "common";
 				break;
-			case MOUNT_TYPE_HOME:
+			case PACKAGE_FS_MOUNT_TYPE_HOME:
 				volumeName = "home";
 				break;
-			case MOUNT_TYPE_CUSTOM:
+			case PACKAGE_FS_MOUNT_TYPE_CUSTOM:
 			default:
 				volumeName = "Package FS";
 				break;
@@ -728,6 +728,28 @@ Volume::Unmount()
 }
 
 
+status_t
+Volume::IOCtl(Node* node, uint32 operation, void* buffer, size_t size)
+{
+	switch (operation) {
+		case PACKAGE_FS_OPERATION_GET_VOLUME_INFO:
+		{
+			if (size != sizeof(PackageFSVolumeInfo))
+				return B_BAD_VALUE;
+
+			PackageFSVolumeInfo info;
+			info.mountType = fMountType;
+			info.rootDeviceID = fPackageFSRoot->DeviceID();
+			info.rootDirectoryID = fPackageFSRoot->NodeID();
+			return user_memcpy(buffer, &info, sizeof(info));
+		}
+
+		default:
+			return B_BAD_VALUE;
+	}
+}
+
+
 void
 Volume::AddNodeListener(NodeListener* listener, Node* node)
 {
@@ -1664,15 +1686,15 @@ status_t
 Volume::_InitMountType(const char* mountType)
 {
 	if (mountType == NULL)
-		fMountType = MOUNT_TYPE_CUSTOM;
+		fMountType = PACKAGE_FS_MOUNT_TYPE_CUSTOM;
 	else if (strcmp(mountType, "system") == 0)
-		fMountType = MOUNT_TYPE_SYSTEM;
+		fMountType = PACKAGE_FS_MOUNT_TYPE_SYSTEM;
 	else if (strcmp(mountType, "common") == 0)
-		fMountType = MOUNT_TYPE_COMMON;
+		fMountType = PACKAGE_FS_MOUNT_TYPE_COMMON;
 	else if (strcmp(mountType, "home") == 0)
-		fMountType = MOUNT_TYPE_HOME;
+		fMountType = PACKAGE_FS_MOUNT_TYPE_HOME;
 	else if (strcmp(mountType, "custom") == 0)
-		fMountType = MOUNT_TYPE_CUSTOM;
+		fMountType = PACKAGE_FS_MOUNT_TYPE_CUSTOM;
 	else
 		RETURN_ERROR(B_BAD_VALUE);
 
@@ -1714,16 +1736,16 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting)
 	if (shineThroughSetting == NULL) {
 		// nothing specified -- derive from mount type
 		switch (fMountType) {
-			case MOUNT_TYPE_SYSTEM:
+			case PACKAGE_FS_MOUNT_TYPE_SYSTEM:
 				directories = kSystemShineThroughDirectories;
 				break;
-			case MOUNT_TYPE_COMMON:
+			case PACKAGE_FS_MOUNT_TYPE_COMMON:
 				directories = kCommonShineThroughDirectories;
 				break;
-			case MOUNT_TYPE_HOME:
+			case PACKAGE_FS_MOUNT_TYPE_HOME:
 				directories = kHomeShineThroughDirectories;
 				break;
-			case MOUNT_TYPE_CUSTOM:
+			case PACKAGE_FS_MOUNT_TYPE_CUSTOM:
 				return B_OK;
 		}
 	} else if (strcmp(shineThroughSetting, "system") == 0)
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index d2356180ac..38a6097978 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -14,6 +14,8 @@
 #include 
 #include 
 
+#include 
+
 #include "Index.h"
 #include "Node.h"
 #include "NodeListener.h"
@@ -29,12 +31,7 @@ class UnpackingNode;
 typedef IndexHashTable::Iterator IndexDirIterator;
 
 
-enum MountType {
-	MOUNT_TYPE_SYSTEM,
-	MOUNT_TYPE_COMMON,
-	MOUNT_TYPE_HOME,
-	MOUNT_TYPE_CUSTOM
-};
+typedef PackageFSMountType MountType;
 
 
 class Volume : public DoublyLinkedListLinkImpl,
@@ -70,6 +67,9 @@ public:
 			Node*				FindNode(ino_t nodeID) const
 									{ return fNodes.Lookup(nodeID); }
 
+			status_t			IOCtl(Node* node, uint32 operation,
+									void* buffer, size_t size);
+
 			// node listeners -- volume must be write-locked
 			void				AddNodeListener(NodeListener* listener,
 									Node* node);
diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
index 35f5a24f9d..2e330d0976 100644
--- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
@@ -284,6 +284,22 @@ packagefs_io(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
 // #pragma mark - Nodes
 
 
+status_t
+packagefs_ioctl(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
+	uint32 operation, void* buffer, size_t size)
+{
+	Volume* volume = (Volume*)fsVolume->private_volume;
+	Node* node = (Node*)fsNode->private_node;
+
+	FUNCTION("volume: %p, node: %p (%lld), cookie: %p, operation: %" B_PRI32u
+		", buffer: %p, size: %zu\n", volume, node, node->ID(), cookie,
+		operation, buffer, size);
+	TOUCH(cookie);
+
+	return volume->IOCtl(node, operation, buffer, size);
+}
+
+
 static status_t
 packagefs_read_symlink(fs_volume* fsVolume, fs_vnode* fsNode, char* buffer,
 	size_t* _bufferSize)
@@ -1179,7 +1195,7 @@ fs_vnode_ops gPackageFSVnodeOps = {
 
 	NULL,	// get_file_map,
 
-	NULL,	// ioctl,
+	&packagefs_ioctl,
 	NULL,	// set_flags,
 	NULL,	// select,
 	NULL,	// deselect,

From 26296b0aa4ddcc1b8baf1e6c380d0f8634730068 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 6 Apr 2013 04:29:34 +0200
Subject: [PATCH 0360/1170] Add the humble beginnings of the package daemon

It doesn't really do anything yet save for tracking what packagefs
volumes are mounted and unmounted.
---
 build/jam/HaikuImage                    |   3 +-
 data/system/boot/Bootscript             |   2 +
 src/servers/Jamfile                     |   1 +
 src/servers/package/DebugSupport.cpp    | 150 +++++++++++++
 src/servers/package/DebugSupport.h      | 184 ++++++++++++++++
 src/servers/package/Jamfile             |  17 ++
 src/servers/package/PackageDaemon.cpp   | 267 ++++++++++++++++++++++++
 src/servers/package/PackageDaemon.h     |  57 +++++
 src/servers/package/Root.cpp            | 145 +++++++++++++
 src/servers/package/Root.h              |  56 +++++
 src/servers/package/Volume.cpp          |  99 +++++++++
 src/servers/package/Volume.h            |  55 +++++
 src/servers/package/package_daemon.rdef |  15 ++
 13 files changed, 1050 insertions(+), 1 deletion(-)
 create mode 100644 src/servers/package/DebugSupport.cpp
 create mode 100644 src/servers/package/DebugSupport.h
 create mode 100644 src/servers/package/Jamfile
 create mode 100644 src/servers/package/PackageDaemon.cpp
 create mode 100644 src/servers/package/PackageDaemon.h
 create mode 100644 src/servers/package/Root.cpp
 create mode 100644 src/servers/package/Root.h
 create mode 100644 src/servers/package/Volume.cpp
 create mode 100644 src/servers/package/Volume.h
 create mode 100644 src/servers/package/package_daemon.rdef

diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage
index 835c1a7553..799cc0c13b 100644
--- a/build/jam/HaikuImage
+++ b/build/jam/HaikuImage
@@ -106,7 +106,8 @@ PRIVATE_SYSTEM_LIBS =
 ;
 SYSTEM_SERVERS = app_server cddb_daemon debug_server input_server mail_daemon
 	media_addon_server media_server midi_server mount_server net_server
-	notification_server power_daemon print_server print_addon_server registrar syslog_daemon
+	notification_server package_daemon power_daemon print_server
+	print_addon_server registrar syslog_daemon
 ;
 
 SYSTEM_NETWORK_DEVICES = ethernet loopback ;
diff --git a/data/system/boot/Bootscript b/data/system/boot/Bootscript
index 8dc3db38a9..3e4b1f1e6d 100644
--- a/data/system/boot/Bootscript
+++ b/data/system/boot/Bootscript
@@ -98,6 +98,8 @@ launch $SERVERS/registrar _roster_thread_	# launch registrar
 
 launch $SERVERS/debug_server				# launch debug_server
 
+launch $SERVERS/package_daemon
+
 # Init Network
 if [ "$SAFEMODE" != "yes" ]; then
 	launch $SERVERS/net_server				# launch net_server
diff --git a/src/servers/Jamfile b/src/servers/Jamfile
index 141a8ad6ee..e906f7fb21 100644
--- a/src/servers/Jamfile
+++ b/src/servers/Jamfile
@@ -13,6 +13,7 @@ SubInclude HAIKU_TOP src servers midi ;
 SubInclude HAIKU_TOP src servers mount ;
 SubInclude HAIKU_TOP src servers net ;
 SubInclude HAIKU_TOP src servers notification ;
+SubInclude HAIKU_TOP src servers package ;
 SubInclude HAIKU_TOP src servers power ;
 SubInclude HAIKU_TOP src servers print ;
 SubInclude HAIKU_TOP src servers print_addon ;
diff --git a/src/servers/package/DebugSupport.cpp b/src/servers/package/DebugSupport.cpp
new file mode 100644
index 0000000000..8377cf340c
--- /dev/null
+++ b/src/servers/package/DebugSupport.cpp
@@ -0,0 +1,150 @@
+/*
+ * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Distributed under the terms of the MIT License.
+ */
+
+
+#include "DebugSupport.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+
+/*!
+	\file Debug.cpp
+	\brief Defines debug output function with printf() signature printing
+		   into a file.
+
+	\note The initialization is not thread safe!
+*/
+
+
+// locking support
+static int32 init_counter = 0;
+static sem_id dbg_printf_sem = -1;
+static thread_id dbg_printf_thread = -1;
+static int dbg_printf_nesting = 0;
+
+
+#if DEBUG_PRINT
+static int out = -1;
+#endif
+
+
+status_t
+init_debugging()
+{
+	status_t error = B_OK;
+	if (init_counter++ == 0) {
+		// open the file
+		#if DEBUG_PRINT
+			out = open(DEBUG_PRINT_FILE, O_RDWR | O_CREAT | O_TRUNC);
+			if (out < 0) {
+				error = errno;
+				init_counter--;
+			}
+		#endif	// DEBUG_PRINT
+		// allocate the semaphore
+		if (error == B_OK) {
+			dbg_printf_sem = create_sem(1, "dbg_printf");
+			if (dbg_printf_sem < 0)
+				error = dbg_printf_sem;
+		}
+		if (error == B_OK) {
+			#if DEBUG
+				__out("##################################################\n");
+			#endif
+		} else
+			exit_debugging();
+	}
+	return error;
+}
+
+
+status_t
+exit_debugging()
+{
+	status_t error = B_OK;
+	if (--init_counter == 0) {
+		#if DEBUG_PRINT
+			close(out);
+			out = -1;
+		#endif	// DEBUG_PRINT
+		delete_sem(dbg_printf_sem);
+	} else
+		error = B_NO_INIT;
+	return error;
+}
+
+
+static inline bool
+dbg_printf_lock()
+{
+	thread_id thread = find_thread(NULL);
+	if (thread != dbg_printf_thread) {
+		if (acquire_sem(dbg_printf_sem) != B_OK)
+			return false;
+		dbg_printf_thread = thread;
+	}
+	dbg_printf_nesting++;
+	return true;
+}
+
+
+static inline void
+dbg_printf_unlock()
+{
+	thread_id thread = find_thread(NULL);
+	if (thread != dbg_printf_thread)
+		return;
+	dbg_printf_nesting--;
+	if (dbg_printf_nesting == 0) {
+		dbg_printf_thread = -1;
+		release_sem(dbg_printf_sem);
+	}
+}
+
+
+void
+dbg_printf_begin()
+{
+	dbg_printf_lock();
+}
+
+
+void
+dbg_printf_end()
+{
+	dbg_printf_unlock();
+}
+
+
+#if DEBUG_PRINT
+
+void
+dbg_printf(const char *format,...)
+{
+	if (!dbg_printf_lock())
+		return;
+	char buffer[1024];
+	va_list args;
+	va_start(args, format);
+	// no vsnprintf() on PPC and in kernel
+	#if defined(__INTEL__) && USER
+		vsnprintf(buffer, sizeof(buffer) - 1, format, args);
+	#else
+		vsprintf(buffer, format, args);
+	#endif
+	va_end(args);
+	buffer[sizeof(buffer) - 1] = '\0';
+	write(out, buffer, strlen(buffer));
+	dbg_printf_unlock();
+}
+
+#endif	// DEBUG_PRINT
diff --git a/src/servers/package/DebugSupport.h b/src/servers/package/DebugSupport.h
new file mode 100644
index 0000000000..25592d41cb
--- /dev/null
+++ b/src/servers/package/DebugSupport.h
@@ -0,0 +1,184 @@
+/*
+ * Copyright 2003-2009, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 200?, Axel Dörfler, axeld@pinc-software.de.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef DEBUG_SUPPORT_H
+#define DEBUG_SUPPORT_H
+
+
+#include 
+
+
+// define all macros we work with -- undefined macros are set to defaults
+#ifndef USER
+#	ifdef _KERNEL_MODE
+#		define USER 0
+#	else
+#		define USER 1
+#	endif
+#endif
+#ifndef DEBUG
+#	define DEBUG 0
+#endif
+#if !DEBUG
+#	undef DEBUG_PRINT
+#	define DEBUG_PRINT 0
+#endif
+#ifndef DEBUG_PRINT
+#	define DEBUG_PRINT 0
+#endif
+#ifndef DEBUG_APP
+#	define DEBUG_APP	"package_daemon"
+#endif
+#ifndef DEBUG_PRINT_FILE
+#	define DEBUG_PRINT_FILE "/var/log/" DEBUG_APP ".log"
+#endif
+
+
+#if !USER
+#	include 
+#endif
+#include 
+#include 
+
+
+// define the debug output function
+#if USER
+#	include 
+#	if DEBUG_PRINT
+#		define __out dbg_printf
+#	else
+#		define __out debug_printf
+#	endif
+#else
+#	include 
+#	include 
+#	if DEBUG_PRINT
+#		define __out dbg_printf
+#	else
+#		define __out dprintf
+#	endif
+#endif
+
+
+// define the PANIC() macro
+#ifndef PANIC
+#	if USER
+#		define PANIC(str)	debugger(str)
+#	else
+#		define PANIC(str)	panic(str)
+#	endif
+#endif
+
+
+// functions exported by this module
+status_t init_debugging();
+status_t exit_debugging();
+void dbg_printf_begin();
+void dbg_printf_end();
+#if DEBUG_PRINT
+	void dbg_printf(const char *format,...);
+#else
+	static inline void dbg_printf(const char *,...) {}
+#endif
+
+
+// Short overview over the debug output macros:
+//	PRINT()
+//		is for general messages that very unlikely should appear in a release
+//		build
+//	FATAL()
+//		this is for fatal messages, when something has really gone wrong
+//	INFORM()
+//		general information, as disk size, etc.
+//	REPORT_ERROR(status_t)
+//		prints out error information
+//	RETURN_ERROR(status_t)
+//		calls REPORT_ERROR() and return the value
+//	D()
+//		the statements in D() are only included if DEBUG is defined
+
+
+#define DEBUG_THREAD	find_thread(NULL)
+#define DEBUG_CONTEXT(x)													\
+{																			\
+	dbg_printf_begin();														\
+	__out(DEBUG_APP " [%Ld: %5ld] ", system_time(), DEBUG_THREAD);			\
+	x;																		\
+	dbg_printf_end();														\
+}
+#define DEBUG_CONTEXT_FUNCTION(prefix, x)									\
+{																			\
+	dbg_printf_begin();														\
+	__out(DEBUG_APP " [%Ld: %5ld] %s" prefix, system_time(), DEBUG_THREAD,	\
+		__PRETTY_FUNCTION__);												\
+	x;																		\
+	dbg_printf_end();														\
+}
+#define DEBUG_CONTEXT_LINE(x)												\
+{																			\
+	dbg_printf_begin();														\
+	__out(DEBUG_APP " [%Ld: %5ld] %s:%d: ", system_time(), DEBUG_THREAD,	\
+		__PRETTY_FUNCTION__, __LINE__);										\
+	x;																		\
+	dbg_printf_end();														\
+}
+
+#define TPRINT(x...)	DEBUG_CONTEXT( __out(x) )
+#define TREPORT_ERROR(status)												\
+	DEBUG_CONTEXT_LINE( __out("%s\n", strerror(status)) )
+#define TRETURN_ERROR(err)													\
+{																			\
+	status_t _status = err;													\
+	if (_status < B_OK)														\
+		TREPORT_ERROR(_status);												\
+	return _status;															\
+}
+#define TSET_ERROR(var, err)												\
+{																			\
+	status_t _status = err;													\
+	if (_status < B_OK)														\
+		TREPORT_ERROR(_status);												\
+		var = _status;														\
+}
+#define TFUNCTION(x...)		DEBUG_CONTEXT_FUNCTION( ": ", __out(x) )
+#define TFUNCTION_START()	DEBUG_CONTEXT_FUNCTION( "\n",  )
+#define TFUNCTION_END()		DEBUG_CONTEXT_FUNCTION( " done\n",  )
+
+#if DEBUG
+	#define PRINT(x...)				TPRINT(x)
+	#define REPORT_ERROR(status)	TREPORT_ERROR(status)
+	#define RETURN_ERROR(err)		TRETURN_ERROR(err)
+	#define SET_ERROR(var, err)		TSET_ERROR(var, err)
+	#define FATAL(x...)				DEBUG_CONTEXT( __out(x) )
+	#define ERROR(x...)				DEBUG_CONTEXT( __out(x) )
+	#define WARN(x...)				DEBUG_CONTEXT( __out(x) )
+	#define INFORM(x...)			DEBUG_CONTEXT( __out(x) )
+	#define FUNCTION(x...)			TFUNCTION(x)
+	#define FUNCTION_START()		TFUNCTION_START()
+	#define FUNCTION_END()			TFUNCTION_END()
+	#define DARG(x)					x
+	#define D(x)					{x;};
+#else
+	#define PRINT(x...)				;
+	#define REPORT_ERROR(status)	;
+	#define RETURN_ERROR(status)	return status;
+	#define SET_ERROR(var, err)		var = err;
+	#define FATAL(x...)				DEBUG_CONTEXT( __out(x) )
+	#define ERROR(x...)				DEBUG_CONTEXT( __out(x) )
+	#define WARN(x...)				DEBUG_CONTEXT( __out(x) )
+	#define INFORM(x...)			DEBUG_CONTEXT( __out(x) )
+	#define FUNCTION(x...)			;
+	#define FUNCTION_START()		;
+	#define FUNCTION_END()			;
+	#define DARG(x)
+	#define D(x)					;
+#endif
+
+#ifndef TOUCH
+#define TOUCH(var) (void)var
+#endif
+
+
+#endif	// DEBUG_SUPPORT_H
diff --git a/src/servers/package/Jamfile b/src/servers/package/Jamfile
new file mode 100644
index 0000000000..099f966092
--- /dev/null
+++ b/src/servers/package/Jamfile
@@ -0,0 +1,17 @@
+SubDir HAIKU_TOP src servers package ;
+
+UsePrivateSystemHeaders ;
+UsePrivateHeaders app package shared ;
+
+Server package_daemon
+ 	:
+ 	DebugSupport.cpp
+ 	PackageDaemon.cpp
+ 	Root.cpp
+ 	Volume.cpp
+	:
+	be package
+	$(TARGET_LIBSTDC++)
+	:
+	package_daemon.rdef
+;
diff --git a/src/servers/package/PackageDaemon.cpp b/src/servers/package/PackageDaemon.cpp
new file mode 100644
index 0000000000..0942049d0f
--- /dev/null
+++ b/src/servers/package/PackageDaemon.cpp
@@ -0,0 +1,267 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include "PackageDaemon.h"
+
+#include 
+#include 
+
+#include 
+#include 
+
+#include 
+
+#include "DebugSupport.h"
+#include "Root.h"
+#include "Volume.h"
+
+
+PackageDaemon::PackageDaemon(status_t* _error)
+	:
+	BServer("application/x-vnd.haiku-package_daemon", false, _error),
+	fSystemRoot(NULL),
+	fRoots(10, true),
+	fVolumeWatcher()
+{
+}
+
+
+PackageDaemon::~PackageDaemon()
+{
+//	delete fSystemRoot;
+}
+
+
+status_t
+PackageDaemon::Init()
+{
+	status_t error = fVolumeWatcher.StartWatching(BMessenger(this, this));
+	if (error != B_OK) {
+		ERROR("PackageDaemon::Init(): failed to start volume watching: %s\n",
+			strerror(error));
+	}
+
+	// register all packagefs volumes
+	for (int32 cookie = 0;;) {
+		dev_t device = next_dev(&cookie);
+		if (device < 0)
+			break;
+
+		_RegisterVolume(device);
+	}
+
+	return B_OK;
+}
+
+
+void
+PackageDaemon::MessageReceived(BMessage* message)
+{
+	switch (message->what) {
+		case B_NODE_MONITOR:
+		{
+			int32 opcode;
+			if (message->FindInt32("opcode", &opcode) != B_OK)
+				break;
+			if (opcode == B_DEVICE_MOUNTED)
+				_HandleVolumeMounted(message);
+			else if (opcode == B_DEVICE_UNMOUNTED)
+				_HandleVolumeUnmounted(message);
+			break;
+		}
+		default:
+			BServer::MessageReceived(message);
+			break;
+	}
+}
+
+
+status_t
+PackageDaemon::_RegisterVolume(dev_t deviceID)
+{
+	// get the FS info and check whether this is a package FS volume at all
+	fs_info info;
+	status_t error = fs_stat_dev(deviceID, &info);
+	if (error != 0)
+		RETURN_ERROR(error);
+
+	if (strcmp(info.fsh_name, "packagefs") != 0)
+		RETURN_ERROR(B_BAD_VALUE);
+
+	// open the root directory of the volume
+	node_ref nodeRef;
+	nodeRef.device = info.dev;
+	nodeRef.node = info.root;
+	BDirectory directory;
+	error = directory.SetTo(&nodeRef);
+	if (error != B_OK) {
+		ERROR("PackageDaemon::_RegisterVolume(): failed to open root: %s\n",
+			strerror(error));
+		return error;
+	}
+
+	// create a volume
+	Volume* volume = new(std::nothrow) Volume;
+	if (volume == NULL)
+		RETURN_ERROR(B_NO_MEMORY);
+	ObjectDeleter volumeDeleter(volume);
+
+	dev_t rootDeviceID;
+	ino_t rootNodeID;
+	error = volume->Init(directory, rootDeviceID, rootNodeID);
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	if (volume->MountType() == PACKAGE_FS_MOUNT_TYPE_CUSTOM) {
+// TODO: Or maybe not?
+		INFORM("skipping custom mounted volume at \"%s\"\n",
+			volume->Path().String());
+		return B_OK;
+	}
+
+	// get the root for the volume and register it
+	Root* root;
+	error = _GetOrCreateRoot(rootDeviceID, rootNodeID, root);
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	error = root->RegisterVolume(volume);
+	if (error != B_OK) {
+		_PutRoot(root);
+		RETURN_ERROR(error);
+	}
+	volumeDeleter.Detach();
+
+	INFORM("volume at \"%s\" registered\n", volume->Path().String());
+
+	return B_OK;
+}
+
+
+void
+PackageDaemon::_UnregisterVolume(Volume* volume)
+{
+	Root* root = volume->GetRoot();
+	root->UnregisterVolume(volume);
+
+	INFORM("volume at \"%s\" unregistered\n", volume->Path().String());
+
+	delete volume;
+	_PutRoot(root);
+}
+
+
+status_t
+PackageDaemon::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, Root*& _root)
+{
+	Root* root = _FindRoot(deviceID, nodeID);
+	if (root != NULL) {
+		root->AcquireReference();
+	} else {
+		root = new(std::nothrow) Root;
+		if (root == NULL)
+			RETURN_ERROR(B_NO_MEMORY);
+		ObjectDeleter rootDeleter(root);
+
+		status_t error = root->Init(deviceID, nodeID);
+		if (error != B_OK)
+			RETURN_ERROR(error);
+
+		if (!fRoots.AddItem(root))
+			RETURN_ERROR(B_NO_MEMORY);
+
+		rootDeleter.Detach();
+
+		INFORM("root at \"%s\" (device: %" B_PRIdDEV ", node: %" B_PRIdINO ") "
+			"registered\n", root->Path().String(), deviceID, nodeID);
+	}
+
+	_root = root;
+	return B_OK;
+}
+
+
+Root*
+PackageDaemon::_FindRoot(dev_t deviceID, ino_t nodeID) const
+{
+	for (int32 i = 0; Root* root = fRoots.ItemAt(i); i++) {
+		if (root->DeviceID() == deviceID && root->NodeID() == nodeID)
+			return root;
+	}
+
+	return NULL;
+}
+
+
+void
+PackageDaemon::_PutRoot(Root* root)
+{
+	if (root->ReleaseReference() == 1) {
+		INFORM("root at \"%s\" unregistered\n", root->Path().String());
+		fRoots.RemoveItem(root, true);
+			// deletes the object
+	}
+}
+
+
+Volume*
+PackageDaemon::_FindVolume(dev_t deviceID) const
+{
+	for (int32 i = 0; Root* root = fRoots.ItemAt(i); i++) {
+		if (Volume* volume = root->FindVolume(deviceID))
+			return volume;
+	}
+
+	return NULL;
+}
+
+
+void
+PackageDaemon::_HandleVolumeMounted(const BMessage* message)
+{
+	int32 device;
+	if (message->FindInt32("new device", &device) != B_OK)
+		return;
+
+	// _RegisterVolume() also checks whether it is a package FS volume, so we
+	// don't need to bother.
+	_RegisterVolume(device);
+}
+
+
+void
+PackageDaemon::_HandleVolumeUnmounted(const BMessage* message)
+{
+	int32 device;
+	if (message->FindInt32("device", &device) != B_OK)
+		return;
+
+	if (Volume* volume = _FindVolume(device))
+		_UnregisterVolume(volume);
+}
+
+
+// #pragma mark -
+
+
+int
+main(int argc, const char* const* argv)
+{
+	status_t error;
+	PackageDaemon daemon(&error);
+	if (error == B_OK)
+		error = daemon.Init();
+	if (error != B_OK) {
+		FATAL("failed to init server application: %s\n", strerror(error));
+		return 1;
+	}
+
+	daemon.Run();
+	return 0;
+}
diff --git a/src/servers/package/PackageDaemon.h b/src/servers/package/PackageDaemon.h
new file mode 100644
index 0000000000..86c6f4c2c0
--- /dev/null
+++ b/src/servers/package/PackageDaemon.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef PACKAGE_DAEMON_H
+#define PACKAGE_DAEMON_H
+
+
+#include 
+#include 
+#include 
+
+#include 
+
+
+class Root;
+class Volume;
+
+
+class PackageDaemon : public BServer {
+public:
+								PackageDaemon(status_t* _error);
+	virtual						~PackageDaemon();
+
+			status_t			Init();
+
+	virtual	void				MessageReceived(BMessage* message);
+
+private:
+			typedef BObjectList RootList;
+
+private:
+			status_t			_RegisterVolume(dev_t device);
+			void				_UnregisterVolume(Volume* volume);
+
+			status_t			_GetOrCreateRoot(dev_t deviceID, ino_t nodeID,
+									Root*& _root);
+			Root*				_FindRoot(dev_t deviceID, ino_t nodeID) const;
+			void				_PutRoot(Root* root);
+
+			Volume*				_FindVolume(dev_t deviceID) const;
+
+			void				_HandleVolumeMounted(const BMessage* message);
+			void				_HandleVolumeUnmounted(const BMessage* message);
+
+private:
+			Root*				fSystemRoot;
+			RootList			fRoots;
+			BVolumeRoster		fVolumeWatcher;
+};
+
+
+
+#endif	// PACKAGE_DAEMON_H
diff --git a/src/servers/package/Root.cpp b/src/servers/package/Root.cpp
new file mode 100644
index 0000000000..bf7fec9939
--- /dev/null
+++ b/src/servers/package/Root.cpp
@@ -0,0 +1,145 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include "Root.h"
+
+#include 
+#include 
+#include 
+
+#include "DebugSupport.h"
+#include "Volume.h"
+
+
+Root::Root()
+	:
+	fDeviceID(-1),
+	fNodeID(-1),
+	fPath(),
+	fSystemVolume(NULL),
+	fCommonVolume(NULL),
+	fHomeVolume(NULL)
+{
+}
+
+
+Root::~Root()
+{
+}
+
+
+status_t
+Root::Init(dev_t deviceID, ino_t nodeID)
+{
+	fDeviceID = deviceID;
+	fNodeID = nodeID;
+
+	// get the path
+	node_ref nodeRef;
+	nodeRef.device = fDeviceID;
+	nodeRef.node = fNodeID;
+	BDirectory directory;
+	status_t error = directory.SetTo(&nodeRef);
+	if (error != B_OK) {
+		ERROR("Root::Init(): failed to open directory: %s\n", strerror(error));
+		return error;
+	}
+
+	BEntry entry;
+	error = directory.GetEntry(&entry);
+
+	BPath path;
+	if (error == B_OK)
+		error = entry.GetPath(&path);
+
+	if (error != B_OK) {
+		ERROR("Root::Init(): failed to get directory path: %s\n",
+			strerror(error));
+		RETURN_ERROR(error);
+	}
+
+	fPath = path.Path();
+	if (fPath.IsEmpty())
+		RETURN_ERROR(B_NO_MEMORY);
+
+	return B_OK;
+}
+
+
+status_t
+Root::RegisterVolume(Volume* volume)
+{
+	Volume** volumeToSet = _GetVolume(volume->MountType());
+	if (volumeToSet == NULL)
+		return B_BAD_VALUE;
+
+	if (*volumeToSet != NULL) {
+		ERROR("Root::RegisterVolume(): can't register volume at \"%s\", since "
+			"there's already volume at \"%s\" with the same type.\n",
+			volume->Path().String(), (*volumeToSet)->Path().String());
+		return B_BAD_VALUE;
+	}
+
+	*volumeToSet = volume;
+	volume->SetRoot(this);
+
+	return B_OK;
+}
+
+
+void
+Root::UnregisterVolume(Volume* volume)
+{
+	Volume** volumeToSet = _GetVolume(volume->MountType());
+	if (volumeToSet == NULL || *volumeToSet != volume) {
+		ERROR("Root::UnregisterVolume(): can't unregister unknown volume at "
+			"\"%s.\n", volume->Path().String());
+		return;
+	}
+
+	*volumeToSet = NULL;
+	volume->SetRoot(NULL);
+}
+
+
+Volume*
+Root::FindVolume(dev_t deviceID) const
+{
+	Volume* volumes[] = { fSystemVolume, fCommonVolume, fHomeVolume };
+	for (size_t i = 0; i < sizeof(volumes) / sizeof(volumes[0]); i++) {
+		Volume* volume = volumes[i];
+		if (volume != NULL && volume->DeviceID() == deviceID)
+			return volume;
+	}
+
+	return NULL;
+}
+
+
+void
+Root::LastReferenceReleased()
+{
+}
+
+
+Volume**
+Root::_GetVolume(PackageFSMountType mountType)
+{
+	switch (mountType) {
+		case PACKAGE_FS_MOUNT_TYPE_SYSTEM:
+			return &fSystemVolume;
+		case PACKAGE_FS_MOUNT_TYPE_COMMON:
+			return &fCommonVolume;
+		case PACKAGE_FS_MOUNT_TYPE_HOME:
+			return &fHomeVolume;
+		case PACKAGE_FS_MOUNT_TYPE_CUSTOM:
+		default:
+			return NULL;
+	}
+}
diff --git a/src/servers/package/Root.h b/src/servers/package/Root.h
new file mode 100644
index 0000000000..940f99c27f
--- /dev/null
+++ b/src/servers/package/Root.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef ROOT_H
+#define ROOT_H
+
+
+#include 
+#include 
+
+#include 
+
+#include 
+
+
+class Volume;
+
+
+class Root : public BReferenceable {
+public:
+								Root();
+	virtual						~Root();
+
+			status_t			Init(dev_t deviceID, ino_t nodeID);
+
+			dev_t				DeviceID() const	{ return fDeviceID; }
+			ino_t				NodeID() const		{ return fNodeID; }
+			const BString&		Path() const
+									{ return fPath; }
+
+			status_t			RegisterVolume(Volume* volume);
+			void				UnregisterVolume(Volume* volume);
+
+			Volume*				FindVolume(dev_t deviceID) const;
+
+protected:
+	virtual	void				LastReferenceReleased();
+
+private:
+			Volume**			_GetVolume(PackageFSMountType mountType);
+
+private:
+			dev_t				fDeviceID;
+			ino_t				fNodeID;
+			BString				fPath;
+			Volume*				fSystemVolume;
+			Volume*				fCommonVolume;
+			Volume*				fHomeVolume;
+};
+
+
+#endif	// ROOT_H
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
new file mode 100644
index 0000000000..4d17279fc0
--- /dev/null
+++ b/src/servers/package/Volume.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include "Volume.h"
+
+#include 
+#include 
+#include 
+
+#include 
+#include 
+#include 
+
+#include "DebugSupport.h"
+
+
+Volume::Volume()
+	:
+	fPath(),
+	fMountType(PACKAGE_FS_MOUNT_TYPE_CUSTOM),
+	fDeviceID(-1),
+	fRootDirectoryID(1),
+	fRoot(NULL)
+{
+}
+
+
+Volume::~Volume()
+{
+}
+
+
+status_t
+Volume::Init(BDirectory& directory, dev_t& _rootDeviceID, ino_t& _rootNodeID)
+{
+	// get the directory path
+	BEntry entry;
+	status_t error = directory.GetEntry(&entry);
+
+	BPath path;
+	if (error == B_OK)
+		error = entry.GetPath(&path);
+
+	if (error != B_OK) {
+		ERROR("Volume::Init(): failed to get root directory path: %s\n",
+			strerror(error));
+		RETURN_ERROR(error);
+	}
+
+	fPath = path.Path();
+	if (fPath.IsEmpty())
+		RETURN_ERROR(B_NO_MEMORY);
+
+	// stat() the directory
+	struct stat st;
+	error = directory.GetStat(&st);
+	if (error != B_OK) {
+		ERROR("Volume::Init(): failed to stat root directory: %s\n",
+			strerror(error));
+		RETURN_ERROR(error);
+	}
+
+	fDeviceID = st.st_dev;
+	fRootDirectoryID = st.st_ino;
+
+	// get a volume info from the FS
+	int fd = directory.Dup();
+	if (fd < 0) {
+		ERROR("Volume::Init(): failed to get root directory FD: %s\n",
+			strerror(fd));
+		RETURN_ERROR(fd);
+	}
+
+	PackageFSVolumeInfo info;
+	if (ioctl(fd, PACKAGE_FS_OPERATION_GET_VOLUME_INFO, &info, sizeof(info))
+			!= 0) {
+		error = errno;
+		close(fd);
+		if (error != B_OK) {
+			ERROR("Volume::Init(): failed to get volume info: %s\n",
+				strerror(error));
+			RETURN_ERROR(error);
+		}
+	}
+
+	close(fd);
+
+	fMountType = info.mountType;
+	_rootDeviceID = info.rootDeviceID;
+	_rootNodeID = info.rootDirectoryID;
+
+	return B_OK;
+}
diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h
new file mode 100644
index 0000000000..aa90a29716
--- /dev/null
+++ b/src/servers/package/Volume.h
@@ -0,0 +1,55 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef VOLUME_H
+#define VOLUME_H
+
+
+#include 
+#include 
+
+#include 
+
+
+class BDirectory;
+
+class Root;
+
+
+class Volume {
+public:
+								Volume();
+								~Volume();
+
+			status_t			Init(BDirectory& directory,
+									dev_t& _rootDeviceID, ino_t& _rootNodeID);
+
+			const BString&		Path() const
+									{ return fPath; }
+			PackageFSMountType	MountType() const
+									{ return fMountType; }
+			dev_t				DeviceID() const
+									{ return fDeviceID; }
+			ino_t				RootDirectoryID() const
+									{ return fRootDirectoryID; }
+
+			Root*				GetRoot() const
+									{ return fRoot; }
+			void				SetRoot(Root* root)
+									{ fRoot = root; }
+
+private:
+			BString				fPath;
+			PackageFSMountType	fMountType;
+			dev_t				fDeviceID;
+			ino_t				fRootDirectoryID;
+			Root*				fRoot;
+};
+
+
+
+#endif	// VOLUME_H
diff --git a/src/servers/package/package_daemon.rdef b/src/servers/package/package_daemon.rdef
new file mode 100644
index 0000000000..ad88e3cba0
--- /dev/null
+++ b/src/servers/package/package_daemon.rdef
@@ -0,0 +1,15 @@
+resource app_signature "application/x-vnd.haiku-package_daemon";
+
+resource app_flags B_EXCLUSIVE_LAUNCH | B_BACKGROUND_APP;
+
+resource app_version {
+	major  = 1,
+	middle = 0,
+	minor  = 0,
+
+	variety = B_APPV_ALPHA,
+	internal = 0,
+
+	short_info = "package_daemon",
+	long_info = "package_daemon ©2013 Haiku, Inc."
+};

From 2d8ec1d502634cf7d3fffc50bae54c5019a807fd Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 6 Apr 2013 23:30:18 +0200
Subject: [PATCH 0361/1170] Add the obvious node_ref constructor

---
 headers/os/storage/Node.h |  1 +
 src/kits/storage/Node.cpp | 10 +++++++++-
 2 files changed, 10 insertions(+), 1 deletion(-)

diff --git a/headers/os/storage/Node.h b/headers/os/storage/Node.h
index bb22e74fac..a7dfe84dec 100644
--- a/headers/os/storage/Node.h
+++ b/headers/os/storage/Node.h
@@ -16,6 +16,7 @@ struct entry_ref;
 
 struct node_ref {
 	node_ref();
+	node_ref(dev_t device, ino_t node);
 	node_ref(const node_ref &ref);
 
 	bool operator==(const node_ref &ref) const;
diff --git a/src/kits/storage/Node.cpp b/src/kits/storage/Node.cpp
index 1fc1fa730b..5cce99b1a7 100644
--- a/src/kits/storage/Node.cpp
+++ b/src/kits/storage/Node.cpp
@@ -38,7 +38,15 @@ node_ref::node_ref()
 {
 }
 
-// copy constructor
+
+node_ref::node_ref(dev_t device, ino_t node)
+	:
+	device(device),
+	node(node)
+{
+}
+
+
 node_ref::node_ref(const node_ref &ref)
 		: device((dev_t)-1),
 		  node((ino_t)-1)

From 27197fd74b19289e5a6dd5a344a66c18259324d8 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 7 Apr 2013 11:38:03 +0200
Subject: [PATCH 0362/1170] packagefs Package: Add getters for device and node
 ID

---
 src/add-ons/kernel/file_systems/packagefs/Package.h | 5 +++++
 1 file changed, 5 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.h b/src/add-ons/kernel/file_systems/packagefs/Package.h
index 2cf5cec1d2..6b69fd01ef 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Package.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Package.h
@@ -44,6 +44,11 @@ public:
 			status_t			SetName(const char* name);
 			const char*			Name() const		{ return fName; }
 
+			dev_t				DeviceID() const
+									{ return fDeviceID; }
+			ino_t				NodeID() const
+									{ return fNodeID; }
+
 			status_t			SetInstallPath(const char* installPath);
 			const char*			InstallPath() const	{ return fInstallPath; }
 

From e85e9dadda48ba707367595e2aa93dc8f9f78054 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 7 Apr 2013 11:45:47 +0200
Subject: [PATCH 0363/1170] packagefs: Move the package loading code to Package

* Volume::_LoadPackage() -> Package::Load()
* Volume::_DomainEntryCreated(): Pull a bit of code into a new
  _LoadPackage() method for reuse.
---
 .../kernel/file_systems/packagefs/Package.cpp | 304 +++++++++++++++
 .../kernel/file_systems/packagefs/Package.h   |   5 +
 .../kernel/file_systems/packagefs/Volume.cpp  | 353 ++----------------
 .../kernel/file_systems/packagefs/Volume.h    |   4 +-
 4 files changed, 345 insertions(+), 321 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.cpp b/src/add-ons/kernel/file_systems/packagefs/Package.cpp
index c5a21e8c96..28fc000b80 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Package.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Package.cpp
@@ -12,13 +12,26 @@
 #include 
 #include 
 
+#include 
+#include 
+#include 
+#include 
+#include 
 #include 
 
 #include "DebugSupport.h"
+#include "PackageDirectory.h"
 #include "PackageDomain.h"
+#include "PackageFile.h"
+#include "PackageSymlink.h"
 #include "Version.h"
 
 
+using namespace BPackageKit;
+using namespace BPackageKit::BHPKG;
+using BPackageKit::BHPKG::BPrivate::PackageReaderImpl;
+
+
 const char* const kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
 	"any",
 	"x86",
@@ -26,6 +39,267 @@ const char* const kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
 };
 
 
+// #pragma mark - LoaderErrorOutput
+
+
+struct Package::LoaderErrorOutput : BErrorOutput {
+	LoaderErrorOutput(Package* package)
+		:
+		fPackage(package)
+	{
+	}
+
+	virtual void PrintErrorVarArgs(const char* format, va_list args)
+	{
+// TODO:...
+	}
+
+private:
+	Package*	fPackage;
+};
+
+
+// #pragma mark - LoaderContentHandler
+
+
+struct Package::LoaderContentHandler : BPackageContentHandler {
+	LoaderContentHandler(Package* package)
+		:
+		fPackage(package),
+		fErrorOccurred(false)
+	{
+	}
+
+	status_t Init()
+	{
+		return B_OK;
+	}
+
+	virtual status_t HandleEntry(BPackageEntry* entry)
+	{
+		if (fErrorOccurred)
+			return B_OK;
+
+		PackageDirectory* parentDir = NULL;
+		if (entry->Parent() != NULL) {
+			parentDir = dynamic_cast(
+				(PackageNode*)entry->Parent()->UserToken());
+			if (parentDir == NULL)
+				RETURN_ERROR(B_BAD_DATA);
+		}
+
+		status_t error;
+
+		// get the file mode -- filter out write permissions
+		mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
+
+		// create the package node
+		PackageNode* node;
+		if (S_ISREG(mode)) {
+			// file
+			node = new(std::nothrow) PackageFile(fPackage, mode, entry->Data());
+		} else if (S_ISLNK(mode)) {
+			// symlink
+			PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
+				fPackage, mode);
+			if (symlink == NULL)
+				RETURN_ERROR(B_NO_MEMORY);
+
+			error = symlink->SetSymlinkPath(entry->SymlinkPath());
+			if (error != B_OK) {
+				delete symlink;
+				return error;
+			}
+
+			node = symlink;
+		} else if (S_ISDIR(mode)) {
+			// directory
+			node = new(std::nothrow) PackageDirectory(fPackage, mode);
+		} else
+			RETURN_ERROR(B_BAD_DATA);
+
+		if (node == NULL)
+			RETURN_ERROR(B_NO_MEMORY);
+		BReference nodeReference(node, true);
+
+		error = node->Init(parentDir, entry->Name());
+		if (error != B_OK)
+			RETURN_ERROR(error);
+
+		node->SetModifiedTime(entry->ModifiedTime());
+
+		// add it to the parent directory
+		if (parentDir != NULL)
+			parentDir->AddChild(node);
+		else
+			fPackage->AddNode(node);
+
+		entry->SetUserToken(node);
+
+		return B_OK;
+	}
+
+	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
+		BPackageEntryAttribute* attribute)
+	{
+		if (fErrorOccurred)
+			return B_OK;
+
+		PackageNode* node = (PackageNode*)entry->UserToken();
+
+		PackageNodeAttribute* nodeAttribute = new(std::nothrow)
+			PackageNodeAttribute(attribute->Type(), attribute->Data());
+		if (nodeAttribute == NULL)
+			RETURN_ERROR(B_NO_MEMORY)
+
+		status_t error = nodeAttribute->Init(attribute->Name());
+		if (error != B_OK) {
+			delete nodeAttribute;
+			RETURN_ERROR(error);
+		}
+
+		node->AddAttribute(nodeAttribute);
+
+		return B_OK;
+	}
+
+	virtual status_t HandleEntryDone(BPackageEntry* entry)
+	{
+		return B_OK;
+	}
+
+	virtual status_t HandlePackageAttribute(
+		const BPackageInfoAttributeValue& value)
+	{
+		switch (value.attributeID) {
+			case B_PACKAGE_INFO_NAME:
+				return fPackage->SetName(value.string);
+
+			case B_PACKAGE_INFO_INSTALL_PATH:
+				return fPackage->SetInstallPath(value.string);
+
+			case B_PACKAGE_INFO_VERSION:
+			{
+				::Version* version;
+				status_t error = Version::Create(value.version.major,
+					value.version.minor, value.version.micro,
+					value.version.preRelease, value.version.release, version);
+				if (error != B_OK)
+					RETURN_ERROR(error);
+
+				fPackage->SetVersion(version);
+
+				break;
+			}
+
+			case B_PACKAGE_INFO_ARCHITECTURE:
+				if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT)
+					RETURN_ERROR(B_BAD_VALUE);
+
+				fPackage->SetArchitecture(
+					(BPackageArchitecture)value.unsignedInt);
+				break;
+
+			case B_PACKAGE_INFO_PROVIDES:
+			{
+				// create a version object, if a version is specified
+				::Version* version = NULL;
+				if (value.resolvable.haveVersion) {
+					const BPackageVersionData& versionInfo
+						= value.resolvable.version;
+					status_t error = Version::Create(versionInfo.major,
+						versionInfo.minor, versionInfo.micro,
+						versionInfo.preRelease, versionInfo.release, version);
+					if (error != B_OK)
+						RETURN_ERROR(error);
+				}
+				ObjectDeleter< ::Version> versionDeleter(version);
+
+				// create a version object, if a compatible version is specified
+				::Version* compatibleVersion = NULL;
+				if (value.resolvable.haveCompatibleVersion) {
+					const BPackageVersionData& versionInfo
+						= value.resolvable.compatibleVersion;
+					status_t error = Version::Create(versionInfo.major,
+						versionInfo.minor, versionInfo.micro,
+						versionInfo.preRelease, versionInfo.release,
+						compatibleVersion);
+					if (error != B_OK)
+						RETURN_ERROR(error);
+				}
+				ObjectDeleter< ::Version> compatibleVersionDeleter(
+					compatibleVersion);
+
+				// create the resolvable
+				Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage);
+				if (resolvable == NULL)
+					RETURN_ERROR(B_NO_MEMORY);
+				ObjectDeleter resolvableDeleter(resolvable);
+
+				status_t error = resolvable->Init(value.resolvable.name,
+					versionDeleter.Detach(), compatibleVersionDeleter.Detach());
+				if (error != B_OK)
+					RETURN_ERROR(error);
+
+				fPackage->AddResolvable(resolvableDeleter.Detach());
+
+				break;
+			}
+
+			case B_PACKAGE_INFO_REQUIRES:
+			{
+				// create the dependency
+				Dependency* dependency = new(std::nothrow) Dependency(fPackage);
+				if (dependency == NULL)
+					RETURN_ERROR(B_NO_MEMORY);
+				ObjectDeleter dependencyDeleter(dependency);
+
+				status_t error = dependency->Init(
+					value.resolvableExpression.name);
+				if (error != B_OK)
+					RETURN_ERROR(error);
+
+				// create a version object, if a version is specified
+				::Version* version = NULL;
+				if (value.resolvableExpression.haveOpAndVersion) {
+					const BPackageVersionData& versionInfo
+						= value.resolvableExpression.version;
+					status_t error = Version::Create(versionInfo.major,
+						versionInfo.minor, versionInfo.micro,
+						versionInfo.preRelease, versionInfo.release, version);
+					if (error != B_OK)
+						RETURN_ERROR(error);
+
+					dependency->SetVersionRequirement(
+						value.resolvableExpression.op, version);
+				}
+
+				fPackage->AddDependency(dependencyDeleter.Detach());
+
+				break;
+			}
+
+			default:
+				break;
+		}
+
+		return B_OK;
+	}
+
+	virtual void HandleErrorOccurred()
+	{
+		fErrorOccurred = true;
+	}
+
+private:
+	Package*	fPackage;
+	bool		fErrorOccurred;
+};
+
+
+// #pragma mark - Package
+
+
 Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID)
 	:
 	fDomain(domain),
@@ -75,6 +349,36 @@ Package::Init(const char* fileName)
 }
 
 
+status_t
+Package::Load()
+{
+	// open package file
+	int fd = Open();
+	if (fd < 0)
+		RETURN_ERROR(fd);
+	PackageCloser packageCloser(this);
+
+	// initialize package reader
+	LoaderErrorOutput errorOutput(this);
+	PackageReaderImpl packageReader(&errorOutput);
+	status_t error = packageReader.Init(fd, false);
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	// parse content
+	LoaderContentHandler handler(this);
+	error = handler.Init();
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	error = packageReader.ParseContent(&handler);
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	return B_OK;
+}
+
+
 status_t
 Package::SetName(const char* name)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.h b/src/add-ons/kernel/file_systems/packagefs/Package.h
index 6b69fd01ef..d9b0b56a6a 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Package.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Package.h
@@ -37,6 +37,7 @@ public:
 								~Package();
 
 			status_t			Init(const char* fileName);
+			status_t			Load();
 
 			PackageDomain*		Domain() const		{ return fDomain; }
 			const char*			FileName() const	{ return fFileName; }
@@ -86,6 +87,10 @@ public:
 			const DependencyList& Dependencies() const
 									{ return fDependencies; }
 
+private:
+			struct LoaderErrorOutput;
+			struct LoaderContentHandler;
+
 private:
 			mutex				fLock;
 			PackageDomain*		fDomain;
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 6d89b4e04d..d0ed67e3d5 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -25,23 +25,15 @@
 #include 
 #include 
 
-#include 
-#include 
-#include 
-#include 
-
 #include "AttributeIndex.h"
 #include "DebugSupport.h"
 #include "kernel_interface.h"
 #include "LastModifiedIndex.h"
 #include "NameIndex.h"
 #include "OldUnpackingNodeAttributes.h"
-#include "PackageDirectory.h"
-#include "PackageFile.h"
 #include "PackageFSRoot.h"
 #include "PackageLinkDirectory.h"
 #include "PackageLinksDirectory.h"
-#include "PackageSymlink.h"
 #include "Resolvable.h"
 #include "SizeIndex.h"
 #include "UnpackingLeafNode.h"
@@ -50,11 +42,6 @@
 #include "Version.h"
 
 
-using namespace BPackageKit;
-using namespace BPackageKit::BHPKG;
-using BPackageKit::BHPKG::BPrivate::PackageReaderImpl;
-
-
 // node ID of the root directory
 static const ino_t kRootDirectoryID = 1;
 
@@ -156,264 +143,6 @@ private:
 };
 
 
-// #pragma mark - PackageLoaderErrorOutput
-
-
-struct Volume::PackageLoaderErrorOutput : BErrorOutput {
-	PackageLoaderErrorOutput(Package* package)
-		:
-		fPackage(package)
-	{
-	}
-
-	virtual void PrintErrorVarArgs(const char* format, va_list args)
-	{
-// TODO:...
-	}
-
-private:
-	Package*	fPackage;
-};
-
-
-// #pragma mark - PackageLoaderContentHandler
-
-
-struct Volume::PackageLoaderContentHandler : BPackageContentHandler {
-	PackageLoaderContentHandler(Package* package)
-		:
-		fPackage(package),
-		fErrorOccurred(false)
-	{
-	}
-
-	status_t Init()
-	{
-		return B_OK;
-	}
-
-	virtual status_t HandleEntry(BPackageEntry* entry)
-	{
-		if (fErrorOccurred)
-			return B_OK;
-
-		PackageDirectory* parentDir = NULL;
-		if (entry->Parent() != NULL) {
-			parentDir = dynamic_cast(
-				(PackageNode*)entry->Parent()->UserToken());
-			if (parentDir == NULL)
-				RETURN_ERROR(B_BAD_DATA);
-		}
-
-		status_t error;
-
-		// get the file mode -- filter out write permissions
-		mode_t mode = entry->Mode() & ~(mode_t)(S_IWUSR | S_IWGRP | S_IWOTH);
-
-		// create the package node
-		PackageNode* node;
-		if (S_ISREG(mode)) {
-			// file
-			node = new(std::nothrow) PackageFile(fPackage, mode, entry->Data());
-		} else if (S_ISLNK(mode)) {
-			// symlink
-			PackageSymlink* symlink = new(std::nothrow) PackageSymlink(
-				fPackage, mode);
-			if (symlink == NULL)
-				RETURN_ERROR(B_NO_MEMORY);
-
-			error = symlink->SetSymlinkPath(entry->SymlinkPath());
-			if (error != B_OK) {
-				delete symlink;
-				return error;
-			}
-
-			node = symlink;
-		} else if (S_ISDIR(mode)) {
-			// directory
-			node = new(std::nothrow) PackageDirectory(fPackage, mode);
-		} else
-			RETURN_ERROR(B_BAD_DATA);
-
-		if (node == NULL)
-			RETURN_ERROR(B_NO_MEMORY);
-		BReference nodeReference(node, true);
-
-		error = node->Init(parentDir, entry->Name());
-		if (error != B_OK)
-			RETURN_ERROR(error);
-
-		node->SetModifiedTime(entry->ModifiedTime());
-
-		// add it to the parent directory
-		if (parentDir != NULL)
-			parentDir->AddChild(node);
-		else
-			fPackage->AddNode(node);
-
-		entry->SetUserToken(node);
-
-		return B_OK;
-	}
-
-	virtual status_t HandleEntryAttribute(BPackageEntry* entry,
-		BPackageEntryAttribute* attribute)
-	{
-		if (fErrorOccurred)
-			return B_OK;
-
-		PackageNode* node = (PackageNode*)entry->UserToken();
-
-		PackageNodeAttribute* nodeAttribute = new(std::nothrow)
-			PackageNodeAttribute(attribute->Type(), attribute->Data());
-		if (nodeAttribute == NULL)
-			RETURN_ERROR(B_NO_MEMORY)
-
-		status_t error = nodeAttribute->Init(attribute->Name());
-		if (error != B_OK) {
-			delete nodeAttribute;
-			RETURN_ERROR(error);
-		}
-
-		node->AddAttribute(nodeAttribute);
-
-		return B_OK;
-	}
-
-	virtual status_t HandleEntryDone(BPackageEntry* entry)
-	{
-		return B_OK;
-	}
-
-	virtual status_t HandlePackageAttribute(
-		const BPackageInfoAttributeValue& value)
-	{
-		switch (value.attributeID) {
-			case B_PACKAGE_INFO_NAME:
-				return fPackage->SetName(value.string);
-
-			case B_PACKAGE_INFO_INSTALL_PATH:
-				return fPackage->SetInstallPath(value.string);
-
-			case B_PACKAGE_INFO_VERSION:
-			{
-				Version* version;
-				status_t error = Version::Create(value.version.major,
-					value.version.minor, value.version.micro,
-					value.version.preRelease, value.version.release, version);
-				if (error != B_OK)
-					RETURN_ERROR(error);
-
-				fPackage->SetVersion(version);
-
-				break;
-			}
-
-			case B_PACKAGE_INFO_ARCHITECTURE:
-				if (value.unsignedInt >= B_PACKAGE_ARCHITECTURE_ENUM_COUNT)
-					RETURN_ERROR(B_BAD_VALUE);
-
-				fPackage->SetArchitecture(
-					(BPackageArchitecture)value.unsignedInt);
-				break;
-
-			case B_PACKAGE_INFO_PROVIDES:
-			{
-				// create a version object, if a version is specified
-				Version* version = NULL;
-				if (value.resolvable.haveVersion) {
-					const BPackageVersionData& versionInfo
-						= value.resolvable.version;
-					status_t error = Version::Create(versionInfo.major,
-						versionInfo.minor, versionInfo.micro,
-						versionInfo.preRelease, versionInfo.release, version);
-					if (error != B_OK)
-						RETURN_ERROR(error);
-				}
-				ObjectDeleter versionDeleter(version);
-
-				// create a version object, if a compatible version is specified
-				Version* compatibleVersion = NULL;
-				if (value.resolvable.haveCompatibleVersion) {
-					const BPackageVersionData& versionInfo
-						= value.resolvable.compatibleVersion;
-					status_t error = Version::Create(versionInfo.major,
-						versionInfo.minor, versionInfo.micro,
-						versionInfo.preRelease, versionInfo.release,
-						compatibleVersion);
-					if (error != B_OK)
-						RETURN_ERROR(error);
-				}
-				ObjectDeleter compatibleVersionDeleter(
-					compatibleVersion);
-
-				// create the resolvable
-				Resolvable* resolvable = new(std::nothrow) Resolvable(fPackage);
-				if (resolvable == NULL)
-					RETURN_ERROR(B_NO_MEMORY);
-				ObjectDeleter resolvableDeleter(resolvable);
-
-				status_t error = resolvable->Init(value.resolvable.name,
-					versionDeleter.Detach(), compatibleVersionDeleter.Detach());
-				if (error != B_OK)
-					RETURN_ERROR(error);
-
-				fPackage->AddResolvable(resolvableDeleter.Detach());
-
-				break;
-			}
-
-			case B_PACKAGE_INFO_REQUIRES:
-			{
-				// create the dependency
-				Dependency* dependency = new(std::nothrow) Dependency(fPackage);
-				if (dependency == NULL)
-					RETURN_ERROR(B_NO_MEMORY);
-				ObjectDeleter dependencyDeleter(dependency);
-
-				status_t error = dependency->Init(
-					value.resolvableExpression.name);
-				if (error != B_OK)
-					RETURN_ERROR(error);
-
-				// create a version object, if a version is specified
-				Version* version = NULL;
-				if (value.resolvableExpression.haveOpAndVersion) {
-					const BPackageVersionData& versionInfo
-						= value.resolvableExpression.version;
-					status_t error = Version::Create(versionInfo.major,
-						versionInfo.minor, versionInfo.micro,
-						versionInfo.preRelease, versionInfo.release, version);
-					if (error != B_OK)
-						RETURN_ERROR(error);
-
-					dependency->SetVersionRequirement(
-						value.resolvableExpression.op, version);
-				}
-
-				fPackage->AddDependency(dependencyDeleter.Detach());
-
-				break;
-			}
-
-			default:
-				break;
-		}
-
-		return B_OK;
-	}
-
-	virtual void HandleErrorOccurred()
-	{
-		fErrorOccurred = true;
-	}
-
-private:
-	Package*	fPackage;
-	bool		fErrorOccurred;
-};
-
-
 // #pragma mark - DomainDirectoryListener
 
 
@@ -1039,36 +768,6 @@ Volume::_RemovePackageDomain(PackageDomain* domain)
 }
 
 
-status_t
-Volume::_LoadPackage(Package* package)
-{
-	// open package file
-	int fd = package->Open();
-	if (fd < 0)
-		RETURN_ERROR(fd);
-	PackageCloser packageCloser(package);
-
-	// initialize package reader
-	PackageLoaderErrorOutput errorOutput(package);
-	PackageReaderImpl packageReader(&errorOutput);
-	status_t error = packageReader.Init(fd, false);
-	if (error != B_OK)
-		RETURN_ERROR(error);
-
-	// parse content
-	PackageLoaderContentHandler handler(package);
-	error = handler.Init();
-	if (error != B_OK)
-		RETURN_ERROR(error);
-
-	error = packageReader.ParseContent(&handler);
-	if (error != B_OK)
-		RETURN_ERROR(error);
-
-	return B_OK;
-}
-
-
 status_t
 Volume::_AddPackageContent(Package* package, bool notify)
 {
@@ -1613,34 +1312,18 @@ Volume::_DomainEntryCreated(PackageDomain* domain, dev_t deviceID,
 		return;
 	}
 
-	// check whether the entry is a file
-	struct stat st;
-	if (fstatat(domain->DirectoryFD(), name, &st, 0) < 0
-		|| !S_ISREG(st.st_mode)) {
-		return;
-	}
-
-	// create a package
-	Package* package = new(std::nothrow) Package(domain, st.st_dev, st.st_ino);
-	if (package == NULL)
+	Package* package;
+	if (_LoadPackage(domain, name, package) != B_OK)
 		return;
 	BReference packageReference(package, true);
 
-	status_t error = package->Init(name);
-	if (error != B_OK)
-		return;
-
-	error = _LoadPackage(package);
-	if (error != B_OK)
-		return;
-
 	VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
 	VolumeWriteLocker volumeLocker(this);
 	domain->AddPackage(package);
 
 	// add the package to the node tree
 	if (addContent) {
-		error = _AddPackageContent(package, notify);
+		status_t error = _AddPackageContent(package, notify);
 		if (error != B_OK) {
 			domain->RemovePackage(package);
 			return;
@@ -1682,6 +1365,36 @@ Volume::_DomainEntryMoved(PackageDomain* domain, dev_t deviceID,
 }
 
 
+/*static*/ status_t
+Volume::_LoadPackage(PackageDomain* domain, const char* name,
+	Package*& _package)
+{
+	// check whether the entry is a file
+	struct stat st;
+	if (fstatat(domain->DirectoryFD(), name, &st, 0) < 0
+		|| !S_ISREG(st.st_mode)) {
+		return B_BAD_VALUE;
+	}
+
+	// create a package
+	Package* package = new(std::nothrow) Package(domain, st.st_dev, st.st_ino);
+	if (package == NULL)
+		RETURN_ERROR(B_NO_MEMORY);
+	BReference packageReference(package, true);
+
+	status_t error = package->Init(name);
+	if (error != B_OK)
+		return error;
+
+	error = package->Load();
+	if (error != B_OK)
+		return error;
+
+	_package = packageReference.Detach();
+	return B_OK;
+}
+
+
 status_t
 Volume::_InitMountType(const char* mountType)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index 38a6097978..b32736a8e9 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -132,7 +132,6 @@ private:
 			status_t			_AddPackageDomain(PackageDomain* domain,
 									bool notify);
 			void				_RemovePackageDomain(PackageDomain* domain);
-			status_t			_LoadPackage(Package* package);
 
 			status_t			_AddPackageContent(Package* package,
 									bool notify);
@@ -177,6 +176,9 @@ private:
 									ino_t nodeID, const char* fromName,
 									const char* name, bool notify);
 
+	static	status_t			_LoadPackage(PackageDomain* domain,
+									const char* name, Package*& _package);
+
 			status_t			_InitMountType(const char* mountType);
 			status_t			_CreateShineThroughDirectory(Directory* parent,
 									const char* name, Directory*& _directory);

From 17bb54dc38958fa7fc945346b3799350fc25e5b3 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 7 Apr 2013 11:53:50 +0200
Subject: [PATCH 0364/1170] packagefs: ioctls for getting and changing package
 activation

* Add PACKAGE_FS_OPERATION_GET_PACKAGE_INFOS which returns the node refs
  of all packages activated.
* Add PACKAGE_FS_OPERATION_CHANGE_ACTIVATION to activate/deactivate
  multiple packages.
---
 headers/private/package/packagefs.h           |  55 ++-
 .../kernel/file_systems/packagefs/Volume.cpp  | 347 +++++++++++++++++-
 .../kernel/file_systems/packagefs/Volume.h    |   4 +
 3 files changed, 403 insertions(+), 3 deletions(-)

diff --git a/headers/private/package/packagefs.h b/headers/private/package/packagefs.h
index 790ac3a1ce..29ef4a11c7 100644
--- a/headers/private/package/packagefs.h
+++ b/headers/private/package/packagefs.h
@@ -21,10 +21,14 @@ enum PackageFSMountType {
 
 
 enum {
-	PACKAGE_FS_OPERATION_GET_VOLUME_INFO	= B_DEVICE_OP_CODES_END + 1
+	PACKAGE_FS_OPERATION_GET_VOLUME_INFO		= B_DEVICE_OP_CODES_END + 1,
+	PACKAGE_FS_OPERATION_GET_PACKAGE_INFOS,
+	PACKAGE_FS_OPERATION_CHANGE_ACTIVATION
 };
 
 
+// PACKAGE_FS_OPERATION_GET_VOLUME_INFO
+
 struct PackageFSVolumeInfo {
 	PackageFSMountType	mountType;
 
@@ -32,6 +36,55 @@ struct PackageFSVolumeInfo {
 	// for the three standard volumes)
 	dev_t				rootDeviceID;
 	ino_t				rootDirectoryID;
+
+	// device and node id of the volume's packages directory
+	dev_t				packagesDeviceID;
+	ino_t				packagesDirectoryID;
+};
+
+
+// PACKAGE_FS_OPERATION_GET_PACKAGE_INFOS
+
+struct PackageFSPackageInfo {
+	// node_ref of the package file
+	dev_t							packageDeviceID;
+	ino_t							packageNodeID;
+};
+
+struct PackageFSGetPackageInfosRequest {
+	// Filled in by the FS. packageCount is set to the actual package count,
+	// even if it is greater than the array, so the caller can determine whether
+	// the array was large enough.
+	uint32							packageCount;
+	PackageFSPackageInfo			infos[1];
+};
+
+
+// PACKAGE_FS_OPERATION_CHANGE_ACTIVATION
+
+enum PackageFSActivationChangeType {
+	PACKAGE_FS_ACTIVATE_PACKAGE,
+	PACKAGE_FS_DEACTIVATE_PACKAGE,
+	PACKAGE_FS_REACTIVATE_PACKAGE
+};
+
+struct PackageFSActivationChangeItem {
+	PackageFSActivationChangeType	type;
+
+	// node_ref of the package file
+	dev_t							packageDeviceID;
+	ino_t							packageNodeID;
+
+	// entry_ref of the package file
+	uint32							nameLength;
+	dev_t							parentDeviceID;
+	ino_t							parentDirectoryID;
+	char							name[1];
+};
+
+struct PackageFSActivationChangeRequest {
+	uint32							itemCount;
+	PackageFSActivationChangeItem	items[1];
 };
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index d0ed67e3d5..31412bd0cc 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -10,6 +10,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -59,6 +60,9 @@ const char* const kCommonShineThroughDirectories[] = {
 const char* const* kHomeShineThroughDirectories
 	= kCommonShineThroughDirectories;
 
+// sanity limit for activation change request
+const size_t kMaxActivationRequestSize = 10 * 1024 * 1024;
+
 
 // #pragma mark - Job
 
@@ -194,6 +198,130 @@ private:
 };
 
 
+// #pragma mark - ActivationChangeRequest
+
+
+struct Volume::ActivationChangeRequest {
+public:
+	struct Iterator {
+		Iterator()
+			:
+			fRequest(NULL),
+			fNextItem(NULL),
+			fNextIndex(0)
+		{
+		}
+
+		Iterator(PackageFSActivationChangeRequest* request)
+			:
+			fRequest(request),
+			fNextItem(NULL),
+			fNextIndex(0)
+		{
+			if (fRequest != NULL && fRequest->itemCount > 0)
+				fNextItem = fRequest->items;
+		}
+
+		bool HasNext() const
+		{
+			return fNextItem != NULL;
+		}
+
+		PackageFSActivationChangeItem* Next()
+		{
+			if (fNextItem == NULL)
+				return NULL;
+
+			PackageFSActivationChangeItem* item = fNextItem;
+			fNextIndex++;
+			fNextItem = fNextIndex < fRequest->itemCount
+				? _NextItem(fNextItem) : NULL;
+			return item;
+		}
+
+	private:
+		PackageFSActivationChangeRequest*	fRequest;
+		PackageFSActivationChangeItem*		fNextItem;
+		uint32								fNextIndex;
+	};
+
+public:
+	ActivationChangeRequest()
+		:
+		fRequest(NULL),
+		fRequestSize(0)
+	{
+	}
+
+	~ActivationChangeRequest()
+	{
+		free(fRequest);
+	}
+
+	status_t Init(const void* userRequest, size_t requestSize)
+	{
+		// copy request to kernel
+		if (requestSize > kMaxActivationRequestSize)
+			RETURN_ERROR(B_BAD_VALUE);
+
+		fRequest = (PackageFSActivationChangeRequest*)malloc(requestSize);
+		if (fRequest == NULL)
+			RETURN_ERROR(B_NO_MEMORY);
+		fRequestSize = requestSize;
+
+		status_t error = user_memcpy(fRequest, userRequest, fRequestSize);
+		if (error != B_OK)
+			RETURN_ERROR(error);
+
+		// check the validity of the items
+		addr_t requestEnd = (addr_t)fRequest + fRequestSize;
+		uint32 itemCount = 0;
+		PackageFSActivationChangeItem* item = fRequest->items;
+		while (itemCount < fRequest->itemCount) {
+			if ((addr_t)item + sizeof(PackageFSActivationChangeItem)
+					> requestEnd
+				|| item->nameLength > B_FILE_NAME_LENGTH
+				|| (addr_t)item->name + item->nameLength > requestEnd
+				|| item->name[item->nameLength] != '\0'
+				|| strlen(item->name) != item->nameLength) {
+				RETURN_ERROR(B_BAD_VALUE);
+			}
+
+			itemCount++;
+			item = _NextItem(item);
+		}
+
+		return B_OK;
+	}
+
+	uint32 CountItems() const
+	{
+		return fRequest->itemCount;
+	}
+
+	Iterator GetIterator() const
+	{
+		return Iterator(fRequest);
+	}
+
+private:
+	friend class Iterator;
+		// for GCC 2
+
+private:
+	static inline PackageFSActivationChangeItem* _NextItem(
+		PackageFSActivationChangeItem* item)
+	{
+		return (PackageFSActivationChangeItem*)_ALIGN(
+			(addr_t)item->name + item->nameLength);
+	}
+
+private:
+	PackageFSActivationChangeRequest*	fRequest;
+	size_t								fRequestSize;
+};
+
+
 // #pragma mark - Volume
 
 
@@ -464,13 +592,65 @@ Volume::IOCtl(Node* node, uint32 operation, void* buffer, size_t size)
 		case PACKAGE_FS_OPERATION_GET_VOLUME_INFO:
 		{
 			if (size != sizeof(PackageFSVolumeInfo))
-				return B_BAD_VALUE;
+				RETURN_ERROR(B_BAD_VALUE);
+
+			VolumeReadLocker volumeReadLocker(this);
 
 			PackageFSVolumeInfo info;
 			info.mountType = fMountType;
 			info.rootDeviceID = fPackageFSRoot->DeviceID();
 			info.rootDirectoryID = fPackageFSRoot->NodeID();
-			return user_memcpy(buffer, &info, sizeof(info));
+
+			PackageDomain* domain = fPackageDomains.Head();
+			info.packagesDeviceID = domain != NULL ? domain->DeviceID() : -1;
+			info.packagesDirectoryID = domain != NULL ? domain->NodeID() : -1;
+
+			RETURN_ERROR(user_memcpy(buffer, &info, sizeof(info)));
+		}
+
+		case PACKAGE_FS_OPERATION_GET_PACKAGE_INFOS:
+		{
+			if (size < sizeof(PackageFSGetPackageInfosRequest))
+				RETURN_ERROR(B_BAD_VALUE);
+
+			PackageFSGetPackageInfosRequest* request
+				= (PackageFSGetPackageInfosRequest*)buffer;
+
+			VolumeReadLocker volumeReadLocker(this);
+
+			PackageDomain* domain = fPackageDomains.Head();
+			if (domain == NULL)
+				RETURN_ERROR(B_BAD_VALUE);
+
+			uint32 packageIndex = 0;
+			for (PackageFileNameHashTable::Iterator it
+					= domain->Packages().GetIterator(); it.HasNext();
+				packageIndex++) {
+				Package* package = it.Next();
+				PackageFSPackageInfo info;
+				info.packageDeviceID = package->DeviceID();
+				info.packageNodeID = package->NodeID();
+				PackageFSPackageInfo* userInfo = request->infos + packageIndex;
+				if (addr_t(userInfo + 1) > (addr_t)buffer + size)
+					break;
+
+				if (user_memcpy(userInfo, &info, sizeof(info)) != B_OK)
+					return B_BAD_ADDRESS;
+			}
+
+			uint32 packageCount = domain->Packages().CountElements();
+			RETURN_ERROR(user_memcpy(&request->packageCount, &packageCount,
+				sizeof(packageCount)));
+		}
+
+		case PACKAGE_FS_OPERATION_CHANGE_ACTIVATION:
+		{
+			ActivationChangeRequest request;
+			status_t error = request.Init(buffer, size);
+			if (error != B_OK)
+				RETURN_ERROR(B_BAD_VALUE);
+
+			return _ChangeActivation(request);
 		}
 
 		default:
@@ -1395,6 +1575,169 @@ Volume::_LoadPackage(PackageDomain* domain, const char* name,
 }
 
 
+status_t
+Volume::_ChangeActivation(ActivationChangeRequest& request)
+{
+// TODO: Would need locking, but will be irrelevant when removing the support
+// for multiple package domains.
+	PackageDomain* domain = fPackageDomains.Head();
+	if (domain == NULL)
+		RETURN_ERROR(B_BAD_VALUE);
+
+	// first check the request
+	int32 newPackageCount = 0;
+	int32 oldPackageCount = 0;
+	{
+		VolumeReadLocker volumeLocker(this);
+
+		for (ActivationChangeRequest::Iterator it = request.GetIterator();
+			it.HasNext();) {
+			PackageFSActivationChangeItem* item = it.Next();
+			if (item->parentDeviceID != domain->DeviceID()
+				|| item->parentDirectoryID != domain->NodeID()) {
+				ERROR("Volume::_ChangeActivation(): mismatching packages "
+					"domain\n");
+				RETURN_ERROR(B_BAD_VALUE);
+			}
+
+			Package* package = domain->FindPackage(item->name);
+// TODO: We should better look up the package by node_ref!
+			if (item->type == PACKAGE_FS_ACTIVATE_PACKAGE) {
+				if (package != NULL) {
+					ERROR("Volume::_ChangeActivation(): package to activate "
+						"already activated: \"%s\"\n", item->name);
+					RETURN_ERROR(B_BAD_VALUE);
+				}
+				newPackageCount++;
+			} else if (item->type == PACKAGE_FS_DEACTIVATE_PACKAGE) {
+				if (package == NULL) {
+					ERROR("Volume::_ChangeActivation(): package to deactivate "
+						"not found: \"%s\"\n", item->name);
+					RETURN_ERROR(B_BAD_VALUE);
+				}
+				oldPackageCount++;
+			} else if (item->type == PACKAGE_FS_REACTIVATE_PACKAGE) {
+				if (package == NULL) {
+					ERROR("Volume::_ChangeActivation(): package to reactivate "
+						"not found: \"%s\"\n", item->name);
+					RETURN_ERROR(B_BAD_VALUE);
+				}
+				oldPackageCount++;
+				newPackageCount++;
+			} else
+				RETURN_ERROR(B_BAD_VALUE);
+		}
+	}
+INFORM("Volume::_ChangeActivation(): %" B_PRId32 " new packages, %" B_PRId32 " old packages\n", newPackageCount, oldPackageCount);
+
+	// Things look good so far -- allocate reference arrays for the packages to
+	// add and remove.
+	BReference* newPackageReferences
+		= new(std::nothrow) BReference[newPackageCount];
+	if (newPackageReferences == NULL)
+		RETURN_ERROR(B_NO_MEMORY);
+	ArrayDeleter > newPackageReferencesDeleter(
+			newPackageReferences);
+
+	BReference* oldPackageReferences
+		= new(std::nothrow) BReference[oldPackageCount];
+	if (oldPackageReferences == NULL)
+		RETURN_ERROR(B_NO_MEMORY);
+	ArrayDeleter > oldPackageReferencesDeleter(
+			oldPackageReferences);
+
+	// load all new packages
+	int32 newPackageIndex = 0;
+	for (ActivationChangeRequest::Iterator it = request.GetIterator();
+		it.HasNext();) {
+		PackageFSActivationChangeItem* item = it.Next();
+
+		if (item->type != PACKAGE_FS_ACTIVATE_PACKAGE
+			&& item->type != PACKAGE_FS_REACTIVATE_PACKAGE) {
+			continue;
+		}
+
+		Package* package;
+		status_t error = _LoadPackage(domain, item->name, package);
+		if (error != B_OK) {
+			ERROR("Volume::_ChangeActivation(): failed to load package "
+				"\"%s\"\n", item->name);
+			RETURN_ERROR(error);
+		}
+
+		newPackageReferences[newPackageIndex++].SetTo(package, true);
+	}
+
+	// apply the changes
+	VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
+	VolumeWriteLocker volumeLocker(this);
+// TODO: Add a change counter to Volume, so we can easily check whether
+// everything is still the same.
+
+	// remove the old packages
+	int32 oldPackageIndex = 0;
+	for (ActivationChangeRequest::Iterator it = request.GetIterator();
+		it.HasNext();) {
+		PackageFSActivationChangeItem* item = it.Next();
+
+		if (item->type != PACKAGE_FS_DEACTIVATE_PACKAGE
+			&& item->type != PACKAGE_FS_REACTIVATE_PACKAGE) {
+			continue;
+		}
+
+		Package* package = domain->FindPackage(item->name);
+// TODO: We should better look up the package by node_ref!
+		oldPackageReferences[oldPackageIndex++].SetTo(package);
+		_RemovePackageContent(package, NULL, true);
+		domain->RemovePackage(package);
+INFORM("package \"%s\" deactivated\n", package->FileName());
+	}
+// TODO: Since package removal cannot fail, consider adding the new packages
+// first. The reactivation case may make that problematic, since two packages
+// with the same name would be active after activating the new one. Check!
+
+	// add the new packages
+	status_t error = B_OK;
+	for (newPackageIndex = 0; newPackageIndex < newPackageCount;
+		newPackageIndex++) {
+		Package* package = newPackageReferences[newPackageIndex];
+		domain->AddPackage(package);
+
+		// add the package to the node tree
+		error = _AddPackageContent(package, true);
+		if (error != B_OK) {
+			domain->RemovePackage(package);
+			break;
+		}
+INFORM("package \"%s\" activated\n", package->FileName());
+	}
+
+	// Try to roll back the changes, if an error occurred.
+	if (error != B_OK) {
+		for (int32 i = newPackageIndex - 1; i >= 0; i--) {
+			Package* package = newPackageReferences[i];
+			_RemovePackageContent(package, NULL, true);
+			domain->RemovePackage(package);
+		}
+
+		for (int32 i = oldPackageCount - 1; i >= 0; i--) {
+			Package* package = oldPackageReferences[i];
+			domain->AddPackage(package);
+
+			if (_AddPackageContent(package, true) != B_OK) {
+				// nothing we can do here
+				ERROR("Volume::_ChangeActivation(): failed to roll back "
+					"deactivation of package \"%s\" after error\n",
+		  			package->FileName());
+				domain->RemovePackage(package);
+			}
+		}
+	}
+
+	return error;
+}
+
+
 status_t
 Volume::_InitMountType(const char* mountType)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index b32736a8e9..66c12d92a1 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -112,6 +112,7 @@ private:
 			struct PackageLoaderContentHandler;
 			struct DomainDirectoryListener;
 			struct ShineThroughDirectory;
+			struct ActivationChangeRequest;
 
 			friend struct AddPackageDomainJob;
 			friend struct DomainDirectoryEventJob;
@@ -179,6 +180,9 @@ private:
 	static	status_t			_LoadPackage(PackageDomain* domain,
 									const char* name, Package*& _package);
 
+			status_t			_ChangeActivation(
+									ActivationChangeRequest& request);
+
 			status_t			_InitMountType(const char* mountType);
 			status_t			_CreateShineThroughDirectory(Directory* parent,
 									const char* name, Directory*& _directory);

From 3d53bd473b49aa91a9611dfe6500492500e1e8c6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 7 Apr 2013 12:02:18 +0200
Subject: [PATCH 0365/1170] package daemon: Add package monitoring and
 de-/activation

* packagefs: Disable (comment out) node monitoring of the packages
  directory.
* package daemon:
  - When a packagefs volume is added load the respective packages
    directory and get from the volume which of the packages are
    activated.
  - Add node monitoring for the packages directory and
    activate/deactivate packages as packages are added/removed.
---
 .../kernel/file_systems/packagefs/Volume.cpp  |  17 +-
 src/servers/package/Jamfile                   |   3 +-
 src/servers/package/Package.cpp               |  67 +++
 src/servers/package/Package.h                 | 113 +++++
 src/servers/package/PackageDaemon.cpp         |  50 ++-
 src/servers/package/PackageDaemon.h           |   5 +-
 src/servers/package/Root.cpp                  |  13 +-
 src/servers/package/Root.h                    |  15 +-
 src/servers/package/Volume.cpp                | 396 ++++++++++++++++--
 src/servers/package/Volume.h                  |  48 ++-
 10 files changed, 639 insertions(+), 88 deletions(-)
 create mode 100644 src/servers/package/Package.cpp
 create mode 100644 src/servers/package/Package.h

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 31412bd0cc..934f7f766e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -161,14 +161,15 @@ struct Volume::DomainDirectoryListener : NotificationListener {
 	virtual void EventOccurred(NotificationService& service,
 		const KMessage* event)
 	{
-		DomainDirectoryEventJob* job = new(std::nothrow)
-			DomainDirectoryEventJob(fVolume, fDomain);
-		if (job == NULL || job->Init(event)) {
-			delete job;
-			return;
-		}
-
-		fVolume->_PushJob(job);
+// TODO: Remove!
+// 		DomainDirectoryEventJob* job = new(std::nothrow)
+// 			DomainDirectoryEventJob(fVolume, fDomain);
+// 		if (job == NULL || job->Init(event)) {
+// 			delete job;
+// 			return;
+// 		}
+// 
+// 		fVolume->_PushJob(job);
 	}
 
 private:
diff --git a/src/servers/package/Jamfile b/src/servers/package/Jamfile
index 099f966092..bc6bc7d7d1 100644
--- a/src/servers/package/Jamfile
+++ b/src/servers/package/Jamfile
@@ -1,11 +1,12 @@
 SubDir HAIKU_TOP src servers package ;
 
 UsePrivateSystemHeaders ;
-UsePrivateHeaders app package shared ;
+UsePrivateHeaders app kernel package shared ;
 
 Server package_daemon
  	:
  	DebugSupport.cpp
+ 	Package.cpp
  	PackageDaemon.cpp
  	Root.cpp
  	Volume.cpp
diff --git a/src/servers/package/Package.cpp b/src/servers/package/Package.cpp
new file mode 100644
index 0000000000..c88767ee0d
--- /dev/null
+++ b/src/servers/package/Package.cpp
@@ -0,0 +1,67 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include "Package.h"
+
+#include 
+
+#include 
+
+#include 
+
+#include "DebugSupport.h"
+
+
+Package::Package()
+	:
+	fNodeRef(),
+	fFileName(),
+	fInfo(),
+	fActive(false),
+	fFileNameHashTableNext(NULL),
+	fNodeRefHashTableNext(NULL)
+{
+}
+
+
+Package::~Package()
+{
+}
+
+
+status_t
+Package::Init(const entry_ref& entryRef)
+{
+	// init the file name
+	fFileName = entryRef.name;
+	if (fFileName.IsEmpty())
+		RETURN_ERROR(B_NO_MEMORY);
+
+	// open the file and get the node_ref
+	BFile file;
+	status_t error = file.SetTo(&entryRef, B_READ_ONLY);
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	error = file.GetNodeRef(&fNodeRef);
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	// get the package info
+	int fd = file.Dup();
+	if (fd < 0)
+		RETURN_ERROR(error);
+	FileDescriptorCloser fdCloser(fd);
+
+	error = fInfo.ReadFromPackageFile(fd);
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	return B_OK;
+}
diff --git a/src/servers/package/Package.h b/src/servers/package/Package.h
new file mode 100644
index 0000000000..b93fed8a2f
--- /dev/null
+++ b/src/servers/package/Package.h
@@ -0,0 +1,113 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef PACKAGE_H
+#define PACKAGE_H
+
+
+#include 
+#include 
+#include 
+
+#include 
+
+
+using namespace BPackageKit;
+
+
+class Package {
+public:
+								Package();
+								~Package();
+
+			status_t			Init(const entry_ref& entryRef);
+
+			const node_ref&		NodeRef() const
+									{ return fNodeRef; }
+			const BString&		FileName() const
+									{ return fFileName; }
+
+			const BPackageInfo & Info() const
+									{ return fInfo; }
+
+			bool				IsActive() const
+									{ return fActive; }
+			void				SetActive(bool active)
+									{ fActive = active; }
+
+			Package*&			FileNameHashTableNext()
+									{ return fFileNameHashTableNext; }
+			Package*&			NodeRefHashTableNext()
+									{ return fNodeRefHashTableNext; }
+
+private:
+			node_ref			fNodeRef;
+			BString				fFileName;
+			BPackageInfo		fInfo;
+			bool				fActive;
+			Package*			fFileNameHashTableNext;
+			Package*			fNodeRefHashTableNext;
+};
+
+
+struct PackageFileNameHashDefinition {
+	typedef const char*		KeyType;
+	typedef	Package			ValueType;
+
+	size_t HashKey(const char* key) const
+	{
+		return BString::HashValue(key);
+	}
+
+	size_t Hash(const Package* value) const
+	{
+		return HashKey(value->FileName());
+	}
+
+	bool Compare(const char* key, const Package* value) const
+	{
+		return value->FileName() == key;
+	}
+
+	Package*& GetLink(Package* value) const
+	{
+		return value->FileNameHashTableNext();
+	}
+};
+
+
+struct PackageNodeRefHashDefinition {
+	typedef node_ref		KeyType;
+	typedef	Package			ValueType;
+
+	size_t HashKey(const node_ref& key) const
+	{
+		return (size_t)key.device + 17 * (size_t)key.node;
+	}
+
+	size_t Hash(const Package* value) const
+	{
+		return HashKey(value->NodeRef());
+	}
+
+	bool Compare(const node_ref& key, const Package* value) const
+	{
+		return key == value->NodeRef();
+	}
+
+	Package*& GetLink(Package* value) const
+	{
+		return value->NodeRefHashTableNext();
+	}
+};
+
+
+typedef BOpenHashTable PackageFileNameHashTable;
+typedef BOpenHashTable PackageNodeRefHashTable;
+
+
+#endif	// PACKAGE_H
diff --git a/src/servers/package/PackageDaemon.cpp b/src/servers/package/PackageDaemon.cpp
index 0942049d0f..8229e4877c 100644
--- a/src/servers/package/PackageDaemon.cpp
+++ b/src/servers/package/PackageDaemon.cpp
@@ -69,6 +69,7 @@ PackageDaemon::MessageReceived(BMessage* message)
 			int32 opcode;
 			if (message->FindInt32("opcode", &opcode) != B_OK)
 				break;
+
 			if (opcode == B_DEVICE_MOUNTED)
 				_HandleVolumeMounted(message);
 			else if (opcode == B_DEVICE_UNMOUNTED)
@@ -94,27 +95,14 @@ PackageDaemon::_RegisterVolume(dev_t deviceID)
 	if (strcmp(info.fsh_name, "packagefs") != 0)
 		RETURN_ERROR(B_BAD_VALUE);
 
-	// open the root directory of the volume
-	node_ref nodeRef;
-	nodeRef.device = info.dev;
-	nodeRef.node = info.root;
-	BDirectory directory;
-	error = directory.SetTo(&nodeRef);
-	if (error != B_OK) {
-		ERROR("PackageDaemon::_RegisterVolume(): failed to open root: %s\n",
-			strerror(error));
-		return error;
-	}
-
 	// create a volume
 	Volume* volume = new(std::nothrow) Volume;
 	if (volume == NULL)
 		RETURN_ERROR(B_NO_MEMORY);
 	ObjectDeleter volumeDeleter(volume);
 
-	dev_t rootDeviceID;
-	ino_t rootNodeID;
-	error = volume->Init(directory, rootDeviceID, rootNodeID);
+	node_ref rootRef;
+	error = volume->Init(node_ref(info.dev, info.root), rootRef);
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
@@ -127,7 +115,7 @@ PackageDaemon::_RegisterVolume(dev_t deviceID)
 
 	// get the root for the volume and register it
 	Root* root;
-	error = _GetOrCreateRoot(rootDeviceID, rootNodeID, root);
+	error = _GetOrCreateRoot(rootRef, root);
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
@@ -138,6 +126,19 @@ PackageDaemon::_RegisterVolume(dev_t deviceID)
 	}
 	volumeDeleter.Detach();
 
+	AddHandler(volume);
+
+	// node-monitor the volume's packages directory
+	error = watch_node(&volume->PackagesDirectoryRef(), B_WATCH_DIRECTORY,
+		BMessenger(volume, this));
+	if (error != B_OK) {
+		ERROR("PackageDaemon::_RegisterVolume(): failed to start watching the "
+			"packages directory of the volume at \"%s\": %s\n",
+			volume->Path().String(), strerror(error));
+		// Not good, but not fatal. Only the manual package operations in the
+		// packages directory won't work correctly.
+	}
+
 	INFORM("volume at \"%s\" registered\n", volume->Path().String());
 
 	return B_OK;
@@ -147,6 +148,10 @@ PackageDaemon::_RegisterVolume(dev_t deviceID)
 void
 PackageDaemon::_UnregisterVolume(Volume* volume)
 {
+	stop_watching(BMessenger(volume, this));
+
+	RemoveHandler(volume);
+
 	Root* root = volume->GetRoot();
 	root->UnregisterVolume(volume);
 
@@ -158,9 +163,9 @@ PackageDaemon::_UnregisterVolume(Volume* volume)
 
 
 status_t
-PackageDaemon::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, Root*& _root)
+PackageDaemon::_GetOrCreateRoot(const node_ref& nodeRef, Root*& _root)
 {
-	Root* root = _FindRoot(deviceID, nodeID);
+	Root* root = _FindRoot(nodeRef);
 	if (root != NULL) {
 		root->AcquireReference();
 	} else {
@@ -169,7 +174,7 @@ PackageDaemon::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, Root*& _root)
 			RETURN_ERROR(B_NO_MEMORY);
 		ObjectDeleter rootDeleter(root);
 
-		status_t error = root->Init(deviceID, nodeID);
+		status_t error = root->Init(nodeRef);
 		if (error != B_OK)
 			RETURN_ERROR(error);
 
@@ -179,7 +184,8 @@ PackageDaemon::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, Root*& _root)
 		rootDeleter.Detach();
 
 		INFORM("root at \"%s\" (device: %" B_PRIdDEV ", node: %" B_PRIdINO ") "
-			"registered\n", root->Path().String(), deviceID, nodeID);
+			"registered\n", root->Path().String(), nodeRef.device,
+			nodeRef.node);
 	}
 
 	_root = root;
@@ -188,10 +194,10 @@ PackageDaemon::_GetOrCreateRoot(dev_t deviceID, ino_t nodeID, Root*& _root)
 
 
 Root*
-PackageDaemon::_FindRoot(dev_t deviceID, ino_t nodeID) const
+PackageDaemon::_FindRoot(const node_ref& nodeRef) const
 {
 	for (int32 i = 0; Root* root = fRoots.ItemAt(i); i++) {
-		if (root->DeviceID() == deviceID && root->NodeID() == nodeID)
+		if (root->NodeRef() == nodeRef)
 			return root;
 	}
 
diff --git a/src/servers/package/PackageDaemon.h b/src/servers/package/PackageDaemon.h
index 86c6f4c2c0..c2ef13ff2a 100644
--- a/src/servers/package/PackageDaemon.h
+++ b/src/servers/package/PackageDaemon.h
@@ -10,6 +10,7 @@
 
 
 #include 
+#include 
 #include 
 #include 
 
@@ -36,9 +37,9 @@ private:
 			status_t			_RegisterVolume(dev_t device);
 			void				_UnregisterVolume(Volume* volume);
 
-			status_t			_GetOrCreateRoot(dev_t deviceID, ino_t nodeID,
+			status_t			_GetOrCreateRoot(const node_ref& nodeRef,
 									Root*& _root);
-			Root*				_FindRoot(dev_t deviceID, ino_t nodeID) const;
+			Root*				_FindRoot(const node_ref& nodeRef) const;
 			void				_PutRoot(Root* root);
 
 			Volume*				_FindVolume(dev_t deviceID) const;
diff --git a/src/servers/package/Root.cpp b/src/servers/package/Root.cpp
index bf7fec9939..d72a5041ef 100644
--- a/src/servers/package/Root.cpp
+++ b/src/servers/package/Root.cpp
@@ -19,8 +19,7 @@
 
 Root::Root()
 	:
-	fDeviceID(-1),
-	fNodeID(-1),
+	fNodeRef(),
 	fPath(),
 	fSystemVolume(NULL),
 	fCommonVolume(NULL),
@@ -35,17 +34,13 @@ Root::~Root()
 
 
 status_t
-Root::Init(dev_t deviceID, ino_t nodeID)
+Root::Init(const node_ref& nodeRef)
 {
-	fDeviceID = deviceID;
-	fNodeID = nodeID;
+	fNodeRef = nodeRef;
 
 	// get the path
-	node_ref nodeRef;
-	nodeRef.device = fDeviceID;
-	nodeRef.node = fNodeID;
 	BDirectory directory;
-	status_t error = directory.SetTo(&nodeRef);
+	status_t error = directory.SetTo(&fNodeRef);
 	if (error != B_OK) {
 		ERROR("Root::Init(): failed to open directory: %s\n", strerror(error));
 		return error;
diff --git a/src/servers/package/Root.h b/src/servers/package/Root.h
index 940f99c27f..8afa89cf14 100644
--- a/src/servers/package/Root.h
+++ b/src/servers/package/Root.h
@@ -9,7 +9,7 @@
 #define ROOT_H
 
 
-#include 
+#include 
 #include 
 
 #include 
@@ -25,12 +25,12 @@ public:
 								Root();
 	virtual						~Root();
 
-			status_t			Init(dev_t deviceID, ino_t nodeID);
+			status_t			Init(const node_ref& nodeRef);
 
-			dev_t				DeviceID() const	{ return fDeviceID; }
-			ino_t				NodeID() const		{ return fNodeID; }
-			const BString&		Path() const
-									{ return fPath; }
+			const node_ref&		NodeRef() const		{ return fNodeRef; }
+			dev_t				DeviceID() const	{ return fNodeRef.device; }
+			ino_t				NodeID() const		{ return fNodeRef.node; }
+			const BString&		Path() const		{ return fPath; }
 
 			status_t			RegisterVolume(Volume* volume);
 			void				UnregisterVolume(Volume* volume);
@@ -44,8 +44,7 @@ private:
 			Volume**			_GetVolume(PackageFSMountType mountType);
 
 private:
-			dev_t				fDeviceID;
-			ino_t				fNodeID;
+			node_ref			fNodeRef;
 			BString				fPath;
 			Volume*				fSystemVolume;
 			Volume*				fCommonVolume;
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index 4d17279fc0..526a7ed2bf 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -10,38 +10,67 @@
 #include "Volume.h"
 
 #include 
+#include 
 #include 
 #include 
 
 #include 
 #include 
+#include 
 #include 
 
+#include 
+
 #include "DebugSupport.h"
 
 
 Volume::Volume()
 	:
+	BHandler(),
 	fPath(),
 	fMountType(PACKAGE_FS_MOUNT_TYPE_CUSTOM),
-	fDeviceID(-1),
-	fRootDirectoryID(1),
-	fRoot(NULL)
+	fRootDirectoryRef(),
+	fPackagesDirectoryRef(),
+	fRoot(NULL),
+	fPackagesByFileName(),
+	fPackagesByNodeRef()
 {
 }
 
 
 Volume::~Volume()
 {
+	fPackagesByFileName.Clear();
+
+	Package* package = fPackagesByNodeRef.Clear(true);
+	while (package != NULL) {
+		Package* next = package->NodeRefHashTableNext();
+		delete package;
+		package = next;
+	}
 }
 
 
 status_t
-Volume::Init(BDirectory& directory, dev_t& _rootDeviceID, ino_t& _rootNodeID)
+Volume::Init(const node_ref& rootDirectoryRef, node_ref& _packageRootRef)
 {
+	if (fPackagesByFileName.Init() != B_OK || fPackagesByNodeRef.Init() != B_OK)
+		RETURN_ERROR(B_NO_MEMORY);
+
+	fRootDirectoryRef = rootDirectoryRef;
+
+	// open the root directory
+	BDirectory directory;
+	status_t error = directory.SetTo(&fRootDirectoryRef);
+	if (error != B_OK) {
+		ERROR("Volume::Init(): failed to open root directory: %s\n",
+			strerror(error));
+		RETURN_ERROR(error);
+	}
+
 	// get the directory path
 	BEntry entry;
-	status_t error = directory.GetEntry(&entry);
+	error = directory.GetEntry(&entry);
 
 	BPath path;
 	if (error == B_OK)
@@ -57,18 +86,6 @@ Volume::Init(BDirectory& directory, dev_t& _rootDeviceID, ino_t& _rootNodeID)
 	if (fPath.IsEmpty())
 		RETURN_ERROR(B_NO_MEMORY);
 
-	// stat() the directory
-	struct stat st;
-	error = directory.GetStat(&st);
-	if (error != B_OK) {
-		ERROR("Volume::Init(): failed to stat root directory: %s\n",
-			strerror(error));
-		RETURN_ERROR(error);
-	}
-
-	fDeviceID = st.st_dev;
-	fRootDirectoryID = st.st_ino;
-
 	// get a volume info from the FS
 	int fd = directory.Dup();
 	if (fd < 0) {
@@ -76,24 +93,347 @@ Volume::Init(BDirectory& directory, dev_t& _rootDeviceID, ino_t& _rootNodeID)
 			strerror(fd));
 		RETURN_ERROR(fd);
 	}
+	FileDescriptorCloser fdCloser(fd);
 
 	PackageFSVolumeInfo info;
 	if (ioctl(fd, PACKAGE_FS_OPERATION_GET_VOLUME_INFO, &info, sizeof(info))
 			!= 0) {
-		error = errno;
-		close(fd);
-		if (error != B_OK) {
-			ERROR("Volume::Init(): failed to get volume info: %s\n",
-				strerror(error));
-			RETURN_ERROR(error);
-		}
+		ERROR("Volume::Init(): failed to get volume info: %s\n",
+			strerror(errno));
+		RETURN_ERROR(errno);
 	}
 
-	close(fd);
-
 	fMountType = info.mountType;
-	_rootDeviceID = info.rootDeviceID;
-	_rootNodeID = info.rootDirectoryID;
+	fPackagesDirectoryRef.device = info.packagesDeviceID;
+	fPackagesDirectoryRef.node = info.packagesDirectoryID;
+
+	// read in all packages in the directory
+	error = _ReadPackagesDirectory();
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	_GetActivePackages(fd);
+
+	_packageRootRef.device = info.rootDeviceID;
+	_packageRootRef.node = info.rootDirectoryID;
+
+	return B_OK;
+}
+
+void
+Volume::MessageReceived(BMessage* message)
+{
+	switch (message->what) {
+		case B_NODE_MONITOR:
+		{
+			int32 opcode;
+			if (message->FindInt32("opcode", &opcode) != B_OK)
+				break;
+
+			switch (opcode) {
+				case B_ENTRY_CREATED:
+					_HandleEntryCreatedOrRemoved(message, true);
+					break;
+				case B_ENTRY_REMOVED:
+					_HandleEntryCreatedOrRemoved(message, false);
+					break;
+				case B_ENTRY_MOVED:
+					_HandleEntryMoved(message);
+					break;
+				default:
+					break;
+			}
+			break;
+		}
+
+		default:
+			BHandler::MessageReceived(message);
+			break;
+	}
+}
+
+
+int
+Volume::OpenRootDirectory() const
+{
+	BDirectory directory;
+	status_t error = directory.SetTo(&fRootDirectoryRef);
+	if (error != B_OK) {
+		ERROR("Volume::OpenRootDirectory(): failed to open root directory: "
+			"%s\n", strerror(error));
+		RETURN_ERROR(error);
+	}
+
+	return directory.Dup();
+}
+
+
+void
+Volume::_HandleEntryCreatedOrRemoved(const BMessage* message, bool created)
+{
+	// only moves to or from our packages directory are interesting
+	int32 deviceID;
+	int64 directoryID;
+	const char* name;
+	if (message->FindInt32("device", &deviceID) != B_OK
+		|| message->FindInt64("directory", &directoryID) != B_OK
+		|| message->FindString("name", &name) != B_OK
+		|| node_ref(deviceID, directoryID) != fPackagesDirectoryRef) {
+		return;
+	}
+
+	if (created)
+		_PackagesEntryCreated(name);
+	else
+		_PackagesEntryRemoved(name);
+}
+
+
+void
+Volume::_HandleEntryMoved(const BMessage* message)
+{
+	int32 deviceID;
+	int64 fromDirectoryID;
+	int64 toDirectoryID;
+	const char* fromName;
+	const char* toName;
+	if (message->FindInt32("device", &deviceID) != B_OK
+		|| message->FindInt64("from directory", &fromDirectoryID) != B_OK
+		|| message->FindInt64("to directory", &toDirectoryID) != B_OK
+		|| message->FindString("from name", &fromName) != B_OK
+		|| message->FindString("name", &toName) != B_OK
+		|| deviceID != fPackagesDirectoryRef.device
+		|| (fromDirectoryID != fPackagesDirectoryRef.node
+			&& toDirectoryID != fPackagesDirectoryRef.node)) {
+		return;
+	}
+
+	if (fromDirectoryID == fPackagesDirectoryRef.node)
+		_PackagesEntryRemoved(fromName);
+	if (toDirectoryID == fPackagesDirectoryRef.node)
+		_PackagesEntryCreated(toName);
+}
+
+
+void
+Volume::_PackagesEntryCreated(const char* name)
+{
+INFORM("Volume::_PackagesEntryCreated(\"%s\")\n", name);
+	entry_ref entry;
+	entry.device = fPackagesDirectoryRef.device;
+	entry.directory = fPackagesDirectoryRef.node;
+	status_t error = entry.set_name(name);
+	if (error != B_OK) {
+		ERROR("out of memory");
+		return;
+	}
+
+	Package* package = new(std::nothrow) Package;
+	if (package == NULL) {
+		ERROR("out of memory");
+		return;
+	}
+	ObjectDeleter packageDeleter(package);
+
+	error = package->Init(entry);
+	if (error != B_OK) {
+		ERROR("failed to init package for file \"%s\"\n", name);
+		return;
+	}
+
+	fPackagesByFileName.Insert(package);
+	fPackagesByNodeRef.Insert(package);
+	packageDeleter.Detach();
+
+	// activate package
+// TODO: Don't do that here!
+	size_t nameLength = strlen(package->FileName());
+	size_t requestSize = sizeof(PackageFSActivationChangeRequest) + nameLength;
+	PackageFSActivationChangeRequest* request
+		= (PackageFSActivationChangeRequest*)malloc(requestSize);
+	if (request == NULL) {
+		ERROR("out of memory");
+		return;
+	}
+	MemoryDeleter requestDeleter(request);
+
+	request->itemCount = 1;
+	PackageFSActivationChangeItem& item = request->items[0];
+	item.type = PACKAGE_FS_ACTIVATE_PACKAGE;
+
+	item.packageDeviceID = package->NodeRef().device;
+	item.packageNodeID = package->NodeRef().node;
+
+	item.nameLength = nameLength;
+	item.parentDeviceID = fPackagesDirectoryRef.device;
+	item.parentDirectoryID = fPackagesDirectoryRef.node;
+	strcpy(item.name, package->FileName());
+
+	int fd = OpenRootDirectory();
+	if (fd < 0) {
+		ERROR("Volume::_PackagesEntryCreated(): failed to open root directory: "
+			"%s", strerror(fd));
+		return;
+	}
+	FileDescriptorCloser fdCloser(fd);
+
+	if (ioctl(fd, PACKAGE_FS_OPERATION_CHANGE_ACTIVATION, request, requestSize)
+			!= 0) {
+		ERROR("Volume::_PackagesEntryCreated(): activate packages: %s\n",
+			strerror(errno));
+		return;
+	}
+
+	package->SetActive(true);
+}
+
+
+void
+Volume::_PackagesEntryRemoved(const char* name)
+{
+INFORM("Volume::_PackagesEntryRemoved(\"%s\")\n", name);
+	Package* package = fPackagesByFileName.Lookup(name);
+	if (package == NULL)
+		return;
+
+	if (package->IsActive()) {
+		// deactivate the package
+// TODO: Don't do that here!
+		size_t nameLength = strlen(package->FileName());
+		size_t requestSize = sizeof(PackageFSActivationChangeRequest)
+			+ nameLength;
+		PackageFSActivationChangeRequest* request
+			= (PackageFSActivationChangeRequest*)malloc(requestSize);
+		if (request == NULL) {
+			ERROR("out of memory");
+			return;
+		}
+		MemoryDeleter requestDeleter(request);
+
+		request->itemCount = 1;
+		PackageFSActivationChangeItem& item = request->items[0];
+		item.type = PACKAGE_FS_DEACTIVATE_PACKAGE;
+
+		item.packageDeviceID = package->NodeRef().device;
+		item.packageNodeID = package->NodeRef().node;
+
+		item.nameLength = nameLength;
+		item.parentDeviceID = fPackagesDirectoryRef.device;
+		item.parentDirectoryID = fPackagesDirectoryRef.node;
+		strcpy(item.name, package->FileName());
+
+		int fd = OpenRootDirectory();
+		if (fd < 0) {
+			ERROR("Volume::_PackagesEntryRemoved(): failed to open root "
+				"directory: %s", strerror(fd));
+			return;
+		}
+		FileDescriptorCloser fdCloser(fd);
+
+		if (ioctl(fd, PACKAGE_FS_OPERATION_CHANGE_ACTIVATION, request,
+				requestSize) != 0) {
+			ERROR("Volume::_PackagesEntryRemoved(): activate packages: %s\n",
+				strerror(errno));
+			return;
+		}
+	}
+
+	fPackagesByFileName.Remove(package);
+	fPackagesByNodeRef.Remove(package);
+	delete package;
+}
+
+
+status_t
+Volume::_ReadPackagesDirectory()
+{
+	BDirectory directory;
+	status_t error = directory.SetTo(&fPackagesDirectoryRef);
+	if (error != B_OK) {
+		ERROR("Volume::_ReadPackagesDirectory(): open packages directory: %s\n",
+			strerror(error));
+		RETURN_ERROR(error);
+	}
+
+	entry_ref entry;
+	while (directory.GetNextRef(&entry) == B_OK) {
+		Package* package = new(std::nothrow) Package;
+		if (package == NULL)
+			RETURN_ERROR(B_NO_MEMORY);
+		ObjectDeleter packageDeleter(package);
+
+		status_t error = package->Init(entry);
+		if (error == B_OK) {
+			fPackagesByFileName.Insert(package);
+			fPackagesByNodeRef.Insert(package);
+			packageDeleter.Detach();
+		}
+	}
+
+	return B_OK;
+}
+
+
+status_t
+Volume::_GetActivePackages(int fd)
+{
+	uint32 maxPackageCount = 16 * 1024;
+	PackageFSGetPackageInfosRequest* request = NULL;
+	MemoryDeleter requestDeleter;
+	size_t bufferSize;
+	for (;;) {
+		bufferSize = sizeof(PackageFSGetPackageInfosRequest)
+			+ (maxPackageCount - 1) * sizeof(PackageFSPackageInfo);
+		request = (PackageFSGetPackageInfosRequest*)malloc(bufferSize);
+		if (request == NULL)
+			RETURN_ERROR(B_NO_MEMORY);
+		requestDeleter.SetTo(request);
+
+		if (ioctl(fd, PACKAGE_FS_OPERATION_GET_PACKAGE_INFOS, request,
+				bufferSize) != 0) {
+			ERROR("Volume::_GetActivePackages(): failed to get active package "
+				"info from package FS: %s\n", strerror(errno));
+			RETURN_ERROR(errno);
+		}
+
+		if (request->packageCount <= maxPackageCount)
+			break;
+
+		maxPackageCount = request->packageCount;
+		requestDeleter.Unset();
+	}
+
+	// mark the returned packages active
+	for (uint32 i = 0; i < request->packageCount; i++) {
+		Package* package = fPackagesByNodeRef.Lookup(
+			node_ref(request->infos[i].packageDeviceID,
+				request->infos[i].packageNodeID));
+		if (package == NULL) {
+			WARN("active package (dev: %" B_PRIdDEV ", node: %" B_PRIdINO ") "
+				"not found in package directory\n",
+				request->infos[i].packageDeviceID,
+				request->infos[i].packageNodeID);
+// TODO: Deactivate the package right away?
+			continue;
+		}
+
+		package->SetActive(true);
+INFORM("active package: \"%s\"\n", package->FileName().String());
+	}
+
+for (PackageNodeRefHashTable::Iterator it = fPackagesByNodeRef.GetIterator();
+	it.HasNext();) {
+	Package* package = it.Next();
+	if (!package->IsActive())
+		INFORM("inactive package: \"%s\"\n", package->FileName().String());
+}
+
+			PackageNodeRefHashTable fPackagesByNodeRef;
+// INFORM("%" B_PRIu32 " active packages:\n", request->packageCount);
+// for (uint32 i = 0; i < request->packageCount; i++) {
+// 	INFORM("  dev: %" B_PRIdDEV ", node: %" B_PRIdINO "\n",
+// 		request->infos[i].packageDeviceID, request->infos[i].packageNodeID);
+// }
 
 	return B_OK;
 }
diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h
index aa90a29716..4dc5450d2f 100644
--- a/src/servers/package/Volume.h
+++ b/src/servers/package/Volume.h
@@ -9,47 +9,75 @@
 #define VOLUME_H
 
 
-#include 
+#include 
 #include 
 
 #include 
 
+#include "Package.h"
+
 
 class BDirectory;
 
 class Root;
 
 
-class Volume {
+class Volume : public BHandler {
 public:
 								Volume();
-								~Volume();
+	virtual						~Volume();
 
-			status_t			Init(BDirectory& directory,
-									dev_t& _rootDeviceID, ino_t& _rootNodeID);
+			status_t			Init(const node_ref& rootDirectoryRef,
+									node_ref& _packageRootRef);
+
+	virtual	void				MessageReceived(BMessage* message);
 
 			const BString&		Path() const
 									{ return fPath; }
 			PackageFSMountType	MountType() const
 									{ return fMountType; }
+
+			const node_ref&		RootDirectoryRef() const
+									{ return fRootDirectoryRef; }
 			dev_t				DeviceID() const
-									{ return fDeviceID; }
+									{ return fRootDirectoryRef.device; }
 			ino_t				RootDirectoryID() const
-									{ return fRootDirectoryID; }
+									{ return fRootDirectoryRef.node; }
+
+			const node_ref&		PackagesDirectoryRef() const
+									{ return fPackagesDirectoryRef; }
+			dev_t				PackagesDeviceID() const
+									{ return fPackagesDirectoryRef.device; }
+			ino_t				PackagesDirectoryID() const
+									{ return fPackagesDirectoryRef.node; }
 
 			Root*				GetRoot() const
 									{ return fRoot; }
 			void				SetRoot(Root* root)
 									{ fRoot = root; }
 
+			int					OpenRootDirectory() const;
+
+private:
+			void				_HandleEntryCreatedOrRemoved(
+									const BMessage* message, bool created);
+			void				_HandleEntryMoved(const BMessage* message);
+
+			void				_PackagesEntryCreated(const char* name);
+			void				_PackagesEntryRemoved(const char* name);
+
+			status_t			_ReadPackagesDirectory();
+			status_t			_GetActivePackages(int fd);
+
 private:
 			BString				fPath;
 			PackageFSMountType	fMountType;
-			dev_t				fDeviceID;
-			ino_t				fRootDirectoryID;
+			node_ref			fRootDirectoryRef;
+			node_ref			fPackagesDirectoryRef;
 			Root*				fRoot;
+			PackageFileNameHashTable fPackagesByFileName;
+			PackageNodeRefHashTable fPackagesByNodeRef;
 };
 
 
-
 #endif	// VOLUME_H

From af5c10ab19555126fc60d7766330ba1cc789cf52 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 7 Apr 2013 12:21:54 +0200
Subject: [PATCH 0366/1170] packagefs: Remove the packages directory node
 monitoring

---
 .../file_systems/packagefs/PackageDomain.cpp  |  25 +-
 .../file_systems/packagefs/PackageDomain.h    |   4 -
 .../kernel/file_systems/packagefs/Volume.cpp  | 230 +-----------------
 .../kernel/file_systems/packagefs/Volume.h    |  22 --
 4 files changed, 11 insertions(+), 270 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp
index d3e48d021d..69e5248eaf 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp
@@ -16,8 +16,6 @@
 #include 
 
 #include 
-#include 
-#include 
 #include 
 #include 
 
@@ -29,8 +27,7 @@ PackageDomain::PackageDomain(::Volume* volume)
 	:
 	fVolume(volume),
 	fPath(NULL),
-	fDirFD(-1),
-	fListener(NULL)
+	fDirFD(-1)
 {
 }
 
@@ -39,11 +36,6 @@ PackageDomain::~PackageDomain()
 {
 	PRINT("PackageDomain::~PackageDomain()\n");
 
-	if (fListener != NULL) {
-		remove_node_listener(fDeviceID, fNodeID, *fListener);
-		delete fListener;
-	}
-
 	Package* package = fPackages.Clear(true);
 	while (package != NULL) {
 		Package* next = package->FileNameHashTableNext();
@@ -128,21 +120,6 @@ PackageDomain::Init(const char* path, struct stat* _st)
 }
 
 
-status_t
-PackageDomain::Prepare(NotificationListener* listener)
-{
-	ObjectDeleter listenerDeleter(listener);
-
-	status_t error = add_node_listener(fDeviceID, fNodeID, B_WATCH_DIRECTORY,
-		*listener);
-	if (error != B_OK)
-		RETURN_ERROR(error);
-	fListener = listenerDeleter.Detach();
-
-	return B_OK;
-}
-
-
 void
 PackageDomain::AddPackage(Package* package)
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h
index 0442547b6c..2c8dd5629e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h
@@ -15,7 +15,6 @@
 
 struct stat;
 
-class NotificationListener;
 class Volume;
 
 
@@ -32,8 +31,6 @@ public:
 			ino_t				NodeID()		{ return fNodeID; }
 
 			status_t			Init(const char* path, struct stat* _st);
-			status_t			Prepare(NotificationListener* listener);
-									// takes over ownership of the listener
 
 			void				AddPackage(Package* package);
 			void				RemovePackage(Package* package);
@@ -49,7 +46,6 @@ private:
 			int					fDirFD;
 			dev_t				fDeviceID;
 			ino_t				fNodeID;
-			NotificationListener* fListener;
 			PackageFileNameHashTable fPackages;
 };
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 934f7f766e..4c4f9c9433 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -23,7 +23,6 @@
 
 #include 
 
-#include 
 #include 
 
 #include "AttributeIndex.h"
@@ -112,72 +111,6 @@ private:
 };
 
 
-// #pragma mark - DomainDirectoryEventJob
-
-
-struct Volume::DomainDirectoryEventJob : Job {
-	DomainDirectoryEventJob(Volume* volume, PackageDomain* domain)
-		:
-		Job(volume),
-		fDomain(domain),
-		fEvent()
-	{
-		fDomain->AcquireReference();
-	}
-
-	virtual ~DomainDirectoryEventJob()
-	{
-		fDomain->ReleaseReference();
-	}
-
-	status_t Init(const KMessage* event)
-	{
-		RETURN_ERROR(fEvent.SetTo(event->Buffer(), -1,
-			KMessage::KMESSAGE_CLONE_BUFFER));
-	}
-
-	virtual void Do()
-	{
-		fVolume->_DomainListenerEventOccurred(fDomain, &fEvent);
-	}
-
-private:
-	PackageDomain*	fDomain;
-	KMessage		fEvent;
-};
-
-
-// #pragma mark - DomainDirectoryListener
-
-
-struct Volume::DomainDirectoryListener : NotificationListener {
-	DomainDirectoryListener(Volume* volume, PackageDomain* domain)
-		:
-		fVolume(volume),
-		fDomain(domain)
-	{
-	}
-
-	virtual void EventOccurred(NotificationService& service,
-		const KMessage* event)
-	{
-// TODO: Remove!
-// 		DomainDirectoryEventJob* job = new(std::nothrow)
-// 			DomainDirectoryEventJob(fVolume, fDomain);
-// 		if (job == NULL || job->Init(event)) {
-// 			delete job;
-// 			return;
-// 		}
-// 
-// 		fVolume->_PushJob(job);
-	}
-
-private:
-	Volume*			fVolume;
-	PackageDomain*	fDomain;
-};
-
-
 // #pragma mark - ShineThroughDirectory
 
 
@@ -870,20 +803,6 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
 {
 	dprintf("packagefs: Adding package domain \"%s\"\n", domain->Path());
 
-	// create a directory listener
-	DomainDirectoryListener* listener = new(std::nothrow)
-		DomainDirectoryListener(this, domain);
-	if (listener == NULL)
-		RETURN_ERROR(B_NO_MEMORY);
-
-	// prepare the package domain
-	status_t error = domain->Prepare(listener);
-	if (error != B_OK) {
-		ERROR("Failed to prepare package domain \"%s\": %s\n",
-			domain->Path(), strerror(errno));
-		RETURN_ERROR(errno);
-	}
-
 	// iterate through the dir and create packages
 	int fd = dup(domain->DirectoryFD());
 	if (fd < 0) {
@@ -904,9 +823,15 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
 		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
 			continue;
 
-		_DomainEntryCreated(domain, domain->DeviceID(), domain->NodeID(),
-			-1, entry->d_name, false, notify);
-// TODO: -1 node ID?
+		Package* package;
+		if (_LoadPackage(domain, entry->d_name, package) != B_OK)
+			continue;
+		BReference packageReference(package, true);
+
+		VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
+		VolumeWriteLocker volumeLocker(this);
+		domain->AddPackage(package);
+
 	}
 
 	// add the packages to the node tree
@@ -914,7 +839,7 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
 	VolumeWriteLocker volumeLocker(this);
 	for (PackageFileNameHashTable::Iterator it
 			= domain->Packages().GetIterator(); Package* package = it.Next();) {
-		error = _AddPackageContent(package, notify);
+		status_t error = _AddPackageContent(package, notify);
 		if (error != B_OK) {
 			for (it.Rewind(); Package* activePackage = it.Next();) {
 				if (activePackage == package)
@@ -1411,141 +1336,6 @@ Volume::_RemoveNodeAndVNode(Node* node)
 }
 
 
-void
-Volume::_DomainListenerEventOccurred(PackageDomain* domain,
-	const KMessage* event)
-{
-	int32 opcode;
-	if (event->What() != B_NODE_MONITOR
-		|| event->FindInt32("opcode", &opcode) != B_OK) {
-		return;
-	}
-
-	switch (opcode) {
-		case B_ENTRY_CREATED:
-		{
-			int32 device;
-			int64 directory;
-			int64 node;
-			const char* name;
-			if (event->FindInt32("device", &device) == B_OK
-				&& event->FindInt64("directory", &directory) == B_OK
-				&& event->FindInt64("node", &node) == B_OK
-				&& event->FindString("name", &name) == B_OK) {
-				_DomainEntryCreated(domain, device, directory, node, name,
-					true, true);
-			}
-			break;
-		}
-
-		case B_ENTRY_REMOVED:
-		{
-			int32 device;
-			int64 directory;
-			int64 node;
-			const char* name;
-			if (event->FindInt32("device", &device) == B_OK
-				&& event->FindInt64("directory", &directory) == B_OK
-				&& event->FindInt64("node", &node) == B_OK
-				&& event->FindString("name", &name) == B_OK) {
-				_DomainEntryRemoved(domain, device, directory, node, name,
-					true);
-			}
-			break;
-		}
-
-		case B_ENTRY_MOVED:
-		{
-			int32 device;
-			int64 fromDirectory;
-			int64 toDirectory;
-			int32 nodeDevice;
-			int64 node;
-			const char* fromName;
-			const char* name;
-			if (event->FindInt32("device", &device) == B_OK
-				&& event->FindInt64("from directory", &fromDirectory) == B_OK
-				&& event->FindInt64("to directory", &toDirectory) == B_OK
-				&& event->FindInt32("node device", &nodeDevice) == B_OK
-				&& event->FindInt64("node", &node) == B_OK
-				&& event->FindString("from name", &fromName) == B_OK
-				&& event->FindString("name", &name) == B_OK) {
-				_DomainEntryMoved(domain, device, fromDirectory, toDirectory,
-					nodeDevice, node, fromName, name, true);
-			}
-			break;
-		}
-
-		default:
-			break;
-	}
-}
-
-
-void
-Volume::_DomainEntryCreated(PackageDomain* domain, dev_t deviceID,
-	ino_t directoryID, ino_t nodeID, const char* name, bool addContent,
-	bool notify)
-{
-	// let's see, if things look plausible
-	if (deviceID != domain->DeviceID() || directoryID != domain->NodeID()
-		|| domain->FindPackage(name) != NULL) {
-		return;
-	}
-
-	Package* package;
-	if (_LoadPackage(domain, name, package) != B_OK)
-		return;
-	BReference packageReference(package, true);
-
-	VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
-	VolumeWriteLocker volumeLocker(this);
-	domain->AddPackage(package);
-
-	// add the package to the node tree
-	if (addContent) {
-		status_t error = _AddPackageContent(package, notify);
-		if (error != B_OK) {
-			domain->RemovePackage(package);
-			return;
-		}
-	}
-}
-
-
-void
-Volume::_DomainEntryRemoved(PackageDomain* domain, dev_t deviceID,
-	ino_t directoryID, ino_t nodeID, const char* name, bool notify)
-{
-	// let's see, if things look plausible
-	if (deviceID != domain->DeviceID() || directoryID != domain->NodeID())
-		return;
-
-	Package* package = domain->FindPackage(name);
-	if (package == NULL)
-		return;
-	BReference packageReference(package);
-
-	// remove the package
-	VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
-	VolumeWriteLocker volumeLocker(this);
-	_RemovePackageContent(package, NULL, true);
-	domain->RemovePackage(package);
-}
-
-
-void
-Volume::_DomainEntryMoved(PackageDomain* domain, dev_t deviceID,
-	ino_t fromDirectoryID, ino_t toDirectoryID, dev_t nodeDeviceID,
-	ino_t nodeID, const char* fromName, const char* name, bool notify)
-{
-	_DomainEntryRemoved(domain, deviceID, fromDirectoryID, nodeID, fromName,
-		notify);
-	_DomainEntryCreated(domain, deviceID, toDirectoryID, nodeID, name, true,
-		notify);
-}
-
-
 /*static*/ status_t
 Volume::_LoadPackage(PackageDomain* domain, const char* name,
 	Package*& _package)
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index 66c12d92a1..2064063236 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -108,15 +108,10 @@ private:
 			struct Job;
 			struct AddPackageDomainJob;
 			struct DomainDirectoryEventJob;
-			struct PackageLoaderErrorOutput;
-			struct PackageLoaderContentHandler;
-			struct DomainDirectoryListener;
 			struct ShineThroughDirectory;
 			struct ActivationChangeRequest;
 
 			friend struct AddPackageDomainJob;
-			friend struct DomainDirectoryEventJob;
-			friend struct DomainDirectoryListener;
 
 			typedef DoublyLinkedList JobList;
 			typedef DoublyLinkedList PackageDomainList;
@@ -160,23 +155,6 @@ private:
 			void				_RemoveNodeAndVNode(Node* node);
 									// caller must hold a reference
 
-			void				_DomainListenerEventOccurred(
-									PackageDomain* domain,
-									const KMessage* event);
-			void				_DomainEntryCreated(PackageDomain* domain,
-									dev_t deviceID, ino_t directoryID,
-									ino_t nodeID, const char* name,
-									bool addContent, bool notify);
-			void				_DomainEntryRemoved(PackageDomain* domain,
-									dev_t deviceID, ino_t directoryID,
-									ino_t nodeID, const char* name,
-									bool notify);
-			void				_DomainEntryMoved(PackageDomain* domain,
-									dev_t deviceID, ino_t fromDirectoryID,
-									ino_t toDirectoryID, dev_t nodeDeviceID,
-									ino_t nodeID, const char* fromName,
-									const char* name, bool notify);
-
 	static	status_t			_LoadPackage(PackageDomain* domain,
 									const char* name, Package*& _package);
 

From 6978941aac85ea329a8552253f384924dcccd1b3 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 7 Apr 2013 12:57:15 +0200
Subject: [PATCH 0367/1170] packagefs: Remove support for multiple package
 domains per volume

That also get rid of the job stuff and the package loader thread.
---
 .../kernel/file_systems/packagefs/Jamfile     |   1 -
 .../kernel/file_systems/packagefs/Package.cpp |   8 +-
 .../kernel/file_systems/packagefs/Package.h   |   8 +-
 .../file_systems/packagefs/PackageDomain.cpp  | 143 -------
 .../file_systems/packagefs/PackageDomain.h    |  53 ---
 .../packagefs/PackageLinkDirectory.cpp        |   4 +-
 .../packagefs/PackageLinkSymlink.cpp          |   2 +-
 .../packagefs/ResolvableFamily.cpp            |   4 +-
 .../kernel/file_systems/packagefs/Volume.cpp  | 374 +++++++++---------
 .../kernel/file_systems/packagefs/Volume.h    |  45 +--
 10 files changed, 203 insertions(+), 439 deletions(-)
 delete mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp
 delete mode 100644 src/add-ons/kernel/file_systems/packagefs/PackageDomain.h

diff --git a/src/add-ons/kernel/file_systems/packagefs/Jamfile b/src/add-ons/kernel/file_systems/packagefs/Jamfile
index 93964979f5..63763c6f49 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Jamfile
+++ b/src/add-ons/kernel/file_systems/packagefs/Jamfile
@@ -28,7 +28,6 @@ HAIKU_PACKAGE_FS_SOURCES =
 	Query.cpp
 	Package.cpp
 	PackageDirectory.cpp
-	PackageDomain.cpp
 	PackageFile.cpp
 	PackageFSRoot.cpp
 	PackageLeafNode.cpp
diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.cpp b/src/add-ons/kernel/file_systems/packagefs/Package.cpp
index 28fc000b80..721d3219f6 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Package.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Package.cpp
@@ -21,10 +21,10 @@
 
 #include "DebugSupport.h"
 #include "PackageDirectory.h"
-#include "PackageDomain.h"
 #include "PackageFile.h"
 #include "PackageSymlink.h"
 #include "Version.h"
+#include "Volume.h"
 
 
 using namespace BPackageKit;
@@ -300,9 +300,9 @@ private:
 // #pragma mark - Package
 
 
-Package::Package(PackageDomain* domain, dev_t deviceID, ino_t nodeID)
+Package::Package(::Volume* volume, dev_t deviceID, ino_t nodeID)
 	:
-	fDomain(domain),
+	fVolume(volume),
 	fFileName(NULL),
 	fName(NULL),
 	fInstallPath(NULL),
@@ -461,7 +461,7 @@ Package::Open()
 	}
 
 	// open the file
-	fFD = openat(fDomain->DirectoryFD(), fFileName, O_RDONLY);
+	fFD = openat(fVolume->PackagesDirectoryFD(), fFileName, O_RDONLY);
 	if (fFD < 0) {
 		ERROR("Failed to open package file \"%s\"\n", fFileName);
 		return errno;
diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.h b/src/add-ons/kernel/file_systems/packagefs/Package.h
index d9b0b56a6a..b8495b5e5d 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Package.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Package.h
@@ -24,22 +24,22 @@
 using BPackageKit::BPackageArchitecture;
 
 
-class PackageDomain;
 class PackageLinkDirectory;
+class Volume;
 class Version;
 
 
 class Package : public BReferenceable,
 	public DoublyLinkedListLinkImpl {
 public:
-								Package(PackageDomain* domain, dev_t deviceID,
+								Package(::Volume* volume, dev_t deviceID,
 									ino_t nodeID);
 								~Package();
 
 			status_t			Init(const char* fileName);
 			status_t			Load();
 
-			PackageDomain*		Domain() const		{ return fDomain; }
+			::Volume*			Volume() const		{ return fVolume; }
 			const char*			FileName() const	{ return fFileName; }
 
 			status_t			SetName(const char* name);
@@ -93,7 +93,7 @@ private:
 
 private:
 			mutex				fLock;
-			PackageDomain*		fDomain;
+			::Volume*			fVolume;
 			char*				fFileName;
 			char*				fName;
 			char*				fInstallPath;
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp
deleted file mode 100644
index 69e5248eaf..0000000000
--- a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.cpp
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * Copyright 2009, Ingo Weinhold, ingo_weinhold@gmx.de.
- * Distributed under the terms of the MIT License.
- */
-
-
-#include "PackageDomain.h"
-
-#include 
-#include 
-#include 
-#include 
-
-#include 
-
-#include 
-
-#include 
-#include 
-#include 
-
-#include "DebugSupport.h"
-#include "Volume.h"
-
-
-PackageDomain::PackageDomain(::Volume* volume)
-	:
-	fVolume(volume),
-	fPath(NULL),
-	fDirFD(-1)
-{
-}
-
-
-PackageDomain::~PackageDomain()
-{
-	PRINT("PackageDomain::~PackageDomain()\n");
-
-	Package* package = fPackages.Clear(true);
-	while (package != NULL) {
-		Package* next = package->FileNameHashTableNext();
-		package->ReleaseReference();
-		package = next;
-	}
-
-	if (fDirFD >= 0)
-		close(fDirFD);
-
-	free(fPath);
-}
-
-
-status_t
-PackageDomain::Init(const char* path, struct stat* _st)
-{
-	// Open the directory. We want the path be interpreted depending on from
-	// where it came (kernel or userland), but we always want a FD in the kernel
-	// I/O context. There's no VFS service method to do that for us, so we need
-	// to do that ourselves.
-	bool calledFromKernel
-		= team_get_current_team_id() == team_get_kernel_team_id();
-		// Not entirely correct, but good enough for now. The only alternative
-		// is to have that information passed in as well.
-
-	struct vnode* vnode;
-	status_t error;
-	if (path != NULL) {
-		error = vfs_get_vnode_from_path(path, calledFromKernel, &vnode);
-	} else {
-		// No path given -- use the "packages" directory at our mount point.
-		error = vfs_entry_ref_to_vnode(fVolume->MountPointDeviceID(),
-			fVolume->MountPointNodeID(), "packages", &vnode);
-	}
-	if (error != B_OK) {
-		ERROR("Failed to open package domain \"%s\"\n", strerror(error));
-		RETURN_ERROR(error);
-	}
-
-	fDirFD = vfs_open_vnode(vnode, O_RDONLY, true);
-
-	if (fDirFD < 0) {
-		ERROR("Failed to open package domain \"%s\"\n", strerror(fDirFD));
-		vfs_put_vnode(vnode);
-		RETURN_ERROR(fDirFD);
-	}
-	// Our vnode reference has been transferred to the FD.
-
-	// Is it a directory at all?
-	struct stat st;
-	if (fstat(fDirFD, &st) < 0)
-		RETURN_ERROR(errno);
-
-	fDeviceID = st.st_dev;
-	fNodeID = st.st_ino;
-
-	// get a normalized path
-	KPath normalizedPath;
-	if (normalizedPath.InitCheck() != B_OK)
-		RETURN_ERROR(normalizedPath.InitCheck());
-
-	char* normalizedPathBuffer = normalizedPath.LockBuffer();
-	error = vfs_entry_ref_to_path(fDeviceID, fNodeID, NULL,
-		normalizedPathBuffer, normalizedPath.BufferSize());
-	if (error != B_OK)
-		RETURN_ERROR(error);
-
-	fPath = strdup(normalizedPathBuffer);
-	if (fPath == NULL)
-		RETURN_ERROR(B_NO_MEMORY);
-
-	// init packages hash table
-	error = fPackages.Init();
-	if (error != B_OK)
-		return error;
-
-	if (_st != NULL)
-		*_st = st;
-
-	return B_OK;
-}
-
-
-void
-PackageDomain::AddPackage(Package* package)
-{
-	fPackages.Insert(package);
-	package->AcquireReference();
-}
-
-
-void
-PackageDomain::RemovePackage(Package* package)
-{
-	fPackages.Remove(package);
-	package->ReleaseReference();
-}
-
-
-Package*
-PackageDomain::FindPackage(const char* fileName) const
-{
-	return fPackages.Lookup(fileName);
-}
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h b/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h
deleted file mode 100644
index 2c8dd5629e..0000000000
--- a/src/add-ons/kernel/file_systems/packagefs/PackageDomain.h
+++ /dev/null
@@ -1,53 +0,0 @@
-/*
- * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
- * Distributed under the terms of the MIT License.
- */
-#ifndef PACKAGE_DOMAIN_H
-#define PACKAGE_DOMAIN_H
-
-
-#include 
-
-#include 
-
-#include "Package.h"
-
-
-struct stat;
-
-class Volume;
-
-
-class PackageDomain : public BReferenceable,
-	public DoublyLinkedListLinkImpl {
-public:
-								PackageDomain(::Volume* volume);
-								~PackageDomain();
-
-			::Volume*			Volume() const	{ return fVolume; }
-			const char*			Path() const	{ return fPath; }
-			int					DirectoryFD()	{ return fDirFD; }
-			dev_t				DeviceID()		{ return fDeviceID; }
-			ino_t				NodeID()		{ return fNodeID; }
-
-			status_t			Init(const char* path, struct stat* _st);
-
-			void				AddPackage(Package* package);
-			void				RemovePackage(Package* package);
-
-			Package*			FindPackage(const char* fileName) const;
-
-			const PackageFileNameHashTable& Packages() const
-									{ return fPackages; }
-
-private:
-			::Volume*			fVolume;
-			char*				fPath;
-			int					fDirFD;
-			dev_t				fDeviceID;
-			ino_t				fNodeID;
-			PackageFileNameHashTable fPackages;
-};
-
-
-#endif	// PACKAGE_DOMAIN_H
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
index 48a11f54ac..b0dc5a45a6 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp
@@ -99,11 +99,11 @@ PackageLinkDirectory::AddPackage(Package* package,
 
 	// Find the insertion point in the list. We sort by mount type -- the more
 	// specific the higher the priority.
-	MountType mountType = package->Domain()->Volume()->MountType();
+	MountType mountType = package->Volume()->MountType();
 	Package* otherPackage = NULL;
 	for (PackageList::Iterator it = fPackages.GetIterator();
 			(otherPackage = it.Next()) != NULL;) {
-		if (otherPackage->Domain()->Volume()->MountType() <= mountType)
+		if (otherPackage->Volume()->MountType() <= mountType)
 			break;
 	}
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
index ed674e2785..4fbf81f7f2 100644
--- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp
@@ -94,7 +94,7 @@ PackageLinkSymlink::Update(Package* package, PackageLinksListener* listener)
 		fLinkPath = package->InstallPath();
 		if (fLinkPath == NULL) {
 			fLinkPath = link_path_for_mount_type(
-				package->Domain()->Volume()->MountType());
+				package->Volume()->MountType());
 		}
 	} else
 		fLinkPath = kUnknownLinkTarget;
diff --git a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp
index f396eb6b03..9e61317986 100644
--- a/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/ResolvableFamily.cpp
@@ -17,11 +17,11 @@ ResolvableFamily::AddResolvable(Resolvable* resolvable,
 	// Find the insertion point in the list. We sort by mount type -- the more
 	// specific the higher the priority.
 	MountType mountType
-		= resolvable->Package()->Domain()->Volume()->MountType();
+		= resolvable->Package()->Volume()->MountType();
 	Resolvable* otherResolvable = NULL;
 	for (FamilyResolvableList::Iterator it = fResolvables.GetIterator();
 			(otherResolvable = it.Next()) != NULL;) {
-		if (otherResolvable->Package()->Domain()->Volume()->MountType()
+		if (otherResolvable->Package()->Volume()->MountType()
 				<= mountType) {
 			break;
 		}
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 4c4f9c9433..523189d082 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2009-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
  * Distributed under the terms of the MIT License.
  */
 
@@ -23,6 +23,8 @@
 
 #include 
 
+#include 
+#include 
 #include 
 
 #include "AttributeIndex.h"
@@ -63,51 +65,112 @@ const char* const* kHomeShineThroughDirectories
 const size_t kMaxActivationRequestSize = 10 * 1024 * 1024;
 
 
-// #pragma mark - Job
+// #pragma mark - ShineThroughDirectory
 
 
-struct Volume::Job : DoublyLinkedListLinkImpl {
-	Job(Volume* volume)
+struct Volume::PackagesDirectory {
+	PackagesDirectory()
 		:
-		fVolume(volume)
+		fPath(NULL),
+		fDirFD(-1)
 	{
 	}
 
-	virtual ~Job()
+
+	~PackagesDirectory()
 	{
+		if (fDirFD >= 0)
+			close(fDirFD);
+
+		free(fPath);
 	}
 
-	virtual void Do() = 0;
-
-protected:
-	Volume*	fVolume;
-};
-
-
-// #pragma mark - AddPackageDomainJob
-
-
-struct Volume::AddPackageDomainJob : Job {
-	AddPackageDomainJob(Volume* volume, PackageDomain* domain)
-		:
-		Job(volume),
-		fDomain(domain)
+	const char* Path() const
 	{
-		fDomain->AcquireReference();
+		return fPath;
 	}
 
-	virtual ~AddPackageDomainJob()
+	int DirectoryFD() const
 	{
-		fDomain->ReleaseReference();
+		return fDirFD;
 	}
 
-	virtual void Do()
+	dev_t DeviceID() const
 	{
-		fVolume->_AddPackageDomain(fDomain, true);
+		return fDeviceID;
+	}
+
+	ino_t NodeID() const
+	{
+		return fNodeID;
+	}
+
+	status_t Init(const char* path, dev_t mountPointDeviceID,
+		ino_t mountPointNodeID, struct stat& _st)
+	{
+		// Open the directory. We want the path be interpreted depending on from
+		// where it came (kernel or userland), but we always want a FD in the
+		// kernel I/O context. There's no VFS service method to do that for us,
+		// so we need to do that ourselves.
+		bool calledFromKernel
+			= team_get_current_team_id() == team_get_kernel_team_id();
+			// Not entirely correct, but good enough for now. The only
+			// alternative is to have that information passed in as well.
+
+		struct vnode* vnode;
+		status_t error;
+		if (path != NULL) {
+			error = vfs_get_vnode_from_path(path, calledFromKernel, &vnode);
+		} else {
+			// No path given -- use the "packages" directory at our mount point.
+			error = vfs_entry_ref_to_vnode(mountPointDeviceID, mountPointNodeID,
+				"packages", &vnode);
+		}
+		if (error != B_OK) {
+			ERROR("Failed to open package domain \"%s\"\n", strerror(error));
+			RETURN_ERROR(error);
+		}
+
+		fDirFD = vfs_open_vnode(vnode, O_RDONLY, true);
+
+		if (fDirFD < 0) {
+			ERROR("Failed to open package domain \"%s\"\n", strerror(fDirFD));
+			vfs_put_vnode(vnode);
+			RETURN_ERROR(fDirFD);
+		}
+		// Our vnode reference has been transferred to the FD.
+
+		// Is it a directory at all?
+		struct stat& st = _st;
+		if (fstat(fDirFD, &st) < 0)
+			RETURN_ERROR(errno);
+
+		fDeviceID = st.st_dev;
+		fNodeID = st.st_ino;
+
+		// get a normalized path
+		KPath normalizedPath;
+		if (normalizedPath.InitCheck() != B_OK)
+			RETURN_ERROR(normalizedPath.InitCheck());
+
+		char* normalizedPathBuffer = normalizedPath.LockBuffer();
+		error = vfs_entry_ref_to_path(fDeviceID, fNodeID, NULL,
+			normalizedPathBuffer, normalizedPath.BufferSize());
+		if (error != B_OK)
+			RETURN_ERROR(error);
+
+		fPath = strdup(normalizedPathBuffer);
+		if (fPath == NULL)
+			RETURN_ERROR(B_NO_MEMORY);
+
+		return B_OK;
 	}
 
 private:
-	PackageDomain*	fDomain;
+	char*	fPath;
+	int		fDirFD;
+	dev_t	fDeviceID;
+	ino_t	fNodeID;
 };
 
 
@@ -264,22 +327,32 @@ Volume::Volume(fs_volume* fsVolume)
 	fFSVolume(fsVolume),
 	fRootDirectory(NULL),
 	fPackageFSRoot(NULL),
-	fPackageLoader(-1),
-	fNextNodeID(kRootDirectoryID + 1),
-	fTerminating(false)
+	fPackagesDirectory(NULL),
+	fNextNodeID(kRootDirectoryID + 1)
 {
 	rw_lock_init(&fLock, "packagefs volume");
-	mutex_init(&fJobQueueLock, "packagefs volume job queue");
-	fJobQueueCondition.Init(this, "packagefs volume job queue");
 }
 
 
 Volume::~Volume()
 {
-	_TerminatePackageLoader();
+	// remove the packages from the node tree
+	{
+		VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
+		VolumeWriteLocker volumeLocker(this);
+		for (PackageFileNameHashTable::Iterator it = fPackages.GetIterator();
+			Package* package = it.Next();) {
+			_RemovePackageContent(package, NULL, false);
+		}
+	}
 
-	while (PackageDomain* packageDomain = fPackageDomains.Head())
-		_RemovePackageDomain(packageDomain);
+	// delete the packages
+	Package* package = fPackages.Clear(true);
+	while (package != NULL) {
+		Package* next = package->FileNameHashTableNext();
+		package->ReleaseReference();
+		package = next;
+	}
 
 	// delete all indices
 	Index* index = fIndices.Clear(true);
@@ -307,11 +380,17 @@ Volume::~Volume()
 	if (fRootDirectory != NULL)
 		fRootDirectory->ReleaseReference();
 
-	mutex_destroy(&fJobQueueLock);
 	rw_lock_destroy(&fLock);
 }
 
 
+int
+Volume::PackagesDirectoryFD() const
+{
+	return fPackagesDirectory->DirectoryFD();
+}
+
+
 status_t
 Volume::Mount(const char* parameterString)
 {
@@ -324,6 +403,10 @@ Volume::Mount(const char* parameterString)
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
+	error = fPackages.Init();
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
 	error = fIndices.Init();
 	if (error != B_OK)
 		RETURN_ERROR(error);
@@ -425,14 +508,14 @@ Volume::Mount(const char* parameterString)
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
-	// create initial package domain
-	PackageDomain* packageDomain = new(std::nothrow) PackageDomain(this);
-	if (packageDomain == NULL)
+	// create package domain
+	fPackagesDirectory = new(std::nothrow) PackagesDirectory;
+	if (fPackagesDirectory == NULL)
 		RETURN_ERROR(B_NO_MEMORY);
-	BReference packageDomainReference(packageDomain, true);
 
 	struct stat st;
-	error = packageDomain->Init(packages, &st);
+	error = fPackagesDirectory->Init(packages, fMountPoint.deviceID,
+		fMountPoint.nodeID, st);
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
@@ -481,17 +564,11 @@ Volume::Mount(const char* parameterString)
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
-	// add initial package domain
-	error = _AddPackageDomain(packageDomain, false);
+	// add initial packages
+	error = _AddInitialPackages();
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
-	// spawn package loader thread
-	fPackageLoader = spawn_kernel_thread(&_PackageLoaderEntry,
-		"package loader", B_NORMAL_PRIORITY, this);
-	if (fPackageLoader < 0)
-		RETURN_ERROR(fPackageLoader);
-
 	// publish the root node
 	fRootDirectory->AcquireReference();
 	error = PublishVNode(fRootDirectory);
@@ -505,9 +582,6 @@ Volume::Mount(const char* parameterString)
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
-	// run the package loader
-	resume_thread(fPackageLoader);
-
 	return B_OK;
 }
 
@@ -515,7 +589,6 @@ Volume::Mount(const char* parameterString)
 void
 Volume::Unmount()
 {
-	_TerminatePackageLoader();
 }
 
 
@@ -534,10 +607,8 @@ Volume::IOCtl(Node* node, uint32 operation, void* buffer, size_t size)
 			info.mountType = fMountType;
 			info.rootDeviceID = fPackageFSRoot->DeviceID();
 			info.rootDirectoryID = fPackageFSRoot->NodeID();
-
-			PackageDomain* domain = fPackageDomains.Head();
-			info.packagesDeviceID = domain != NULL ? domain->DeviceID() : -1;
-			info.packagesDirectoryID = domain != NULL ? domain->NodeID() : -1;
+			info.packagesDeviceID = fPackagesDirectory->DeviceID();
+			info.packagesDirectoryID = fPackagesDirectory->NodeID();
 
 			RETURN_ERROR(user_memcpy(buffer, &info, sizeof(info)));
 		}
@@ -552,13 +623,9 @@ Volume::IOCtl(Node* node, uint32 operation, void* buffer, size_t size)
 
 			VolumeReadLocker volumeReadLocker(this);
 
-			PackageDomain* domain = fPackageDomains.Head();
-			if (domain == NULL)
-				RETURN_ERROR(B_BAD_VALUE);
-
 			uint32 packageIndex = 0;
 			for (PackageFileNameHashTable::Iterator it
-					= domain->Packages().GetIterator(); it.HasNext();
+					= fPackages.GetIterator(); it.HasNext();
 				packageIndex++) {
 				Package* package = it.Next();
 				PackageFSPackageInfo info;
@@ -572,7 +639,7 @@ Volume::IOCtl(Node* node, uint32 operation, void* buffer, size_t size)
 					return B_BAD_ADDRESS;
 			}
 
-			uint32 packageCount = domain->Packages().CountElements();
+			uint32 packageCount = fPackages.CountElements();
 			RETURN_ERROR(user_memcpy(&request->packageCount, &packageCount,
 				sizeof(packageCount)));
 		}
@@ -685,28 +752,6 @@ Volume::PublishVNode(Node* node)
 }
 
 
-status_t
-Volume::AddPackageDomain(const char* path)
-{
-	PackageDomain* packageDomain = new(std::nothrow) PackageDomain(this);
-	if (packageDomain == NULL)
-		RETURN_ERROR(B_NO_MEMORY);
-	BReference packageDomainReference(packageDomain, true);
-
-	status_t error = packageDomain->Init(path, NULL);
-	if (error != B_OK)
-		RETURN_ERROR(error);
-
-	Job* job = new(std::nothrow) AddPackageDomainJob(this, packageDomain);
-	if (job == NULL)
-		RETURN_ERROR(B_NO_MEMORY);
-
-	_PushJob(job);
-
-	return B_OK;
-}
-
-
 void
 Volume::PackageLinkNodeAdded(Node* node)
 {
@@ -736,84 +781,23 @@ Volume::PackageLinkNodeChanged(Node* node, uint32 statFields,
 }
 
 
-/*static*/ status_t
-Volume::_PackageLoaderEntry(void* data)
-{
-	return ((Volume*)data)->_PackageLoader();
-}
-
-
 status_t
-Volume::_PackageLoader()
+Volume::_AddInitialPackages()
 {
-	while (!fTerminating) {
-		MutexLocker jobQueueLocker(fJobQueueLock);
-
-		Job* job = fJobQueue.RemoveHead();
-		if (job == NULL) {
-			// no job yet -- wait for someone notifying us
-			ConditionVariableEntry waitEntry;
-			fJobQueueCondition.Add(&waitEntry);
-			jobQueueLocker.Unlock();
-			waitEntry.Wait();
-			continue;
-		}
-
-		// do the job
-		jobQueueLocker.Unlock();
-		job->Do();
-		delete job;
-	}
-
-	return B_OK;
-}
-
-
-void
-Volume::_TerminatePackageLoader()
-{
-	fTerminating = true;
-
-	if (fPackageLoader >= 0) {
-		MutexLocker jobQueueLocker(fJobQueueLock);
-		fJobQueueCondition.NotifyOne();
-		jobQueueLocker.Unlock();
-
-		wait_for_thread(fPackageLoader, NULL);
-		fPackageLoader = -1;
-	}
-
-	// empty the job queue
-	while (Job* job = fJobQueue.RemoveHead())
-		delete job;
-}
-
-
-void
-Volume::_PushJob(Job* job)
-{
-	MutexLocker jobQueueLocker(fJobQueueLock);
-	fJobQueue.Add(job);
-	fJobQueueCondition.NotifyOne();
-}
-
-
-status_t
-Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
-{
-	dprintf("packagefs: Adding package domain \"%s\"\n", domain->Path());
+	dprintf("packagefs: Adding packages from \"%s\"\n",
+		fPackagesDirectory->Path());
 
 	// iterate through the dir and create packages
-	int fd = dup(domain->DirectoryFD());
+	int fd = dup(fPackagesDirectory->DirectoryFD());
 	if (fd < 0) {
-		ERROR("Failed to dup() package domain FD: %s\n", strerror(errno));
+		ERROR("Failed to dup() packages directory FD: %s\n", strerror(errno));
 		RETURN_ERROR(errno);
 	}
 
 	DIR* dir = fdopendir(fd);
 	if (dir == NULL) {
-		ERROR("Failed to open package domain directory \"%s\": %s\n",
-			domain->Path(), strerror(errno));
+		ERROR("Failed to open packages directory \"%s\": %s\n",
+			fPackagesDirectory->Path(), strerror(errno));
 		RETURN_ERROR(errno);
 	}
 	CObjectDeleter dirCloser(dir, closedir);
@@ -824,53 +808,56 @@ Volume::_AddPackageDomain(PackageDomain* domain, bool notify)
 			continue;
 
 		Package* package;
-		if (_LoadPackage(domain, entry->d_name, package) != B_OK)
+		if (_LoadPackage(entry->d_name, package) != B_OK)
 			continue;
 		BReference packageReference(package, true);
 
 		VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
 		VolumeWriteLocker volumeLocker(this);
-		domain->AddPackage(package);
+		_AddPackage(package);
 
 	}
 
 	// add the packages to the node tree
 	VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
 	VolumeWriteLocker volumeLocker(this);
-	for (PackageFileNameHashTable::Iterator it
-			= domain->Packages().GetIterator(); Package* package = it.Next();) {
-		status_t error = _AddPackageContent(package, notify);
+	for (PackageFileNameHashTable::Iterator it = fPackages.GetIterator();
+		Package* package = it.Next();) {
+		status_t error = _AddPackageContent(package, false);
 		if (error != B_OK) {
 			for (it.Rewind(); Package* activePackage = it.Next();) {
 				if (activePackage == package)
 					break;
-				_RemovePackageContent(activePackage, NULL, notify);
+				_RemovePackageContent(activePackage, NULL, false);
 			}
 			RETURN_ERROR(error);
 		}
 	}
 
-	fPackageDomains.Add(domain);
-	domain->AcquireReference();
-
 	return B_OK;
 }
 
 
-void
-Volume::_RemovePackageDomain(PackageDomain* domain)
+inline void
+Volume::_AddPackage(Package* package)
 {
-	// remove the domain's packages from the node tree
-	VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
-	VolumeWriteLocker volumeLocker(this);
-	for (PackageFileNameHashTable::Iterator it
-			= domain->Packages().GetIterator(); Package* package = it.Next();) {
-		_RemovePackageContent(package, NULL, false);
-	}
+	fPackages.Insert(package);
+	package->AcquireReference();
+}
 
-	// remove the domain
-	fPackageDomains.Remove(domain);
-	domain->ReleaseReference();
+
+inline void
+Volume::_RemovePackage(Package* package)
+{
+	fPackages.Remove(package);
+	package->ReleaseReference();
+}
+
+
+inline Package*
+Volume::_FindPackage(const char* fileName) const
+{
+	return fPackages.Lookup(fileName);
 }
 
 
@@ -1336,19 +1323,18 @@ Volume::_RemoveNodeAndVNode(Node* node)
 }
 
 
-/*static*/ status_t
-Volume::_LoadPackage(PackageDomain* domain, const char* name,
-	Package*& _package)
+status_t
+Volume::_LoadPackage(const char* name, Package*& _package)
 {
 	// check whether the entry is a file
 	struct stat st;
-	if (fstatat(domain->DirectoryFD(), name, &st, 0) < 0
+	if (fstatat(fPackagesDirectory->DirectoryFD(), name, &st, 0) < 0
 		|| !S_ISREG(st.st_mode)) {
 		return B_BAD_VALUE;
 	}
 
 	// create a package
-	Package* package = new(std::nothrow) Package(domain, st.st_dev, st.st_ino);
+	Package* package = new(std::nothrow) Package(this, st.st_dev, st.st_ino);
 	if (package == NULL)
 		RETURN_ERROR(B_NO_MEMORY);
 	BReference packageReference(package, true);
@@ -1369,12 +1355,6 @@ Volume::_LoadPackage(PackageDomain* domain, const char* name,
 status_t
 Volume::_ChangeActivation(ActivationChangeRequest& request)
 {
-// TODO: Would need locking, but will be irrelevant when removing the support
-// for multiple package domains.
-	PackageDomain* domain = fPackageDomains.Head();
-	if (domain == NULL)
-		RETURN_ERROR(B_BAD_VALUE);
-
 	// first check the request
 	int32 newPackageCount = 0;
 	int32 oldPackageCount = 0;
@@ -1384,14 +1364,14 @@ Volume::_ChangeActivation(ActivationChangeRequest& request)
 		for (ActivationChangeRequest::Iterator it = request.GetIterator();
 			it.HasNext();) {
 			PackageFSActivationChangeItem* item = it.Next();
-			if (item->parentDeviceID != domain->DeviceID()
-				|| item->parentDirectoryID != domain->NodeID()) {
+			if (item->parentDeviceID != fPackagesDirectory->DeviceID()
+				|| item->parentDirectoryID != fPackagesDirectory->NodeID()) {
 				ERROR("Volume::_ChangeActivation(): mismatching packages "
-					"domain\n");
+					"directory\n");
 				RETURN_ERROR(B_BAD_VALUE);
 			}
 
-			Package* package = domain->FindPackage(item->name);
+			Package* package = _FindPackage(item->name);
 // TODO: We should better look up the package by node_ref!
 			if (item->type == PACKAGE_FS_ACTIVATE_PACKAGE) {
 				if (package != NULL) {
@@ -1449,7 +1429,7 @@ INFORM("Volume::_ChangeActivation(): %" B_PRId32 " new packages, %" B_PRId32 " o
 		}
 
 		Package* package;
-		status_t error = _LoadPackage(domain, item->name, package);
+		status_t error = _LoadPackage(item->name, package);
 		if (error != B_OK) {
 			ERROR("Volume::_ChangeActivation(): failed to load package "
 				"\"%s\"\n", item->name);
@@ -1476,11 +1456,11 @@ INFORM("Volume::_ChangeActivation(): %" B_PRId32 " new packages, %" B_PRId32 " o
 			continue;
 		}
 
-		Package* package = domain->FindPackage(item->name);
+		Package* package = _FindPackage(item->name);
 // TODO: We should better look up the package by node_ref!
 		oldPackageReferences[oldPackageIndex++].SetTo(package);
 		_RemovePackageContent(package, NULL, true);
-		domain->RemovePackage(package);
+		_RemovePackage(package);
 INFORM("package \"%s\" deactivated\n", package->FileName());
 	}
 // TODO: Since package removal cannot fail, consider adding the new packages
@@ -1492,12 +1472,12 @@ INFORM("package \"%s\" deactivated\n", package->FileName());
 	for (newPackageIndex = 0; newPackageIndex < newPackageCount;
 		newPackageIndex++) {
 		Package* package = newPackageReferences[newPackageIndex];
-		domain->AddPackage(package);
+		_AddPackage(package);
 
 		// add the package to the node tree
 		error = _AddPackageContent(package, true);
 		if (error != B_OK) {
-			domain->RemovePackage(package);
+			_RemovePackage(package);
 			break;
 		}
 INFORM("package \"%s\" activated\n", package->FileName());
@@ -1508,19 +1488,19 @@ INFORM("package \"%s\" activated\n", package->FileName());
 		for (int32 i = newPackageIndex - 1; i >= 0; i--) {
 			Package* package = newPackageReferences[i];
 			_RemovePackageContent(package, NULL, true);
-			domain->RemovePackage(package);
+			_RemovePackage(package);
 		}
 
 		for (int32 i = oldPackageCount - 1; i >= 0; i--) {
 			Package* package = oldPackageReferences[i];
-			domain->AddPackage(package);
+			_AddPackage(package);
 
 			if (_AddPackageContent(package, true) != B_OK) {
 				// nothing we can do here
 				ERROR("Volume::_ChangeActivation(): failed to roll back "
 					"deactivation of package \"%s\" after error\n",
 		  			package->FileName());
-				domain->RemovePackage(package);
+				_RemovePackage(package);
 			}
 		}
 	}
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index 2064063236..23caf19fb8 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -1,5 +1,5 @@
 /*
- * Copyright 2009-2011, Ingo Weinhold, ingo_weinhold@gmx.de.
+ * Copyright 2009-2013, Ingo Weinhold, ingo_weinhold@gmx.de.
  * Distributed under the terms of the MIT License.
  */
 #ifndef VOLUME_H
@@ -19,7 +19,7 @@
 #include "Index.h"
 #include "Node.h"
 #include "NodeListener.h"
-#include "PackageDomain.h"
+#include "Package.h"
 #include "PackageLinksListener.h"
 #include "Query.h"
 
@@ -51,6 +51,8 @@ public:
 
 			::MountType			MountType() const	{ return fMountType; }
 
+			int					PackagesDirectoryFD() const;
+
 			void				SetPackageFSRoot(::PackageFSRoot* root)
 									{ fPackageFSRoot = root; }
 			::PackageFSRoot*	PackageFSRoot() const
@@ -94,8 +96,6 @@ public:
 			status_t			RemoveVNode(ino_t nodeID);
 			status_t			PublishVNode(Node* node);
 
-			status_t			AddPackageDomain(const char* path);
-
 private:
 	// PackageLinksListener
 	virtual	void				PackageLinkNodeAdded(Node* node);
@@ -105,29 +105,16 @@ private:
 									const OldNodeAttributes& oldAttributes);
 
 private:
-			struct Job;
-			struct AddPackageDomainJob;
-			struct DomainDirectoryEventJob;
+			struct PackagesDirectory;
 			struct ShineThroughDirectory;
 			struct ActivationChangeRequest;
 
-			friend struct AddPackageDomainJob;
-
-			typedef DoublyLinkedList JobList;
-			typedef DoublyLinkedList PackageDomainList;
-
 private:
-	static	status_t			_PackageLoaderEntry(void* data);
-			status_t			_PackageLoader();
+			status_t			_AddInitialPackages();
 
-			void				_TerminatePackageLoader();
-
-			void				_PushJob(Job* job);
-
-			status_t			_AddInitialPackageDomain(const char* path);
-			status_t			_AddPackageDomain(PackageDomain* domain,
-									bool notify);
-			void				_RemovePackageDomain(PackageDomain* domain);
+	inline	void				_AddPackage(Package* package);
+	inline	void				_RemovePackage(Package* package);
+	inline	Package*			_FindPackage(const char* fileName) const;
 
 			status_t			_AddPackageContent(Package* package,
 									bool notify);
@@ -155,8 +142,8 @@ private:
 			void				_RemoveNodeAndVNode(Node* node);
 									// caller must hold a reference
 
-	static	status_t			_LoadPackage(PackageDomain* domain,
-									const char* name, Package*& _package);
+			status_t			_LoadPackage(const char* name,
+									Package*& _package);
 
 			status_t			_ChangeActivation(
 									ActivationChangeRequest& request);
@@ -187,8 +174,7 @@ private:
 			Directory*			fRootDirectory;
 			::PackageFSRoot*	fPackageFSRoot;
 			::MountType			fMountType;
-			thread_id			fPackageLoader;
-			PackageDomainList	fPackageDomains;
+			PackagesDirectory*	fPackagesDirectory;
 
 			struct {
 				dev_t			deviceID;
@@ -197,16 +183,11 @@ private:
 
 			NodeIDHashTable		fNodes;
 			NodeListenerHashTable fNodeListeners;
+			PackageFileNameHashTable fPackages;
 			QueryList			fQueries;
 			IndexHashTable		fIndices;
 
-			JobList				fJobQueue;
-			mutex				fJobQueueLock;
-			ConditionVariable	fJobQueueCondition;
-
 			ino_t				fNextNodeID;
-
-	volatile bool				fTerminating;
 };
 
 

From 71364193839bcbefb2df5223133f901e25c3a99f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 7 Apr 2013 23:59:43 +0200
Subject: [PATCH 0368/1170] Add shared PthreadMutexLocker, an AutoLocker for
 pthread_mutex_t

---
 headers/private/shared/PthreadMutexLocker.h | 42 +++++++++++++++++++++
 1 file changed, 42 insertions(+)
 create mode 100644 headers/private/shared/PthreadMutexLocker.h

diff --git a/headers/private/shared/PthreadMutexLocker.h b/headers/private/shared/PthreadMutexLocker.h
new file mode 100644
index 0000000000..db0e69516f
--- /dev/null
+++ b/headers/private/shared/PthreadMutexLocker.h
@@ -0,0 +1,42 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef _PTHREAD_MUTEX_LOCKER_H
+#define _PTHREAD_MUTEX_LOCKER_H
+
+
+#include 
+
+#include 
+
+
+namespace BPrivate {
+
+
+class AutoLockerMutexLocking {
+public:
+	inline bool Lock(pthread_mutex_t* lockable)
+	{
+		return pthread_mutex_lock(lockable) == 0;
+	}
+
+	inline void Unlock(pthread_mutex_t* lockable)
+	{
+		pthread_mutex_unlock(lockable);
+	}
+};
+
+
+typedef AutoLocker PthreadMutexLocker;
+
+
+}	// namespace BPrivate
+
+using BPrivate::PthreadMutexLocker;
+
+
+#endif	// _PTHREAD_MUTEX_LOCKER_H

From 8fb3930a4290eb1156bbe53fba7947b0cd2be237 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 8 Apr 2013 00:05:51 +0200
Subject: [PATCH 0369/1170] package daemon: Make all work with the packages
 asynchronous

There's now a worker thread per Root that does all the work that can
take time. Node monitoring notifications received in the main thread are
just pushed into the worker's job queue, so the application looper
remains responsive.
---
 src/servers/package/Jamfile           |   2 +
 src/servers/package/Job.cpp           |  20 ++++
 src/servers/package/Job.h             |  25 +++++
 src/servers/package/JobQueue.cpp      |  99 +++++++++++++++++
 src/servers/package/JobQueue.h        |  43 ++++++++
 src/servers/package/PackageDaemon.cpp |  22 +---
 src/servers/package/Root.cpp          | 143 ++++++++++++++++++++++++-
 src/servers/package/Root.h            |  19 ++++
 src/servers/package/Volume.cpp        | 146 +++++++++++++++++++++++---
 src/servers/package/Volume.h          |  17 ++-
 10 files changed, 497 insertions(+), 39 deletions(-)
 create mode 100644 src/servers/package/Job.cpp
 create mode 100644 src/servers/package/Job.h
 create mode 100644 src/servers/package/JobQueue.cpp
 create mode 100644 src/servers/package/JobQueue.h

diff --git a/src/servers/package/Jamfile b/src/servers/package/Jamfile
index bc6bc7d7d1..05425898e9 100644
--- a/src/servers/package/Jamfile
+++ b/src/servers/package/Jamfile
@@ -6,6 +6,8 @@ UsePrivateHeaders app kernel package shared ;
 Server package_daemon
  	:
  	DebugSupport.cpp
+ 	Job.cpp
+ 	JobQueue.cpp
  	Package.cpp
  	PackageDaemon.cpp
  	Root.cpp
diff --git a/src/servers/package/Job.cpp b/src/servers/package/Job.cpp
new file mode 100644
index 0000000000..092d1d755c
--- /dev/null
+++ b/src/servers/package/Job.cpp
@@ -0,0 +1,20 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include "Job.h"
+
+
+Job::Job()
+{
+}
+
+
+Job::~Job()
+{
+}
diff --git a/src/servers/package/Job.h b/src/servers/package/Job.h
new file mode 100644
index 0000000000..a7e91c76ae
--- /dev/null
+++ b/src/servers/package/Job.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef JOB_H
+#define JOB_H
+
+
+#include 
+#include 
+
+
+class Job : public BReferenceable, public DoublyLinkedListLinkImpl {
+public:
+								Job();
+	virtual						~Job();
+
+	virtual	void				Do() = 0;
+};
+
+
+#endif	// JOB_H
diff --git a/src/servers/package/JobQueue.cpp b/src/servers/package/JobQueue.cpp
new file mode 100644
index 0000000000..8572a088c3
--- /dev/null
+++ b/src/servers/package/JobQueue.cpp
@@ -0,0 +1,99 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include "JobQueue.h"
+
+#include 
+
+
+JobQueue::JobQueue()
+	:
+	fMutexInitialized(false),
+	fNewJobConditionInitialized(false),
+	fJobs(),
+	fClosed(false)
+{
+}
+
+
+JobQueue::~JobQueue()
+{
+	if (fMutexInitialized) {
+		PthreadMutexLocker mutexLocker(fMutex);
+		while (Job* job = fJobs.RemoveHead())
+			job->ReleaseReference();
+	}
+
+	if (fNewJobConditionInitialized)
+		pthread_cond_destroy(&fNewJobCondition);
+
+	if (fMutexInitialized)
+		pthread_mutex_destroy(&fMutex);
+}
+
+
+status_t
+JobQueue::Init()
+{
+	status_t error = pthread_mutex_init(&fMutex, NULL);
+	if (error != B_OK)
+		return error;
+	fMutexInitialized = true;
+
+	error = pthread_cond_init(&fNewJobCondition, NULL);
+	if (error != B_OK)
+		return error;
+	fNewJobConditionInitialized = true;
+
+	return B_OK;
+}
+
+
+void
+JobQueue::Close()
+{
+	if (fMutexInitialized && fNewJobConditionInitialized) {
+		PthreadMutexLocker mutexLocker(fMutex);
+		fClosed = true;
+		pthread_cond_broadcast(&fNewJobCondition);
+	}
+}
+
+
+bool
+JobQueue::QueueJob(Job* job)
+{
+	PthreadMutexLocker mutexLocker(fMutex);
+	if (fClosed)
+		return false;
+
+	fJobs.Add(job);
+	job->AcquireReference();
+
+	pthread_cond_signal(&fNewJobCondition);
+	return true;
+}
+
+
+Job*
+JobQueue::DequeueJob()
+{
+	PthreadMutexLocker mutexLocker(fMutex);
+
+	while (!fClosed) {
+		Job* job = fJobs.RemoveHead();
+		if (job != NULL)
+			return job;
+
+		if (!fClosed)
+			pthread_cond_wait(&fNewJobCondition, &fMutex);
+	}
+
+	return NULL;
+}
diff --git a/src/servers/package/JobQueue.h b/src/servers/package/JobQueue.h
new file mode 100644
index 0000000000..4d6d93e5fa
--- /dev/null
+++ b/src/servers/package/JobQueue.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef JOB_QUEUE_H
+#define JOB_QUEUE_H
+
+
+#include 
+
+#include "Job.h"
+
+
+class JobQueue {
+public:
+								JobQueue();
+								~JobQueue();
+
+			status_t			Init();
+			void				Close();
+
+			bool				QueueJob(Job* job);
+									// acquires a reference, if successful
+			Job*				DequeueJob();
+									// returns a reference
+
+private:
+			typedef DoublyLinkedList JobList;
+
+private:
+			pthread_mutex_t		fMutex;
+			pthread_cond_t		fNewJobCondition;
+			bool				fMutexInitialized;
+			bool				fNewJobConditionInitialized;
+			JobList				fJobs;
+			bool				fClosed;
+};
+
+
+#endif	// JOB_QUEUE_H
diff --git a/src/servers/package/PackageDaemon.cpp b/src/servers/package/PackageDaemon.cpp
index 8229e4877c..4380102f5c 100644
--- a/src/servers/package/PackageDaemon.cpp
+++ b/src/servers/package/PackageDaemon.cpp
@@ -96,7 +96,7 @@ PackageDaemon::_RegisterVolume(dev_t deviceID)
 		RETURN_ERROR(B_BAD_VALUE);
 
 	// create a volume
-	Volume* volume = new(std::nothrow) Volume;
+	Volume* volume = new(std::nothrow) Volume(this);
 	if (volume == NULL)
 		RETURN_ERROR(B_NO_MEMORY);
 	ObjectDeleter volumeDeleter(volume);
@@ -126,19 +126,6 @@ PackageDaemon::_RegisterVolume(dev_t deviceID)
 	}
 	volumeDeleter.Detach();
 
-	AddHandler(volume);
-
-	// node-monitor the volume's packages directory
-	error = watch_node(&volume->PackagesDirectoryRef(), B_WATCH_DIRECTORY,
-		BMessenger(volume, this));
-	if (error != B_OK) {
-		ERROR("PackageDaemon::_RegisterVolume(): failed to start watching the "
-			"packages directory of the volume at \"%s\": %s\n",
-			volume->Path().String(), strerror(error));
-		// Not good, but not fatal. Only the manual package operations in the
-		// packages directory won't work correctly.
-	}
-
 	INFORM("volume at \"%s\" registered\n", volume->Path().String());
 
 	return B_OK;
@@ -148,16 +135,13 @@ PackageDaemon::_RegisterVolume(dev_t deviceID)
 void
 PackageDaemon::_UnregisterVolume(Volume* volume)
 {
-	stop_watching(BMessenger(volume, this));
+	volume->Unmounted();
 
-	RemoveHandler(volume);
+	INFORM("volume at \"%s\" unregistered\n", volume->Path().String());
 
 	Root* root = volume->GetRoot();
 	root->UnregisterVolume(volume);
 
-	INFORM("volume at \"%s\" unregistered\n", volume->Path().String());
-
-	delete volume;
 	_PutRoot(root);
 }
 
diff --git a/src/servers/package/Root.cpp b/src/servers/package/Root.cpp
index d72a5041ef..6553f4bba7 100644
--- a/src/servers/package/Root.cpp
+++ b/src/servers/package/Root.cpp
@@ -17,19 +17,88 @@
 #include "Volume.h"
 
 
+// #pragma mark - InitVolumePackagesJob
+
+
+struct Root::InitPackagesJob : public Job {
+	InitPackagesJob(Volume* volume)
+		:
+		fVolume(volume)
+	{
+	}
+
+	virtual void Do()
+	{
+		fVolume->InitPackages();
+	}
+
+private:
+	Volume*	fVolume;
+};
+
+
+// #pragma mark - DeleteVolumeJob
+
+
+struct Root::DeleteVolumeJob : public Job {
+	DeleteVolumeJob(Volume* volume)
+		:
+		fVolume(volume)
+	{
+	}
+
+	virtual void Do()
+	{
+		delete fVolume;
+	}
+
+private:
+	Volume*	fVolume;
+};
+
+
+// #pragma mark - HandleNodeMonitorEventsJob
+
+
+struct Root::HandleNodeMonitorEventsJob : public Job {
+	HandleNodeMonitorEventsJob(Volume* volume)
+		:
+		fVolume(volume)
+	{
+	}
+
+	virtual void Do()
+	{
+		fVolume->ProcessPendingNodeMonitorEvents();
+	}
+
+private:
+	Volume*	fVolume;
+};
+
+
+// #pragma mark - Root
+
+
 Root::Root()
 	:
 	fNodeRef(),
 	fPath(),
 	fSystemVolume(NULL),
 	fCommonVolume(NULL),
-	fHomeVolume(NULL)
+	fHomeVolume(NULL),
+	fJobQueue(),
+	fJobRunner(-1)
 {
 }
 
 
 Root::~Root()
 {
+	fJobQueue.Close();
+
+	if (fJobRunner >= 0)
+		wait_for_thread(fJobRunner, NULL);
 }
 
 
@@ -38,12 +107,22 @@ Root::Init(const node_ref& nodeRef)
 {
 	fNodeRef = nodeRef;
 
+	// init job queue and spawn job runner thread
+	status_t error = fJobQueue.Init();
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	fJobRunner = spawn_thread(&_JobRunnerEntry, "job runner", B_NORMAL_PRIORITY,
+		this);
+	if (fJobRunner < 0)
+		RETURN_ERROR(fJobRunner);
+
 	// get the path
 	BDirectory directory;
-	status_t error = directory.SetTo(&fNodeRef);
+	error = directory.SetTo(&fNodeRef);
 	if (error != B_OK) {
 		ERROR("Root::Init(): failed to open directory: %s\n", strerror(error));
-		return error;
+		RETURN_ERROR(error);
 	}
 
 	BEntry entry;
@@ -63,6 +142,8 @@ Root::Init(const node_ref& nodeRef)
 	if (fPath.IsEmpty())
 		RETURN_ERROR(B_NO_MEMORY);
 
+	resume_thread(fJobRunner);
+
 	return B_OK;
 }
 
@@ -84,6 +165,14 @@ Root::RegisterVolume(Volume* volume)
 	*volumeToSet = volume;
 	volume->SetRoot(this);
 
+	// queue a job for reading the volume's packages
+	status_t error = _QueueJob(new(std::nothrow) InitPackagesJob(volume));
+	if (error != B_OK) {
+		volume->SetRoot(NULL);
+		*volumeToSet = NULL;
+		return error;
+	}
+
 	return B_OK;
 }
 
@@ -99,7 +188,10 @@ Root::UnregisterVolume(Volume* volume)
 	}
 
 	*volumeToSet = NULL;
-	volume->SetRoot(NULL);
+
+	// Use the job queue to delete the volume to make sure there aren't any
+	// pending jobs that reference the volume.
+	_QueueJob(new(std::nothrow) DeleteVolumeJob(volume));
 }
 
 
@@ -117,6 +209,14 @@ Root::FindVolume(dev_t deviceID) const
 }
 
 
+void
+Root::HandleNodeMonitorEvents(Volume* volume)
+{
+// TODO: Don't push a new one, if one is already pending!
+	_QueueJob(new(std::nothrow) HandleNodeMonitorEventsJob(volume));
+}
+
+
 void
 Root::LastReferenceReleased()
 {
@@ -138,3 +238,38 @@ Root::_GetVolume(PackageFSMountType mountType)
 			return NULL;
 	}
 }
+
+
+status_t
+Root::_QueueJob(Job* job)
+{
+	if (job == NULL)
+		return B_NO_MEMORY;
+
+	BReference jobReference(job, true);
+	if (!fJobQueue.QueueJob(job)) {
+		// job queue already closed
+		return B_BAD_VALUE;
+	}
+
+	return B_OK;
+}
+
+
+/*static*/ status_t
+Root::_JobRunnerEntry(void* data)
+{
+	return ((Root*)data)->_JobRunner();
+}
+
+
+status_t
+Root::_JobRunner()
+{
+	while (Job* job = fJobQueue.DequeueJob()) {
+		job->Do();
+		job->ReleaseReference();
+	}
+
+	return B_OK;
+}
diff --git a/src/servers/package/Root.h b/src/servers/package/Root.h
index 8afa89cf14..288f5088e9 100644
--- a/src/servers/package/Root.h
+++ b/src/servers/package/Root.h
@@ -10,12 +10,16 @@
 
 
 #include 
+#include 
+#include 
 #include 
 
 #include 
 
 #include 
 
+#include "JobQueue.h"
+
 
 class Volume;
 
@@ -34,21 +38,36 @@ public:
 
 			status_t			RegisterVolume(Volume* volume);
 			void				UnregisterVolume(Volume* volume);
+									// deletes the volume (eventually)
 
 			Volume*				FindVolume(dev_t deviceID) const;
 
+			void				HandleNodeMonitorEvents(Volume* volume);
+
 protected:
 	virtual	void				LastReferenceReleased();
 
+private:
+			struct InitPackagesJob;
+			struct DeleteVolumeJob;
+			struct HandleNodeMonitorEventsJob;
+
 private:
 			Volume**			_GetVolume(PackageFSMountType mountType);
 
+			status_t			_QueueJob(Job* job);
+
+	static	status_t			_JobRunnerEntry(void* data);
+			status_t			_JobRunner();
+
 private:
 			node_ref			fNodeRef;
 			BString				fPath;
 			Volume*				fSystemVolume;
 			Volume*				fCommonVolume;
 			Volume*				fHomeVolume;
+			JobQueue			fJobQueue;
+			thread_id			fJobRunner;
 };
 
 
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index 526a7ed2bf..8c330847fd 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -16,15 +16,50 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 
 #include 
+#include 
 
 #include "DebugSupport.h"
+#include "Root.h"
 
 
-Volume::Volume()
+// #pragma mark - NodeMonitorEvent
+
+
+struct Volume::NodeMonitorEvent
+	: public DoublyLinkedListLinkImpl {
+public:
+	NodeMonitorEvent(const BString& entryName, bool created)
+		:
+		fEntryName(entryName),
+		fCreated(created)
+	{
+	}
+
+	const BString& EntryName() const
+	{
+		return fEntryName;
+	}
+
+	bool WasCreated() const
+	{
+		return fCreated;
+	}
+
+private:
+	BString	fEntryName;
+	bool	fCreated;
+};
+
+
+// #pragma mark - Volume
+
+
+Volume::Volume(BLooper* looper)
 	:
 	BHandler(),
 	fPath(),
@@ -33,8 +68,11 @@ Volume::Volume()
 	fPackagesDirectoryRef(),
 	fRoot(NULL),
 	fPackagesByFileName(),
-	fPackagesByNodeRef()
+	fPackagesByNodeRef(),
+	fPendingNodeMonitorEventsLock("pending node monitor events"),
+	fPendingNodeMonitorEvents()
 {
+	looper->AddHandler(this);
 }
 
 
@@ -107,19 +145,55 @@ Volume::Init(const node_ref& rootDirectoryRef, node_ref& _packageRootRef)
 	fPackagesDirectoryRef.device = info.packagesDeviceID;
 	fPackagesDirectoryRef.node = info.packagesDirectoryID;
 
-	// read in all packages in the directory
-	error = _ReadPackagesDirectory();
-	if (error != B_OK)
-		RETURN_ERROR(error);
-
-	_GetActivePackages(fd);
-
 	_packageRootRef.device = info.rootDeviceID;
 	_packageRootRef.node = info.rootDirectoryID;
 
 	return B_OK;
 }
 
+
+status_t
+Volume::InitPackages()
+{
+	// node-monitor the volume's packages directory
+	status_t error = watch_node(&fPackagesDirectoryRef, B_WATCH_DIRECTORY,
+		BMessenger(this));
+	if (error != B_OK) {
+		ERROR("Volume::InitPackages(): failed to start watching the packages "
+			"directory of the volume at \"%s\": %s\n",
+			fPath.String(), strerror(error));
+		// Not good, but not fatal. Only the manual package operations in the
+		// packages directory won't work correctly.
+	}
+
+	// read the packages directory and get the active packages
+	int fd = OpenRootDirectory();
+	if (fd < 0) {
+		ERROR("Volume::InitPackages(): failed to open root directory: %s\n",
+			strerror(fd));
+		RETURN_ERROR(fd);
+	}
+	FileDescriptorCloser fdCloser(fd);
+
+	error = _ReadPackagesDirectory();
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	error = _GetActivePackages(fd);
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
+	return B_OK;
+}
+
+
+void
+Volume::Unmounted()
+{
+	stop_watching(BMessenger(this));
+}
+
+
 void
 Volume::MessageReceived(BMessage* message)
 {
@@ -168,6 +242,28 @@ Volume::OpenRootDirectory() const
 }
 
 
+void
+Volume::ProcessPendingNodeMonitorEvents()
+{
+	// get the events
+	NodeMonitorEventList events;
+	{
+		AutoLocker eventsLock(fPendingNodeMonitorEventsLock);
+		events.MoveFrom(&fPendingNodeMonitorEvents);
+	}
+
+	// process them
+// TODO: Don't do that individually.
+	while (NodeMonitorEvent* event = events.RemoveHead()) {
+		ObjectDeleter eventDeleter(event);
+		if (event->WasCreated())
+			_PackagesEntryCreated(event->EntryName());
+		else
+			_PackagesEntryRemoved(event->EntryName());
+	}
+}
+
+
 void
 Volume::_HandleEntryCreatedOrRemoved(const BMessage* message, bool created)
 {
@@ -182,10 +278,7 @@ Volume::_HandleEntryCreatedOrRemoved(const BMessage* message, bool created)
 		return;
 	}
 
-	if (created)
-		_PackagesEntryCreated(name);
-	else
-		_PackagesEntryRemoved(name);
+	_QueueNodeMonitorEvent(name, created);
 }
 
 
@@ -209,9 +302,32 @@ Volume::_HandleEntryMoved(const BMessage* message)
 	}
 
 	if (fromDirectoryID == fPackagesDirectoryRef.node)
-		_PackagesEntryRemoved(fromName);
+		_QueueNodeMonitorEvent(fromName, false);
 	if (toDirectoryID == fPackagesDirectoryRef.node)
-		_PackagesEntryCreated(toName);
+		_QueueNodeMonitorEvent(toName, true);
+}
+
+
+void
+Volume::_QueueNodeMonitorEvent(const BString& name, bool wasCreated)
+{
+	if (name.IsEmpty()) {
+		ERROR("Volume::_QueueNodeMonitorEvent(): got empty name.\n");
+		return;
+	}
+
+	NodeMonitorEvent* event
+		= new(std::nothrow) NodeMonitorEvent(name, wasCreated);
+	if (event == NULL) {
+		ERROR("Volume::_QueueNodeMonitorEvent(): out of memory.\n");
+		return;
+	}
+
+	AutoLocker eventsLock(fPendingNodeMonitorEventsLock);
+	fPendingNodeMonitorEvents.Add(event);
+	eventsLock.Unlock();
+
+	fRoot->HandleNodeMonitorEvents(this);
 }
 
 
diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h
index 4dc5450d2f..c791cae258 100644
--- a/src/servers/package/Volume.h
+++ b/src/servers/package/Volume.h
@@ -10,9 +10,11 @@
 
 
 #include 
+#include 
 #include 
 
 #include 
+#include 
 
 #include "Package.h"
 
@@ -24,11 +26,14 @@ class Root;
 
 class Volume : public BHandler {
 public:
-								Volume();
+								Volume(BLooper* looper);
 	virtual						~Volume();
 
 			status_t			Init(const node_ref& rootDirectoryRef,
 									node_ref& _packageRootRef);
+			status_t			InitPackages();
+
+			void				Unmounted();
 
 	virtual	void				MessageReceived(BMessage* message);
 
@@ -58,10 +63,18 @@ public:
 
 			int					OpenRootDirectory() const;
 
+			void				ProcessPendingNodeMonitorEvents();
+
+private:
+			struct NodeMonitorEvent;
+			typedef DoublyLinkedList NodeMonitorEventList;
+
 private:
 			void				_HandleEntryCreatedOrRemoved(
 									const BMessage* message, bool created);
 			void				_HandleEntryMoved(const BMessage* message);
+			void				_QueueNodeMonitorEvent(const BString& name,
+									bool wasCreated);
 
 			void				_PackagesEntryCreated(const char* name);
 			void				_PackagesEntryRemoved(const char* name);
@@ -77,6 +90,8 @@ private:
 			Root*				fRoot;
 			PackageFileNameHashTable fPackagesByFileName;
 			PackageNodeRefHashTable fPackagesByNodeRef;
+			BLocker				fPendingNodeMonitorEventsLock;
+			NodeMonitorEventList fPendingNodeMonitorEvents;
 };
 
 

From 9e4096146fa5a20df2fc06301683853029851163 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 8 Apr 2013 15:19:11 +0200
Subject: [PATCH 0370/1170] package daemon: Add a Listener interface for Volume

* This way, Volume doesn't have to know Root.
* Suppress listener notifications for node monitoring events when there
  are were already events pending.
---
 src/servers/package/Root.cpp   |  6 ++----
 src/servers/package/Root.h     | 12 +++++++-----
 src/servers/package/Volume.cpp | 29 +++++++++++++++++++++++++----
 src/servers/package/Volume.h   | 15 ++++++++++++++-
 4 files changed, 48 insertions(+), 14 deletions(-)

diff --git a/src/servers/package/Root.cpp b/src/servers/package/Root.cpp
index 6553f4bba7..f05dcc66cb 100644
--- a/src/servers/package/Root.cpp
+++ b/src/servers/package/Root.cpp
@@ -14,7 +14,6 @@
 #include 
 
 #include "DebugSupport.h"
-#include "Volume.h"
 
 
 // #pragma mark - InitVolumePackagesJob
@@ -29,7 +28,7 @@ struct Root::InitPackagesJob : public Job {
 
 	virtual void Do()
 	{
-		fVolume->InitPackages();
+		fVolume->InitPackages(fVolume->GetRoot());
 	}
 
 private:
@@ -210,9 +209,8 @@ Root::FindVolume(dev_t deviceID) const
 
 
 void
-Root::HandleNodeMonitorEvents(Volume* volume)
+Root::VolumeNodeMonitorEventOccurred(Volume* volume)
 {
-// TODO: Don't push a new one, if one is already pending!
 	_QueueJob(new(std::nothrow) HandleNodeMonitorEventsJob(volume));
 }
 
diff --git a/src/servers/package/Root.h b/src/servers/package/Root.h
index 288f5088e9..2c7f328f08 100644
--- a/src/servers/package/Root.h
+++ b/src/servers/package/Root.h
@@ -19,12 +19,10 @@
 #include 
 
 #include "JobQueue.h"
+#include "Volume.h"
 
 
-class Volume;
-
-
-class Root : public BReferenceable {
+class Root : public BReferenceable, private Volume::Listener {
 public:
 								Root();
 	virtual						~Root();
@@ -42,7 +40,9 @@ public:
 
 			Volume*				FindVolume(dev_t deviceID) const;
 
-			void				HandleNodeMonitorEvents(Volume* volume);
+private:
+	// Volume::Listener
+	virtual	void				VolumeNodeMonitorEventOccurred(Volume* volume);
 
 protected:
 	virtual	void				LastReferenceReleased();
@@ -52,6 +52,8 @@ private:
 			struct DeleteVolumeJob;
 			struct HandleNodeMonitorEventsJob;
 
+			friend struct InitPackagesJob;
+
 private:
 			Volume**			_GetVolume(PackageFSMountType mountType);
 
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index 8c330847fd..a1945c1e77 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -24,7 +24,14 @@
 #include 
 
 #include "DebugSupport.h"
-#include "Root.h"
+
+
+// #pragma mark - Listener
+
+
+Volume::Listener::~Listener()
+{
+}
 
 
 // #pragma mark - NodeMonitorEvent
@@ -67,6 +74,7 @@ Volume::Volume(BLooper* looper)
 	fRootDirectoryRef(),
 	fPackagesDirectoryRef(),
 	fRoot(NULL),
+	fListener(NULL),
 	fPackagesByFileName(),
 	fPackagesByNodeRef(),
 	fPendingNodeMonitorEventsLock("pending node monitor events"),
@@ -78,6 +86,9 @@ Volume::Volume(BLooper* looper)
 
 Volume::~Volume()
 {
+	Unmounted();
+		// need for error case in InitPackages()
+
 	fPackagesByFileName.Clear();
 
 	Package* package = fPackagesByNodeRef.Clear(true);
@@ -153,7 +164,7 @@ Volume::Init(const node_ref& rootDirectoryRef, node_ref& _packageRootRef)
 
 
 status_t
-Volume::InitPackages()
+Volume::InitPackages(Listener* listener)
 {
 	// node-monitor the volume's packages directory
 	status_t error = watch_node(&fPackagesDirectoryRef, B_WATCH_DIRECTORY,
@@ -166,6 +177,8 @@ Volume::InitPackages()
 		// packages directory won't work correctly.
 	}
 
+	fListener = listener;
+
 	// read the packages directory and get the active packages
 	int fd = OpenRootDirectory();
 	if (fd < 0) {
@@ -190,7 +203,13 @@ Volume::InitPackages()
 void
 Volume::Unmounted()
 {
-	stop_watching(BMessenger(this));
+	if (fListener != NULL) {
+		stop_watching(BMessenger(this));
+		fListener = NULL;
+	}
+
+	if (BLooper* looper = Looper())
+		looper->RemoveHandler(this);
 }
 
 
@@ -324,10 +343,12 @@ Volume::_QueueNodeMonitorEvent(const BString& name, bool wasCreated)
 	}
 
 	AutoLocker eventsLock(fPendingNodeMonitorEventsLock);
+	bool firstEvent = fPendingNodeMonitorEvents.IsEmpty();
 	fPendingNodeMonitorEvents.Add(event);
 	eventsLock.Unlock();
 
-	fRoot->HandleNodeMonitorEvents(this);
+	if (firstEvent && fListener != NULL)
+		fListener->VolumeNodeMonitorEventOccurred(this);
 }
 
 
diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h
index c791cae258..24eab04c6d 100644
--- a/src/servers/package/Volume.h
+++ b/src/servers/package/Volume.h
@@ -25,13 +25,16 @@ class Root;
 
 
 class Volume : public BHandler {
+public:
+			class Listener;
+
 public:
 								Volume(BLooper* looper);
 	virtual						~Volume();
 
 			status_t			Init(const node_ref& rootDirectoryRef,
 									node_ref& _packageRootRef);
-			status_t			InitPackages();
+			status_t			InitPackages(Listener* listener);
 
 			void				Unmounted();
 
@@ -88,6 +91,7 @@ private:
 			node_ref			fRootDirectoryRef;
 			node_ref			fPackagesDirectoryRef;
 			Root*				fRoot;
+			Listener*			fListener;
 			PackageFileNameHashTable fPackagesByFileName;
 			PackageNodeRefHashTable fPackagesByNodeRef;
 			BLocker				fPendingNodeMonitorEventsLock;
@@ -95,4 +99,13 @@ private:
 };
 
 
+class Volume::Listener {
+public:
+	virtual						~Listener();
+
+	virtual	void				VolumeNodeMonitorEventOccurred(Volume* volume)
+									= 0;
+};
+
+
 #endif	// VOLUME_H

From 91a9b5f2765833cec3bfeda5f4962f45931dbe9d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 8 Apr 2013 15:21:26 +0200
Subject: [PATCH 0371/1170] package daemon: Volume: Make sure move entry events
 don't get split

---
 src/servers/package/Volume.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index a1945c1e77..d504b1723d 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -320,6 +320,9 @@ Volume::_HandleEntryMoved(const BMessage* message)
 		return;
 	}
 
+	AutoLocker eventsLock(fPendingNodeMonitorEventsLock);
+		// make sure for a move the two events cannot get split
+
 	if (fromDirectoryID == fPackagesDirectoryRef.node)
 		_QueueNodeMonitorEvent(fromName, false);
 	if (toDirectoryID == fPackagesDirectoryRef.node)

From 379131d97d1bda4b50a0a384c36abd239783cc83 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 8 Apr 2013 15:44:31 +0200
Subject: [PATCH 0372/1170] BString: Add StartsWith() and EndsWith() methods

---
 headers/os/support/String.h |  8 ++++++
 src/kits/support/String.cpp | 49 +++++++++++++++++++++++++++++++++++++
 2 files changed, 57 insertions(+)

diff --git a/headers/os/support/String.h b/headers/os/support/String.h
index bbe5354d51..a487a040e3 100644
--- a/headers/os/support/String.h
+++ b/headers/os/support/String.h
@@ -221,6 +221,14 @@ public:
 			int32			IFindLast(const char* string,
 								int32 beforeOffset) const;
 
+			bool			StartsWith(const BString& string) const;
+			bool			StartsWith(const char* string) const;
+			bool			StartsWith(const char* string, int32 length) const;
+
+			bool			EndsWith(const BString& string) const;
+			bool			EndsWith(const char* string) const;
+			bool			EndsWith(const char* string, int32 length) const;
+
 			// Replacing
 			BString&		ReplaceFirst(char replaceThis, char withThis);
 			BString&		ReplaceLast(char replaceThis, char withThis);
diff --git a/src/kits/support/String.cpp b/src/kits/support/String.cpp
index 990100f7cc..36936cf9f1 100644
--- a/src/kits/support/String.cpp
+++ b/src/kits/support/String.cpp
@@ -1362,6 +1362,55 @@ BString::IFindLast(const char* string, int32 beforeOffset) const
 }
 
 
+bool
+BString::StartsWith(const BString& string) const
+{
+	return StartsWith(string.String(), string.Length());
+}
+
+
+bool
+BString::StartsWith(const char* string) const
+{
+	return StartsWith(string, strlen(string));
+}
+
+
+bool
+BString::StartsWith(const char* string, int32 length) const
+{
+	if (length > Length())
+		return false;
+
+	return memcmp(String(), string, length) == 0;
+}
+
+
+bool
+BString::EndsWith(const BString& string) const
+{
+	return EndsWith(string.String(), string.Length());
+}
+
+
+bool
+BString::EndsWith(const char* string) const
+{
+	return EndsWith(string, strlen(string));
+}
+
+
+bool
+BString::EndsWith(const char* string, int32 length) const
+{
+	int32 offset = Length() - length;
+	if (offset < 0)
+		return false;
+
+	return memcmp(String() + offset, string, length) == 0;
+}
+
+
 //	#pragma mark - Replacing
 
 

From def92c01eec2711ecf3bc42c64d92be7c90c650f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 8 Apr 2013 15:45:47 +0200
Subject: [PATCH 0373/1170] packagefs/daemon: Ignore packages/ entries without
 .hpkg suffix

---
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp |  7 +++++++
 src/servers/package/Volume.cpp                       | 10 ++++++++++
 2 files changed, 17 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 523189d082..2a2c924e3e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -807,6 +807,13 @@ Volume::_AddInitialPackages()
 		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
 			continue;
 
+		// also skip any entry without a ".hpkg" extension
+		size_t nameLength = strlen(entry->d_name);
+		if (nameLength < 5
+			|| memcmp(entry->d_name + nameLength - 5, ".hpkg", 5) != 0) {
+			continue;
+		}
+
 		Package* package;
 		if (_LoadPackage(entry->d_name, package) != B_OK)
 			continue;
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index d504b1723d..014540d64f 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -26,6 +26,9 @@
 #include "DebugSupport.h"
 
 
+static const char* kPackageFileNameExtension = ".hpkg";
+
+
 // #pragma mark - Listener
 
 
@@ -338,6 +341,10 @@ Volume::_QueueNodeMonitorEvent(const BString& name, bool wasCreated)
 		return;
 	}
 
+	// ignore entries that don't have the ".hpkg" extension
+	if (!name.EndsWith(kPackageFileNameExtension))
+		return;
+
 	NodeMonitorEvent* event
 		= new(std::nothrow) NodeMonitorEvent(name, wasCreated);
 	if (event == NULL) {
@@ -497,6 +504,9 @@ Volume::_ReadPackagesDirectory()
 
 	entry_ref entry;
 	while (directory.GetNextRef(&entry) == B_OK) {
+		if (!BString(entry.name).EndsWith(kPackageFileNameExtension))
+			continue;
+
 		Package* package = new(std::nothrow) Package;
 		if (package == NULL)
 			RETURN_ERROR(B_NO_MEMORY);

From bb88feaa3a3c83e4a0f6b3de355ecb57b426f4cc Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 8 Apr 2013 17:44:43 +0200
Subject: [PATCH 0374/1170] PackageFSActivationChangeRequest: Make items array
 0 sized

That's more convenient to use and the actual size of an item is variable
anyway.
---
 headers/private/package/packagefs.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/headers/private/package/packagefs.h b/headers/private/package/packagefs.h
index 29ef4a11c7..d7ef1a9dc0 100644
--- a/headers/private/package/packagefs.h
+++ b/headers/private/package/packagefs.h
@@ -84,7 +84,7 @@ struct PackageFSActivationChangeItem {
 
 struct PackageFSActivationChangeRequest {
 	uint32							itemCount;
-	PackageFSActivationChangeItem	items[1];
+	PackageFSActivationChangeItem	items[0];
 };
 
 

From 2508cd615fdcbdefcf8b913a5ef23a267499d924 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 8 Apr 2013 17:45:24 +0200
Subject: [PATCH 0375/1170] packagefs: Volume::_ChangeActivation(): Check 0
 request size

---
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 2a2c924e3e..f31fb43e7d 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -1362,6 +1362,9 @@ Volume::_LoadPackage(const char* name, Package*& _package)
 status_t
 Volume::_ChangeActivation(ActivationChangeRequest& request)
 {
+	if (request.CountItems() == 0)
+		return B_OK;
+
 	// first check the request
 	int32 newPackageCount = 0;
 	int32 oldPackageCount = 0;

From ebbefc0151ffae360647cf2ee50a5b28c63bda80 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 8 Apr 2013 17:49:14 +0200
Subject: [PATCH 0376/1170] package daemon: Root: Use a common job for volume
 work

Add VolumeJob which, besides the Volume, takes a Root method to be
invoked. That allows to replace the specific job classes by simple
methods.
---
 src/servers/package/Root.cpp | 81 +++++++++++++++---------------------
 src/servers/package/Root.h   | 10 ++---
 2 files changed, 38 insertions(+), 53 deletions(-)

diff --git a/src/servers/package/Root.cpp b/src/servers/package/Root.cpp
index f05dcc66cb..6c2f505531 100644
--- a/src/servers/package/Root.cpp
+++ b/src/servers/package/Root.cpp
@@ -16,63 +16,25 @@
 #include "DebugSupport.h"
 
 
-// #pragma mark - InitVolumePackagesJob
+// #pragma mark - VolumeJob
 
 
-struct Root::InitPackagesJob : public Job {
-	InitPackagesJob(Volume* volume)
+struct Root::VolumeJob : public Job {
+	VolumeJob(Volume* volume, void (Root::*method)(Volume*))
 		:
-		fVolume(volume)
+		fVolume(volume),
+		fMethod(method)
 	{
 	}
 
 	virtual void Do()
 	{
-		fVolume->InitPackages(fVolume->GetRoot());
-	}
-
-private:
-	Volume*	fVolume;
-};
-
-
-// #pragma mark - DeleteVolumeJob
-
-
-struct Root::DeleteVolumeJob : public Job {
-	DeleteVolumeJob(Volume* volume)
-		:
-		fVolume(volume)
-	{
-	}
-
-	virtual void Do()
-	{
-		delete fVolume;
-	}
-
-private:
-	Volume*	fVolume;
-};
-
-
-// #pragma mark - HandleNodeMonitorEventsJob
-
-
-struct Root::HandleNodeMonitorEventsJob : public Job {
-	HandleNodeMonitorEventsJob(Volume* volume)
-		:
-		fVolume(volume)
-	{
-	}
-
-	virtual void Do()
-	{
-		fVolume->ProcessPendingNodeMonitorEvents();
+		(fVolume->GetRoot()->*fMethod)(fVolume);
 	}
 
 private:
 	Volume*	fVolume;
+	void	(Root::*fMethod)(Volume*);
 };
 
 
@@ -165,7 +127,8 @@ Root::RegisterVolume(Volume* volume)
 	volume->SetRoot(this);
 
 	// queue a job for reading the volume's packages
-	status_t error = _QueueJob(new(std::nothrow) InitPackagesJob(volume));
+	status_t error = _QueueJob(
+		new(std::nothrow) VolumeJob(volume, &Root::_InitPackages));
 	if (error != B_OK) {
 		volume->SetRoot(NULL);
 		*volumeToSet = NULL;
@@ -190,7 +153,7 @@ Root::UnregisterVolume(Volume* volume)
 
 	// Use the job queue to delete the volume to make sure there aren't any
 	// pending jobs that reference the volume.
-	_QueueJob(new(std::nothrow) DeleteVolumeJob(volume));
+	_QueueJob(new(std::nothrow) VolumeJob(volume, &Root::_DeleteVolume));
 }
 
 
@@ -211,7 +174,8 @@ Root::FindVolume(dev_t deviceID) const
 void
 Root::VolumeNodeMonitorEventOccurred(Volume* volume)
 {
-	_QueueJob(new(std::nothrow) HandleNodeMonitorEventsJob(volume));
+	_QueueJob(
+		new(std::nothrow) VolumeJob(volume, &Root::_ProcessNodeMonitorEvents));
 }
 
 
@@ -238,6 +202,27 @@ Root::_GetVolume(PackageFSMountType mountType)
 }
 
 
+void
+Root::_InitPackages(Volume* volume)
+{
+	volume->InitPackages(this);
+}
+
+
+void
+Root::_DeleteVolume(Volume* volume)
+{
+	delete volume;
+}
+
+
+void
+Root::_ProcessNodeMonitorEvents(Volume* volume)
+{
+	volume->ProcessPendingNodeMonitorEvents();
+}
+
+
 status_t
 Root::_QueueJob(Job* job)
 {
diff --git a/src/servers/package/Root.h b/src/servers/package/Root.h
index 2c7f328f08..b2afd2c6e9 100644
--- a/src/servers/package/Root.h
+++ b/src/servers/package/Root.h
@@ -48,15 +48,15 @@ protected:
 	virtual	void				LastReferenceReleased();
 
 private:
-			struct InitPackagesJob;
-			struct DeleteVolumeJob;
-			struct HandleNodeMonitorEventsJob;
-
-			friend struct InitPackagesJob;
+			struct VolumeJob;
 
 private:
 			Volume**			_GetVolume(PackageFSMountType mountType);
 
+			void				_InitPackages(Volume* volume);
+			void				_DeleteVolume(Volume* volume);
+			void				_ProcessNodeMonitorEvents(Volume* volume);
+
 			status_t			_QueueJob(Job* job);
 
 	static	status_t			_JobRunnerEntry(void* data);

From a6c7f5e33c2a4e8596b2901d2fbecdd579d47b36 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 8 Apr 2013 19:06:18 +0200
Subject: [PATCH 0377/1170] package daemon: De/-activate all changed packages
 together

* We first process the node monitoring events, collecting the required
  package activation changes, then apply all changes together.
* Change the PackageFSActivationChangeItem/-Request structs. The former
  is no longer variable in size, which makes it easier to work with.
---
 headers/private/package/packagefs.h           |   4 +-
 .../kernel/file_systems/packagefs/Volume.cpp  | 106 ++-------
 src/servers/package/Root.cpp                  |   3 +
 src/servers/package/Volume.cpp                | 224 +++++++++++-------
 src/servers/package/Volume.h                  |  15 ++
 5 files changed, 187 insertions(+), 165 deletions(-)

diff --git a/headers/private/package/packagefs.h b/headers/private/package/packagefs.h
index d7ef1a9dc0..8768e6c0ef 100644
--- a/headers/private/package/packagefs.h
+++ b/headers/private/package/packagefs.h
@@ -79,7 +79,9 @@ struct PackageFSActivationChangeItem {
 	uint32							nameLength;
 	dev_t							parentDeviceID;
 	ino_t							parentDirectoryID;
-	char							name[1];
+	char*							name;
+										// must point to a location within the
+										// request
 };
 
 struct PackageFSActivationChangeRequest {
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index f31fb43e7d..16126af844 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -199,49 +199,6 @@ private:
 
 
 struct Volume::ActivationChangeRequest {
-public:
-	struct Iterator {
-		Iterator()
-			:
-			fRequest(NULL),
-			fNextItem(NULL),
-			fNextIndex(0)
-		{
-		}
-
-		Iterator(PackageFSActivationChangeRequest* request)
-			:
-			fRequest(request),
-			fNextItem(NULL),
-			fNextIndex(0)
-		{
-			if (fRequest != NULL && fRequest->itemCount > 0)
-				fNextItem = fRequest->items;
-		}
-
-		bool HasNext() const
-		{
-			return fNextItem != NULL;
-		}
-
-		PackageFSActivationChangeItem* Next()
-		{
-			if (fNextItem == NULL)
-				return NULL;
-
-			PackageFSActivationChangeItem* item = fNextItem;
-			fNextIndex++;
-			fNextItem = fNextIndex < fRequest->itemCount
-				? _NextItem(fNextItem) : NULL;
-			return item;
-		}
-
-	private:
-		PackageFSActivationChangeRequest*	fRequest;
-		PackageFSActivationChangeItem*		fNextItem;
-		uint32								fNextIndex;
-	};
-
 public:
 	ActivationChangeRequest()
 		:
@@ -270,22 +227,21 @@ public:
 		if (error != B_OK)
 			RETURN_ERROR(error);
 
-		// check the validity of the items
-		addr_t requestEnd = (addr_t)fRequest + fRequestSize;
-		uint32 itemCount = 0;
-		PackageFSActivationChangeItem* item = fRequest->items;
-		while (itemCount < fRequest->itemCount) {
-			if ((addr_t)item + sizeof(PackageFSActivationChangeItem)
-					> requestEnd
-				|| item->nameLength > B_FILE_NAME_LENGTH
-				|| (addr_t)item->name + item->nameLength > requestEnd
-				|| item->name[item->nameLength] != '\0'
-				|| strlen(item->name) != item->nameLength) {
-				RETURN_ERROR(B_BAD_VALUE);
-			}
+		uint32 itemCount = fRequest->itemCount;
+		const char* requestEnd = (const char*)fRequest + requestSize;
+		if (&fRequest->items[itemCount] > (void*)requestEnd)
+			RETURN_ERROR(B_BAD_VALUE);
 
-			itemCount++;
-			item = _NextItem(item);
+		// adjust the item name pointers and check their validity
+		addr_t nameDelta = (addr_t)fRequest - (addr_t)userRequest;
+		for (uint32 i = 0; i < itemCount; i++) {
+			PackageFSActivationChangeItem& item = fRequest->items[i];
+			item.name += nameDelta;
+			if (item.name < (char*)fRequest || item.name >= requestEnd)
+				RETURN_ERROR(B_BAD_VALUE);
+			size_t maxNameSize = requestEnd - item.name;
+			if (strnlen(item.name, maxNameSize) == maxNameSize)
+				RETURN_ERROR(B_BAD_VALUE);
 		}
 
 		return B_OK;
@@ -296,21 +252,9 @@ public:
 		return fRequest->itemCount;
 	}
 
-	Iterator GetIterator() const
+	PackageFSActivationChangeItem* ItemAt(uint32 index) const
 	{
-		return Iterator(fRequest);
-	}
-
-private:
-	friend class Iterator;
-		// for GCC 2
-
-private:
-	static inline PackageFSActivationChangeItem* _NextItem(
-		PackageFSActivationChangeItem* item)
-	{
-		return (PackageFSActivationChangeItem*)_ALIGN(
-			(addr_t)item->name + item->nameLength);
+		return index < CountItems() ? &fRequest->items[index] : NULL;
 	}
 
 private:
@@ -1362,7 +1306,8 @@ Volume::_LoadPackage(const char* name, Package*& _package)
 status_t
 Volume::_ChangeActivation(ActivationChangeRequest& request)
 {
-	if (request.CountItems() == 0)
+	uint32 itemCount = request.CountItems();
+	if (itemCount == 0)
 		return B_OK;
 
 	// first check the request
@@ -1371,9 +1316,8 @@ Volume::_ChangeActivation(ActivationChangeRequest& request)
 	{
 		VolumeReadLocker volumeLocker(this);
 
-		for (ActivationChangeRequest::Iterator it = request.GetIterator();
-			it.HasNext();) {
-			PackageFSActivationChangeItem* item = it.Next();
+		for (uint32 i = 0; i < itemCount; i++) {
+			PackageFSActivationChangeItem* item = request.ItemAt(i);
 			if (item->parentDeviceID != fPackagesDirectory->DeviceID()
 				|| item->parentDirectoryID != fPackagesDirectory->NodeID()) {
 				ERROR("Volume::_ChangeActivation(): mismatching packages "
@@ -1429,9 +1373,8 @@ INFORM("Volume::_ChangeActivation(): %" B_PRId32 " new packages, %" B_PRId32 " o
 
 	// load all new packages
 	int32 newPackageIndex = 0;
-	for (ActivationChangeRequest::Iterator it = request.GetIterator();
-		it.HasNext();) {
-		PackageFSActivationChangeItem* item = it.Next();
+	for (uint32 i = 0; i < itemCount; i++) {
+		PackageFSActivationChangeItem* item = request.ItemAt(i);
 
 		if (item->type != PACKAGE_FS_ACTIVATE_PACKAGE
 			&& item->type != PACKAGE_FS_REACTIVATE_PACKAGE) {
@@ -1457,9 +1400,8 @@ INFORM("Volume::_ChangeActivation(): %" B_PRId32 " new packages, %" B_PRId32 " o
 
 	// remove the old packages
 	int32 oldPackageIndex = 0;
-	for (ActivationChangeRequest::Iterator it = request.GetIterator();
-		it.HasNext();) {
-		PackageFSActivationChangeItem* item = it.Next();
+	for (uint32 i = 0; i < itemCount; i++) {
+		PackageFSActivationChangeItem* item = request.ItemAt(i);
 
 		if (item->type != PACKAGE_FS_DEACTIVATE_PACKAGE
 			&& item->type != PACKAGE_FS_REACTIVATE_PACKAGE) {
diff --git a/src/servers/package/Root.cpp b/src/servers/package/Root.cpp
index 6c2f505531..7a138789a5 100644
--- a/src/servers/package/Root.cpp
+++ b/src/servers/package/Root.cpp
@@ -220,6 +220,9 @@ void
 Root::_ProcessNodeMonitorEvents(Volume* volume)
 {
 	volume->ProcessPendingNodeMonitorEvents();
+
+	if (volume->HasPendingPackageActivationChanges())
+		volume->ProcessPendingPackageActivationChanges();
 }
 
 
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index 014540d64f..b1e1d6a74a 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -81,7 +81,9 @@ Volume::Volume(BLooper* looper)
 	fPackagesByFileName(),
 	fPackagesByNodeRef(),
 	fPendingNodeMonitorEventsLock("pending node monitor events"),
-	fPendingNodeMonitorEvents()
+	fPendingNodeMonitorEvents(),
+	fPackagesToBeActivated(),
+	fPackagesToBeDeactivated()
 {
 	looper->AddHandler(this);
 }
@@ -275,7 +277,6 @@ Volume::ProcessPendingNodeMonitorEvents()
 	}
 
 	// process them
-// TODO: Don't do that individually.
 	while (NodeMonitorEvent* event = events.RemoveHead()) {
 		ObjectDeleter eventDeleter(event);
 		if (event->WasCreated())
@@ -286,6 +287,100 @@ Volume::ProcessPendingNodeMonitorEvents()
 }
 
 
+bool
+Volume::HasPendingPackageActivationChanges() const
+{
+	return !fPackagesToBeActivated.empty() || !fPackagesToBeDeactivated.empty();
+}
+
+
+void
+Volume::ProcessPendingPackageActivationChanges()
+{
+	if (!HasPendingPackageActivationChanges())
+		return;
+INFORM("Volume::ProcessPendingPackageActivationChanges(): activating %zu, deactivating %zu packages\n",
+fPackagesToBeActivated.size(), fPackagesToBeDeactivated.size());
+
+	// compute the size of the allocation we need for the activation change
+	// request
+	int32 itemCount
+		= fPackagesToBeActivated.size() + fPackagesToBeDeactivated.size();
+	size_t requestSize = sizeof(PackageFSActivationChangeRequest)
+		+ itemCount * sizeof(PackageFSActivationChangeItem);
+
+	for (PackageSet::iterator it = fPackagesToBeActivated.begin();
+		 it != fPackagesToBeActivated.end(); ++it) {
+		requestSize += (*it)->FileName().Length() + 1;
+	}
+
+	for (PackageSet::iterator it = fPackagesToBeDeactivated.begin();
+		 it != fPackagesToBeDeactivated.end(); ++it) {
+		requestSize += (*it)->FileName().Length() + 1;
+	}
+
+	// allocate and prepare the request
+	PackageFSActivationChangeRequest* request
+		= (PackageFSActivationChangeRequest*)malloc(requestSize);
+	if (request == NULL) {
+		ERROR("out of memory\n");
+		return;
+	}
+	MemoryDeleter requestDeleter(request);
+
+	request->itemCount = itemCount;
+
+	PackageFSActivationChangeItem* item = &request->items[0];
+	char* nameBuffer = (char*)(item + itemCount);
+
+	for (PackageSet::iterator it = fPackagesToBeActivated.begin();
+		it != fPackagesToBeActivated.end(); ++it, item++) {
+		_FillInActivationChangeItem(item, PACKAGE_FS_ACTIVATE_PACKAGE, *it,
+			nameBuffer);
+	}
+
+	for (PackageSet::iterator it = fPackagesToBeDeactivated.begin();
+		it != fPackagesToBeDeactivated.end(); ++it, item++) {
+		_FillInActivationChangeItem(item, PACKAGE_FS_DEACTIVATE_PACKAGE, *it,
+			nameBuffer);
+	}
+
+	// issue the request
+	int fd = OpenRootDirectory();
+	if (fd < 0) {
+		ERROR("Volume::ProcessPendingPackageActivationChanges(): failed to "
+			"open root directory: %s", strerror(fd));
+		return;
+	}
+	FileDescriptorCloser fdCloser(fd);
+
+	if (ioctl(fd, PACKAGE_FS_OPERATION_CHANGE_ACTIVATION, request, requestSize)
+			!= 0) {
+// TODO: We need more error information and error handling!
+		ERROR("Volume::ProcessPendingPackageActivationChanges(): failed to "
+			"activate packages: %s\n", strerror(errno));
+		return;
+	}
+
+	// Update our state, i.e. remove deactivated packages and mark activated
+	// packages accordingly.
+	for (PackageSet::iterator it = fPackagesToBeActivated.begin();
+		it != fPackagesToBeActivated.end(); ++it) {
+		(*it)->SetActive(true);
+	}
+
+	for (PackageSet::iterator it = fPackagesToBeDeactivated.begin();
+		it != fPackagesToBeDeactivated.end(); ++it) {
+		Package* package = *it;
+		_RemovePackage(package);
+		delete package;
+	}
+
+	fPackagesToBeActivated.clear();
+	fPackagesToBeDeactivated.clear();
+}
+
+
 void
 Volume::_HandleEntryCreatedOrRemoved(const BMessage* message, bool created)
 {
@@ -371,13 +466,13 @@ INFORM("Volume::_PackagesEntryCreated(\"%s\")\n", name);
 	entry.directory = fPackagesDirectoryRef.node;
 	status_t error = entry.set_name(name);
 	if (error != B_OK) {
-		ERROR("out of memory");
+		ERROR("out of memory\n");
 		return;
 	}
 
 	Package* package = new(std::nothrow) Package;
 	if (package == NULL) {
-		ERROR("out of memory");
+		ERROR("out of memory\n");
 		return;
 	}
 	ObjectDeleter packageDeleter(package);
@@ -392,46 +487,12 @@ INFORM("Volume::_PackagesEntryCreated(\"%s\")\n", name);
 	fPackagesByNodeRef.Insert(package);
 	packageDeleter.Detach();
 
-	// activate package
-// TODO: Don't do that here!
-	size_t nameLength = strlen(package->FileName());
-	size_t requestSize = sizeof(PackageFSActivationChangeRequest) + nameLength;
-	PackageFSActivationChangeRequest* request
-		= (PackageFSActivationChangeRequest*)malloc(requestSize);
-	if (request == NULL) {
-		ERROR("out of memory");
+	try {
+		fPackagesToBeActivated.insert(package);
+	} catch (std::bad_alloc& exception) {
+		ERROR("out of memory\n");
 		return;
 	}
-	MemoryDeleter requestDeleter(request);
-
-	request->itemCount = 1;
-	PackageFSActivationChangeItem& item = request->items[0];
-	item.type = PACKAGE_FS_ACTIVATE_PACKAGE;
-
-	item.packageDeviceID = package->NodeRef().device;
-	item.packageNodeID = package->NodeRef().node;
-
-	item.nameLength = nameLength;
-	item.parentDeviceID = fPackagesDirectoryRef.device;
-	item.parentDirectoryID = fPackagesDirectoryRef.node;
-	strcpy(item.name, package->FileName());
-
-	int fd = OpenRootDirectory();
-	if (fd < 0) {
-		ERROR("Volume::_PackagesEntryCreated(): failed to open root directory: "
-			"%s", strerror(fd));
-		return;
-	}
-	FileDescriptorCloser fdCloser(fd);
-
-	if (ioctl(fd, PACKAGE_FS_OPERATION_CHANGE_ACTIVATION, request, requestSize)
-			!= 0) {
-		ERROR("Volume::_PackagesEntryCreated(): activate packages: %s\n",
-			strerror(errno));
-		return;
-	}
-
-	package->SetActive(true);
 }
 
 
@@ -443,51 +504,50 @@ INFORM("Volume::_PackagesEntryRemoved(\"%s\")\n", name);
 	if (package == NULL)
 		return;
 
-	if (package->IsActive()) {
-		// deactivate the package
-// TODO: Don't do that here!
-		size_t nameLength = strlen(package->FileName());
-		size_t requestSize = sizeof(PackageFSActivationChangeRequest)
-			+ nameLength;
-		PackageFSActivationChangeRequest* request
-			= (PackageFSActivationChangeRequest*)malloc(requestSize);
-		if (request == NULL) {
-			ERROR("out of memory");
-			return;
-		}
-		MemoryDeleter requestDeleter(request);
+	// Remove the package from the packages-to-be-activated set, if it is in
+	// there (unlikely, unless we see a create-remove-create sequence).
+	PackageSet::iterator it = fPackagesToBeActivated.find(package);
+	if (it != fPackagesToBeActivated.end())
+		fPackagesToBeActivated.erase(it);
 
-		request->itemCount = 1;
-		PackageFSActivationChangeItem& item = request->items[0];
-		item.type = PACKAGE_FS_DEACTIVATE_PACKAGE;
-
-		item.packageDeviceID = package->NodeRef().device;
-		item.packageNodeID = package->NodeRef().node;
-
-		item.nameLength = nameLength;
-		item.parentDeviceID = fPackagesDirectoryRef.device;
-		item.parentDirectoryID = fPackagesDirectoryRef.node;
-		strcpy(item.name, package->FileName());
-
-		int fd = OpenRootDirectory();
-		if (fd < 0) {
-			ERROR("Volume::_PackagesEntryRemoved(): failed to open root "
-				"directory: %s", strerror(fd));
-			return;
-		}
-		FileDescriptorCloser fdCloser(fd);
-
-		if (ioctl(fd, PACKAGE_FS_OPERATION_CHANGE_ACTIVATION, request,
-				requestSize) != 0) {
-			ERROR("Volume::_PackagesEntryRemoved(): activate packages: %s\n",
-				strerror(errno));
-			return;
-		}
+	// If the package isn't active, just remove it for good.
+	if (!package->IsActive()) {
+		_RemovePackage(package);
+		delete package;
+		return;
 	}
 
+	// The package must be deactivated.
+	try {
+		fPackagesToBeDeactivated.insert(package);
+	} catch (std::bad_alloc& exception) {
+		ERROR("out of memory\n");
+		return;
+	}
+}
+
+
+void
+Volume::_FillInActivationChangeItem(PackageFSActivationChangeItem* item,
+	PackageFSActivationChangeType type, Package* package, char*& nameBuffer)
+{
+	item->type = type;
+	item->packageDeviceID = package->NodeRef().device;
+	item->packageNodeID = package->NodeRef().node;
+	item->nameLength = package->FileName().Length();
+	item->parentDeviceID = fPackagesDirectoryRef.device;
+	item->parentDirectoryID = fPackagesDirectoryRef.node;
+	item->name = nameBuffer;
+	strcpy(nameBuffer, package->FileName());
+	nameBuffer += package->FileName().Length() + 1;
+}
+
+
+void
+Volume::_RemovePackage(Package* package)
+{
 	fPackagesByFileName.Remove(package);
 	fPackagesByNodeRef.Remove(package);
-	delete package;
 }
 
 
diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h
index 24eab04c6d..b83bc401cd 100644
--- a/src/servers/package/Volume.h
+++ b/src/servers/package/Volume.h
@@ -9,6 +9,8 @@
 #define VOLUME_H
 
 
+#include 
+
 #include 
 #include 
 #include 
@@ -68,10 +70,15 @@ public:
 
 			void				ProcessPendingNodeMonitorEvents();
 
+			bool				HasPendingPackageActivationChanges() const;
+			void				ProcessPendingPackageActivationChanges();
+
 private:
 			struct NodeMonitorEvent;
 			typedef DoublyLinkedList NodeMonitorEventList;
 
+			typedef std::set PackageSet;
+
 private:
 			void				_HandleEntryCreatedOrRemoved(
 									const BMessage* message, bool created);
@@ -82,6 +89,12 @@ private:
 			void				_PackagesEntryCreated(const char* name);
 			void				_PackagesEntryRemoved(const char* name);
 
+			void				_FillInActivationChangeItem(
+									PackageFSActivationChangeItem* item,
+									PackageFSActivationChangeType type,
+									Package* package, char*& nameBuffer);
+			void				_RemovePackage(Package* package);
+
 			status_t			_ReadPackagesDirectory();
 			status_t			_GetActivePackages(int fd);
 
@@ -96,6 +109,8 @@ private:
 			PackageNodeRefHashTable fPackagesByNodeRef;
 			BLocker				fPendingNodeMonitorEventsLock;
 			NodeMonitorEventList fPendingNodeMonitorEvents;
+			PackageSet			fPackagesToBeActivated;
+			PackageSet			fPackagesToBeDeactivated;
 };
 
 

From 1047e84f39654c67e966afd0b41d3488d8d9b09d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 8 Apr 2013 20:53:32 +0200
Subject: [PATCH 0378/1170] package daemon: Volume::InitPackages(): Fix error
 case

Don't assign fListener, when starting node monitoring fails.
---
 src/servers/package/Volume.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index b1e1d6a74a..b3664924f0 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -174,7 +174,9 @@ Volume::InitPackages(Listener* listener)
 	// node-monitor the volume's packages directory
 	status_t error = watch_node(&fPackagesDirectoryRef, B_WATCH_DIRECTORY,
 		BMessenger(this));
-	if (error != B_OK) {
+	if (error == B_OK) {
+		fListener = listener;
+	} else {
 		ERROR("Volume::InitPackages(): failed to start watching the packages "
 			"directory of the volume at \"%s\": %s\n",
 			fPath.String(), strerror(error));
@@ -182,8 +184,6 @@ Volume::InitPackages(Listener* listener)
 		// packages directory won't work correctly.
 	}
 
-	fListener = listener;
-
 	// read the packages directory and get the active packages
 	int fd = OpenRootDirectory();
 	if (fd < 0) {

From 5e01af3199254d0f5fd666b32b073a5283230021 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 9 Apr 2013 17:24:27 +0200
Subject: [PATCH 0379/1170] package kit: Add data structures for problem
 solutions

... and add the problem solutions in LibsolvSolver.
---
 headers/os/package/solver/SolverProblem.h     |  12 +
 .../os/package/solver/SolverProblemSolution.h |  90 +++++++
 src/kits/package/Jamfile                      |   1 +
 src/kits/package/solver/LibsolvSolver.cpp     | 242 +++++++++++++++++-
 src/kits/package/solver/LibsolvSolver.h       |  13 +-
 src/kits/package/solver/SolverProblem.cpp     |  30 ++-
 .../package/solver/SolverProblemSolution.cpp  | 157 ++++++++++++
 7 files changed, 539 insertions(+), 6 deletions(-)
 create mode 100644 headers/os/package/solver/SolverProblemSolution.h
 create mode 100644 src/kits/package/solver/SolverProblemSolution.cpp

diff --git a/headers/os/package/solver/SolverProblem.h b/headers/os/package/solver/SolverProblem.h
index f660837fbf..4cd6df8668 100644
--- a/headers/os/package/solver/SolverProblem.h
+++ b/headers/os/package/solver/SolverProblem.h
@@ -6,6 +6,7 @@
 #define _PACKAGE__SOLVER_PROBLEM_H_
 
 
+#include 
 #include 
 
 
@@ -13,6 +14,7 @@ namespace BPackageKit {
 
 
 class BSolverPackage;
+class BSolverProblemSolution;
 
 
 class BSolverProblem {
@@ -53,13 +55,23 @@ public:
 			BSolverPackage*		TargetPackage() const;
 			const BPackageResolvableExpression& Dependency() const;
 
+			int32				CountSolutions() const;
+			const BSolverProblemSolution* SolutionAt(int32 index) const;
+
+			bool				AppendSolution(
+									BSolverProblemSolution* solution);
+
 			BString				ToString() const;
 
+private:
+			typedef BObjectList SolutionList;
+
 private:
 			BType				fType;
 			BSolverPackage*		fSourcePackage;
 			BSolverPackage*		fTargetPackage;
 			BPackageResolvableExpression fDependency;
+			SolutionList		fSolutions;
 };
 
 
diff --git a/headers/os/package/solver/SolverProblemSolution.h b/headers/os/package/solver/SolverProblemSolution.h
new file mode 100644
index 0000000000..767611d14f
--- /dev/null
+++ b/headers/os/package/solver/SolverProblemSolution.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__SOLVER_PROBLEM_SOLUTION_H_
+#define _PACKAGE__SOLVER_PROBLEM_SOLUTION_H_
+
+
+#include 
+#include 
+
+
+namespace BPackageKit {
+
+
+class BSolverPackage;
+
+
+class BSolverProblemSolutionElement {
+public:
+			enum BType {
+				B_UNSPECIFIED,
+				B_DONT_KEEP,
+				B_DONT_INSTALL,
+				B_DONT_INSTALL_MOST_RECENT,
+				B_DONT_FORBID_INSTALLATION,
+				B_DONT_DEINSTALL,
+				B_DONT_DEINSTALL_ALL,
+				B_DONT_LOCK,
+				B_KEEP_INFERIOR_ARCHITECTURE,
+				B_KEEP_EXCLUDED,
+				B_KEEP_OLD,
+				B_INSTALL_INFERIOR_ARCHITECTURE,
+				B_INSTALL_EXCLUDED,
+				B_INSTALL_OLD,
+				B_ALLOW_DOWNGRADE,
+				B_ALLOW_NAME_CHANGE,
+				B_ALLOW_ARCHITECTURE_CHANGE,
+				B_ALLOW_VENDOR_CHANGE,
+				B_ALLOW_REPLACEMENT,
+				B_ALLOW_DEINSTALLATION
+			};
+
+public:
+								BSolverProblemSolutionElement(BType type,
+									BSolverPackage* sourcePackage,
+									BSolverPackage* targetPackage,
+									const BString& selection);
+								~BSolverProblemSolutionElement();
+
+			BType				Type() const;
+			BSolverPackage*		SourcePackage() const;
+			BSolverPackage*		TargetPackage() const;
+			const BString&		Selection() const;
+
+			BString				ToString() const;
+
+private:
+			BType				fType;
+			BSolverPackage*		fSourcePackage;
+			BSolverPackage*		fTargetPackage;
+			BString				fSelection;
+};
+
+
+class BSolverProblemSolution {
+public:
+			typedef BSolverProblemSolutionElement Element;
+
+public:
+								BSolverProblemSolution();
+								~BSolverProblemSolution();
+
+			int32				CountElements() const;
+			const Element*		ElementAt(int32 index) const;
+
+			bool				AppendElement(const Element& element);
+
+private:
+			typedef BObjectList ElementList;
+
+private:
+			ElementList			fElements;
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif // _PACKAGE__SOLVER_PROBLEM_SOLUTION_H_
diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile
index 6eb0ac4468..338aceedf7 100644
--- a/src/kits/package/Jamfile
+++ b/src/kits/package/Jamfile
@@ -83,6 +83,7 @@ SharedLibrary libpackage.so
 	SolverPackageSpecifier.cpp
 	SolverPackageSpecifierList.cpp
 	SolverProblem.cpp
+	SolverProblemSolution.cpp
 	SolverRepository.cpp
 	SolverResult.cpp
 	:
diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index c12e8456f6..7e2a0769cd 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -13,6 +13,7 @@
 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -85,6 +86,46 @@ private:
 };
 
 
+struct LibsolvSolver::Problem : public BSolverProblem {
+	Problem(::Id id, BType type, BSolverPackage* sourcePackage,
+		BSolverPackage* targetPackage,
+		const BPackageResolvableExpression& dependency)
+		:
+		BSolverProblem(type, sourcePackage, targetPackage, dependency),
+		fId(id)
+	{
+	}
+
+	::Id Id() const
+	{
+		return fId;
+	}
+
+private:
+	::Id	fId;
+};
+
+
+struct LibsolvSolver::Solution : public BSolverProblemSolution {
+	Solution(::Id id, Problem* problem)
+		:
+		BSolverProblemSolution(),
+		fId(id),
+		fProblem(problem)
+	{
+	}
+
+	::Id Id() const
+	{
+		return fId;
+	}
+
+private:
+	::Id		fId;
+	Problem*	fProblem;
+};
+
+
 // #pragma mark - LibsolvSolver
 
 
@@ -546,13 +587,212 @@ LibsolvSolver::_AddProblem(Id problemId)
 			return error;
 	}
 
-	BSolverProblem* problem = new(std::nothrow) BSolverProblem(problemType,
+	Problem* problem = new(std::nothrow) Problem(problemId, problemType,
 		sourcePackage, targetPackage, dependency);
 	if (problem == NULL || !fProblems.AddItem(problem)) {
 		delete problem;
 		return B_NO_MEMORY;
 	}
 
+	int solutionCount = solver_solution_count(fSolver, problemId);
+	for (Id solutionId = 1; solutionId <= solutionCount; solutionId++) {
+		status_t error = _AddSolution(problem, solutionId);
+		if (error != B_OK)
+			return error;
+	}
+
+	return B_OK;
+}
+
+
+status_t
+LibsolvSolver::_AddSolution(Problem* problem, Id solutionId)
+{
+	Solution* solution = new(std::nothrow) Solution(solutionId, problem);
+	if (solution == NULL || !problem->AppendSolution(solution)) {
+		delete solution;
+		return B_NO_MEMORY;
+	}
+
+	Id elementId = 0;
+	for (;;) {
+		Id sourceId;
+		Id targetId;
+		elementId = solver_next_solutionelement(fSolver, problem->Id(),
+			solutionId, elementId, &sourceId, &targetId);
+		if (elementId == 0)
+			break;
+
+		status_t error = _AddSolutionElement(solution, sourceId, targetId);
+		if (error != B_OK)
+			return error;
+	}
+
+	return B_OK;
+}
+
+
+status_t
+LibsolvSolver::_AddSolutionElement(Solution* solution, Id sourceId, Id targetId)
+{
+	typedef BSolverProblemSolutionElement Element;
+
+	if (sourceId == SOLVER_SOLUTION_JOB
+		|| sourceId == SOLVER_SOLUTION_POOLJOB) {
+		// targetId is an index into the job queue
+		if (sourceId == SOLVER_SOLUTION_JOB)
+			targetId += fSolver->pooljobcnt;
+
+		Id how = fSolver->job.elements[targetId - 1];
+		Id what = fSolver->job.elements[targetId];
+		Id select = how & SOLVER_SELECTMASK;
+
+		switch (how & SOLVER_JOBMASK) {
+			case SOLVER_INSTALL:
+				if (select == SOLVER_SOLVABLE && fInstalledRepository != NULL
+					&& fPool->solvables[what].repo
+						== fInstalledRepository->SolvRepo()) {
+					return _AddSolutionElement(solution, Element::B_DONT_KEEP,
+						fPool->solvables + what, NULL, NULL);
+				}
+
+				return _AddSolutionElement(solution,
+					Element::B_DONT_INSTALL, NULL, NULL,
+					solver_select2str(fPool, select, what));
+
+			case SOLVER_ERASE:
+			{
+				if (select == SOLVER_SOLVABLE
+					&& (fInstalledRepository == NULL
+						|| fPool->solvables[what].repo
+							!= fInstalledRepository->SolvRepo())) {
+					return _AddSolutionElement(solution,
+						Element::B_DONT_FORBID_INSTALLATION,
+						fPool->solvables + what, NULL, NULL);
+				}
+
+				Element::BType type = select == SOLVER_SOLVABLE_PROVIDES
+					? Element::B_DONT_DEINSTALL_ALL : Element::B_DONT_DEINSTALL;
+				return _AddSolutionElement(solution, type, NULL, NULL,
+					solver_select2str(fPool, select, what));
+			}
+
+			case SOLVER_UPDATE:
+				return _AddSolutionElement(solution,
+					Element::B_DONT_INSTALL_MOST_RECENT, NULL, NULL,
+					solver_select2str(fPool, select, what));
+
+			case SOLVER_LOCK:
+				return _AddSolutionElement(solution, Element::B_DONT_LOCK, NULL,
+					NULL, solver_select2str(fPool, select, what));
+
+			default:
+				return _AddSolutionElement(solution, Element::B_UNSPECIFIED,
+					NULL, NULL, NULL);
+		}
+	}
+
+	Solvable* target = targetId != 0 ? fPool->solvables + targetId : NULL;
+	bool targetInstalled = target && fInstalledRepository
+		&& target->repo == fInstalledRepository->SolvRepo();
+
+	if (sourceId == SOLVER_SOLUTION_INFARCH) {
+		return _AddSolutionElement(solution,
+			targetInstalled
+				? Element::B_KEEP_INFERIOR_ARCHITECTURE
+				: Element::B_INSTALL_INFERIOR_ARCHITECTURE,
+			target, NULL, NULL);
+	}
+
+	if (sourceId == SOLVER_SOLUTION_DISTUPGRADE) {
+		return _AddSolutionElement(solution,
+			targetInstalled
+				? Element::B_KEEP_EXCLUDED : Element::B_INSTALL_EXCLUDED,
+			target, NULL, NULL);
+	}
+
+	if (sourceId == SOLVER_SOLUTION_BEST) {
+		return _AddSolutionElement(solution,
+			targetInstalled ? Element::B_KEEP_OLD : Element::B_INSTALL_OLD,
+			target, NULL, NULL);
+	}
+
+	// replace source with target
+	Solvable* source = fPool->solvables + sourceId;
+	if (target == NULL) {
+		return _AddSolutionElement(solution, Element::B_ALLOW_DEINSTALLATION,
+			source, NULL, NULL);
+	}
+
+	int illegalMask = policy_is_illegal(fSolver, source, target, 0);
+	if ((illegalMask & POLICY_ILLEGAL_DOWNGRADE) != 0) {
+		status_t error = _AddSolutionElement(solution,
+			Element::B_ALLOW_DOWNGRADE, source, target, NULL);
+		if (error != B_OK)
+			return error;
+	}
+
+	if ((illegalMask & POLICY_ILLEGAL_NAMECHANGE) != 0) {
+		status_t error = _AddSolutionElement(solution,
+			Element::B_ALLOW_NAME_CHANGE, source, target, NULL);
+		if (error != B_OK)
+			return error;
+	}
+
+	if ((illegalMask & POLICY_ILLEGAL_ARCHCHANGE) != 0) {
+		status_t error = _AddSolutionElement(solution,
+			Element::B_ALLOW_ARCHITECTURE_CHANGE, source, target, NULL);
+		if (error != B_OK)
+			return error;
+	}
+
+	if ((illegalMask & POLICY_ILLEGAL_VENDORCHANGE) != 0) {
+		status_t error = _AddSolutionElement(solution,
+			Element::B_ALLOW_VENDOR_CHANGE, source, target, NULL);
+		if (error != B_OK)
+			return error;
+	}
+
+	if (illegalMask == 0) {
+		return _AddSolutionElement(solution, Element::B_ALLOW_REPLACEMENT,
+			source, target, NULL);
+	}
+
+	return B_OK;
+}
+
+
+status_t
+LibsolvSolver::_AddSolutionElement(Solution* solution,
+	BSolverProblemSolutionElement::BType type, Solvable* sourceSolvable,
+	Solvable* targetSolvable, const char* selectionString)
+{
+	BSolverPackage* sourcePackage = NULL;
+	if (sourceSolvable != NULL) {
+		sourcePackage = _GetPackage(sourceSolvable);
+		if (sourcePackage == NULL)
+			return B_ERROR;
+	}
+
+	BSolverPackage* targetPackage = NULL;
+	if (targetSolvable != NULL) {
+		targetPackage = _GetPackage(targetSolvable);
+		if (targetPackage == NULL)
+			return B_ERROR;
+	}
+
+	BString selection;
+	if (selectionString != NULL && selectionString[0] != '\0') {
+		selection = selectionString;
+		if (selection.IsEmpty())
+			return B_NO_MEMORY;
+	}
+
+	if (!solution->AppendElement(BSolverProblemSolutionElement(
+			type, sourcePackage, targetPackage, selection))) {
+		return B_NO_MEMORY;
+	}
+
 	return B_OK;
 }
 
diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h
index e31eeadca2..5eb4acbb71 100644
--- a/src/kits/package/solver/LibsolvSolver.h
+++ b/src/kits/package/solver/LibsolvSolver.h
@@ -10,6 +10,7 @@
 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -46,9 +47,11 @@ public:
 private:
 			struct SolvQueue;
 			struct RepositoryInfo;
+			struct Problem;
+			struct Solution;
 
 			typedef BObjectList RepositoryInfoList;
-			typedef BObjectList ProblemList;
+			typedef BObjectList ProblemList;
 			typedef std::map SolvableMap;
 
 private:
@@ -61,6 +64,14 @@ private:
 			BSolverPackage*		_GetPackage(Id solvableId) const;
 
 			status_t			_AddProblem(Id problemId);
+			status_t			_AddSolution(Problem* problem, Id solutionId);
+			status_t			_AddSolutionElement(Solution* solution,
+									Id sourceId, Id targetId);
+			status_t			_AddSolutionElement(Solution* solution,
+									BSolverProblemSolutionElement::BType type,
+									Solvable* sourceSolvable,
+									Solvable* targetSolvable,
+									const char* selectionString);
 			status_t			_GetResolvableExpression(Id id,
 									BPackageResolvableExpression& _expression)
 									const;
diff --git a/src/kits/package/solver/SolverProblem.cpp b/src/kits/package/solver/SolverProblem.cpp
index 034f3d2ad6..e0adce076d 100644
--- a/src/kits/package/solver/SolverProblem.cpp
+++ b/src/kits/package/solver/SolverProblem.cpp
@@ -9,9 +9,8 @@
 
 #include 
 
-#include 
-
 #include 
+#include 
 
 
 static const char* const kToStringTexts[] = {
@@ -45,7 +44,8 @@ BSolverProblem::BSolverProblem(BType type, BSolverPackage* sourcePackage,
 	fType(type),
 	fSourcePackage(sourcePackage),
 	fTargetPackage(targetPackage),
-	fDependency()
+	fDependency(),
+	fSolutions(10, true)
 {
 }
 
@@ -57,7 +57,8 @@ BSolverProblem::BSolverProblem(BType type, BSolverPackage* sourcePackage,
 	fType(type),
 	fSourcePackage(sourcePackage),
 	fTargetPackage(targetPackage),
-	fDependency(dependency)
+	fDependency(dependency),
+	fSolutions(10, true)
 {
 }
 
@@ -95,6 +96,27 @@ BSolverProblem::Dependency() const
 }
 
 
+int32
+BSolverProblem::CountSolutions() const
+{
+	return fSolutions.CountItems();
+}
+
+
+const BSolverProblemSolution*
+BSolverProblem::SolutionAt(int32 index) const
+{
+	return fSolutions.ItemAt(index);
+}
+
+
+bool
+BSolverProblem::AppendSolution(BSolverProblemSolution* solution)
+{
+	return fSolutions.AddItem(solution);
+}
+
+
 BString
 BSolverProblem::ToString() const
 {
diff --git a/src/kits/package/solver/SolverProblemSolution.cpp b/src/kits/package/solver/SolverProblemSolution.cpp
new file mode 100644
index 0000000000..4b6f55f5e9
--- /dev/null
+++ b/src/kits/package/solver/SolverProblemSolution.cpp
@@ -0,0 +1,157 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+#include 
+
+
+static const char* const kToStringTexts[] = {
+	"do something",
+	"do not keep %source% installed",
+	"do not install \"%selection%\"",
+	"do not install the most recent version of \"%selection%\"",
+	"do not forbid installation of %source%",
+	"do not deinstall \"%selection%\"",
+	"do not deinstall all resolvables \"%s\"",
+	"do not lock \"%selection%\"",
+	"keep %source% despite its inferior architecture",
+	"keep %source% from excluded repository",
+	"keep old %source%",
+	"install %source% despite its inferior architecture",
+	"install %source% from excluded repository",
+	"install %s despite its old version",
+	"allow downgrade of %source% to %target%",
+	"allow name change of %source% to %target%",
+	"allow architecture change of %source% to %target%",
+	"allow vendor change from \"%sourceVendor%\" (%source%) to "
+		"\"%targetVendor%\" (%target%)",
+	"allow replacement of %source% with %target%",
+	"allow deinstallation of %source%"
+};
+
+
+namespace BPackageKit {
+
+
+// #pragma mark - BSolverProblemSolutionElement
+
+
+BSolverProblemSolutionElement::BSolverProblemSolutionElement(BType type,
+	BSolverPackage* sourcePackage, BSolverPackage* targetPackage,
+	const BString& selection)
+	:
+	fType(type),
+	fSourcePackage(sourcePackage),
+	fTargetPackage(targetPackage),
+	fSelection(selection)
+{
+}
+
+
+BSolverProblemSolutionElement::~BSolverProblemSolutionElement()
+{
+}
+
+
+BSolverProblemSolutionElement::BType
+BSolverProblemSolutionElement::Type() const
+{
+	return fType;
+}
+
+
+BSolverPackage*
+BSolverProblemSolutionElement::SourcePackage() const
+{
+	return fSourcePackage;
+}
+
+
+BSolverPackage*
+BSolverProblemSolutionElement::TargetPackage() const
+{
+	return fTargetPackage;
+}
+
+
+const BString&
+BSolverProblemSolutionElement::Selection() const
+{
+	return fSelection;
+}
+
+
+BString
+BSolverProblemSolutionElement::ToString() const
+{
+	size_t index = fType;
+	if (index >= sizeof(kToStringTexts) / sizeof(kToStringTexts[0]))
+		index = 0;
+
+	return BString(kToStringTexts[index])
+		.ReplaceAll("%source%",
+			fSourcePackage != NULL 
+				? fSourcePackage->VersionedName().String() : "?")
+		.ReplaceAll("%target%",
+			fTargetPackage != NULL
+				? fTargetPackage->VersionedName().String() : "?")
+		.ReplaceAll("%selection%", fSelection)
+		.ReplaceAll("%sourceVendor%",
+			fSourcePackage != NULL
+				? fSourcePackage->Info().Vendor().String() : "?")
+		.ReplaceAll("%targetVendor%",
+			fTargetPackage != NULL
+				? fTargetPackage->Info().Vendor().String() : "?");
+}
+
+
+// #pragma mark - BSolverProblemSolution
+
+
+BSolverProblemSolution::BSolverProblemSolution()
+	:
+	fElements(10, true)
+{
+}
+
+
+BSolverProblemSolution::~BSolverProblemSolution()
+{
+}
+
+
+int32
+BSolverProblemSolution::CountElements() const
+{
+	return fElements.CountItems();
+}
+
+
+const BSolverProblemSolution::Element*
+BSolverProblemSolution::ElementAt(int32 index) const
+{
+	return fElements.ItemAt(index);
+}
+
+
+bool
+BSolverProblemSolution::AppendElement(const Element& element)
+{
+	Element* newElement = new(std::nothrow) Element(element);
+	if (newElement == NULL || !fElements.AddItem(newElement)) {
+		delete newElement;
+		return false;
+	}
+
+	return true;
+}
+
+
+}	// namespace BPackageKit

From 4b3ca457b640c8759328c93aa9333f960de33196 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 9 Apr 2013 18:55:07 +0200
Subject: [PATCH 0380/1170] BSolverProblemSolution: Fix ToString() template
 strings

---
 src/kits/package/solver/SolverProblemSolution.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/kits/package/solver/SolverProblemSolution.cpp b/src/kits/package/solver/SolverProblemSolution.cpp
index 4b6f55f5e9..26cf36f91f 100644
--- a/src/kits/package/solver/SolverProblemSolution.cpp
+++ b/src/kits/package/solver/SolverProblemSolution.cpp
@@ -19,14 +19,14 @@ static const char* const kToStringTexts[] = {
 	"do not install the most recent version of \"%selection%\"",
 	"do not forbid installation of %source%",
 	"do not deinstall \"%selection%\"",
-	"do not deinstall all resolvables \"%s\"",
+	"do not deinstall all resolvables \"%selection%\"",
 	"do not lock \"%selection%\"",
 	"keep %source% despite its inferior architecture",
 	"keep %source% from excluded repository",
 	"keep old %source%",
 	"install %source% despite its inferior architecture",
 	"install %source% from excluded repository",
-	"install %s despite its old version",
+	"install %selection% despite its old version",
 	"allow downgrade of %source% to %target%",
 	"allow name change of %source% to %target%",
 	"allow architecture change of %source% to %target%",

From 92b6d58598fb09b38150027f6cbfa38fd5fb53e6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 9 Apr 2013 19:51:10 +0200
Subject: [PATCH 0381/1170] package daemon: Check volume package dependencies
 initially

Dumps the result (i.e. found problems and solutions) to the syslog.
Eventually the user should be asked what to do when inconsistencies are
encountered.
---
 src/servers/package/Root.cpp   |  35 +++++++-
 src/servers/package/Root.h     |   1 +
 src/servers/package/Volume.cpp | 146 +++++++++++++++++++++++++++++++++
 src/servers/package/Volume.h   |  15 ++++
 4 files changed, 196 insertions(+), 1 deletion(-)

diff --git a/src/servers/package/Root.cpp b/src/servers/package/Root.cpp
index 7a138789a5..012f5d0276 100644
--- a/src/servers/package/Root.cpp
+++ b/src/servers/package/Root.cpp
@@ -202,10 +202,43 @@ Root::_GetVolume(PackageFSMountType mountType)
 }
 
 
+Volume*
+Root::_NextVolumeFor(Volume* volume)
+{
+	if (volume == NULL)
+		return NULL;
+
+	PackageFSMountType mountType = volume->MountType();
+
+	do {
+		switch (mountType) {
+			case PACKAGE_FS_MOUNT_TYPE_HOME:
+				mountType = PACKAGE_FS_MOUNT_TYPE_COMMON;
+				break;
+			case PACKAGE_FS_MOUNT_TYPE_COMMON:
+				mountType = PACKAGE_FS_MOUNT_TYPE_SYSTEM;
+				break;
+			case PACKAGE_FS_MOUNT_TYPE_SYSTEM:
+			case PACKAGE_FS_MOUNT_TYPE_CUSTOM:
+			default:
+				return NULL;
+		}
+
+		volume = *_GetVolume(mountType);
+	} while (volume == NULL);
+
+	return volume;
+}
+
+
 void
 Root::_InitPackages(Volume* volume)
 {
-	volume->InitPackages(this);
+	if (volume->InitPackages(this) == B_OK) {
+		Volume* nextVolume = _NextVolumeFor(volume);
+		Volume* nextNextVolume = _NextVolumeFor(nextVolume);
+		volume->InitialVerify(nextVolume, nextNextVolume);
+	}
 }
 
 
diff --git a/src/servers/package/Root.h b/src/servers/package/Root.h
index b2afd2c6e9..4709d32f86 100644
--- a/src/servers/package/Root.h
+++ b/src/servers/package/Root.h
@@ -52,6 +52,7 @@ private:
 
 private:
 			Volume**			_GetVolume(PackageFSMountType mountType);
+			Volume*				_NextVolumeFor(Volume* volume);
 
 			void				_InitPackages(Volume* volume);
 			void				_DeleteVolume(Volume* volume);
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index b3664924f0..f5082baab9 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -20,6 +20,13 @@
 #include 
 #include 
 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
 #include 
 #include 
 
@@ -205,6 +212,114 @@ Volume::InitPackages(Listener* listener)
 }
 
 
+status_t
+Volume::AddPackagesToRepository(BSolverRepository& repository, bool activeOnly)
+{
+	for (PackageFileNameHashTable::Iterator it
+			= fPackagesByFileName.GetIterator(); it.HasNext();) {
+		Package* package = it.Next();
+		if (activeOnly && !package->IsActive())
+			continue;
+
+		status_t error = repository.AddPackage(package->Info());
+		if (error != B_OK) {
+			ERROR("Volume::AddPackagesToRepository(): failed to add package %s "
+				"to repository: %s\n", package->FileName().String(),
+				strerror(error));
+			return error;
+		}
+	}
+
+	return B_OK;
+}
+
+
+void
+Volume::InitialVerify(Volume* nextVolume, Volume* nextNextVolume)
+{
+INFORM("Volume::InitialVerify(%p, %p)\n", nextVolume, nextNextVolume);
+	// create the solver
+	BSolver* solver;
+	status_t error = BSolver::Create(solver);
+	if (error != B_OK) {
+		ERROR("Volume::InitialVerify(): failed to create solver: %s\n",
+			strerror(error));
+		return;
+	}
+	ObjectDeleter solverDeleter(solver);
+
+	// add a repository with all active packages
+	BSolverRepository repository;
+	error = _AddRepository(solver, repository, true, true);
+	if (error != B_OK) {
+		ERROR("Volume::InitialVerify(): failed to add repository: %s\n",
+			strerror(error));
+		return;
+	}
+
+	// add a repository for the next volume
+	BSolverRepository nextRepository;
+	if (nextVolume != NULL) {
+		nextRepository.SetPriority(1);
+		error = nextVolume->_AddRepository(solver, nextRepository, true, false);
+		if (error != B_OK) {
+			ERROR("Volume::InitialVerify(): failed to add repository: %s\n",
+				strerror(error));
+			return;
+		}
+	}
+
+	// add a repository for the next next volume
+	BSolverRepository nextNextRepository;
+	if (nextNextVolume != NULL) {
+		nextNextRepository.SetPriority(2);
+		error = nextNextVolume->_AddRepository(solver, nextNextRepository, true,
+			false);
+		if (error != B_OK) {
+			ERROR("Volume::InitialVerify(): failed to add repository: %s\n",
+				strerror(error));
+			return;
+		}
+	}
+
+	// verify
+	error = solver->VerifyInstallation();
+	if (error != B_OK) {
+		ERROR("Volume::InitialVerify(): failed to verify: %s\n",
+			strerror(error));
+		return;
+	}
+
+	if (!solver->HasProblems()) {
+		INFORM("Volume::InitialVerify(): volume at \"%s\" is consistent\n",
+			Path().String());
+		return;
+	}
+
+	// print the problems
+// TODO: Notify the user ...
+	INFORM("Volume::InitialVerify(): volume at \"%s\" has problems:\n",
+		Path().String());
+
+	int32 problemCount = solver->CountProblems();
+	for (int32 i = 0; i < problemCount; i++) {
+		BSolverProblem* problem = solver->ProblemAt(i);
+		INFORM("  %" B_PRId32 ": %s\n", i + 1, problem->ToString().String());
+		int32 solutionCount = problem->CountSolutions();
+		for (int32 k = 0; k < solutionCount; k++) {
+			const BSolverProblemSolution* solution = problem->SolutionAt(k);
+			INFORM("    solution %" B_PRId32 ":\n", k + 1);
+			int32 elementCount = solution->CountElements();
+			for (int32 l = 0; l < elementCount; l++) {
+				const BSolverProblemSolutionElement* element
+					= solution->ElementAt(l);
+				INFORM("      - %s\n", element->ToString().String());
+			}
+		}
+	}
+}
+
+
 void
 Volume::Unmounted()
 {
@@ -647,3 +762,34 @@ for (PackageNodeRefHashTable::Iterator it = fPackagesByNodeRef.GetIterator();
 
 	return B_OK;
 }
+
+
+status_t
+Volume::_AddRepository(BSolver* solver, BSolverRepository& repository,
+	bool activeOnly, bool installed)
+{
+	status_t error = repository.SetTo(Path());
+	if (error != B_OK) {
+		ERROR("Volume::_AddRepository(): failed to init repository: %s\n",
+			strerror(error));
+		return error;
+	}
+
+	repository.SetInstalled(installed);
+
+	error = AddPackagesToRepository(repository, true);
+	if (error != B_OK) {
+		ERROR("Volume::_AddRepository(): failed to add packages to "
+			"repository: %s\n", strerror(error));
+		return error;
+	}
+
+	error = solver->AddRepository(&repository);
+	if (error != B_OK) {
+		ERROR("Volume::_AddRepository(): failed to add repository to solver: "
+			"%s\n", strerror(error));
+		return error;
+	}
+
+	return B_OK;
+}
diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h
index b83bc401cd..ba95caac5a 100644
--- a/src/servers/package/Volume.h
+++ b/src/servers/package/Volume.h
@@ -25,6 +25,11 @@ class BDirectory;
 
 class Root;
 
+namespace BPackageKit {
+	class BSolver;
+	class BSolverRepository;
+}
+
 
 class Volume : public BHandler {
 public:
@@ -38,6 +43,12 @@ public:
 									node_ref& _packageRootRef);
 			status_t			InitPackages(Listener* listener);
 
+			status_t			AddPackagesToRepository(
+									BSolverRepository& repository,
+									bool activeOnly);
+			void				InitialVerify(Volume* nextVolume,
+									Volume* nextNextVolume);
+
 			void				Unmounted();
 
 	virtual	void				MessageReceived(BMessage* message);
@@ -98,6 +109,10 @@ private:
 			status_t			_ReadPackagesDirectory();
 			status_t			_GetActivePackages(int fd);
 
+			status_t			_AddRepository(BSolver* solver,
+									BSolverRepository& repository,
+							 		bool activeOnly, bool installed);
+
 private:
 			BString				fPath;
 			PackageFSMountType	fMountType;

From 19a268a459bb8a117f42937901532ef3b117a8d7 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 9 Apr 2013 20:07:46 +0200
Subject: [PATCH 0382/1170] Update libiconv and sqlite packages

The new package files haven't been rebuilt, just repackaged. Only small
details in the package-info changed.
---
 build/jam/OptionalPackages | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index ee2c9abe4b..e820993970 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -882,8 +882,8 @@ if [ IsOptionalHaikuImagePackageAdded LibIconv ] {
 				: $(baseURL)/libiconv-1.13.1-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				libiconv-1.13.1-2-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/libiconv-1.13.1-2-x86_gcc2.hpkg
+				libiconv-1.13.1-3-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/libiconv-1.13.1-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1393,8 +1393,8 @@ if [ IsOptionalHaikuImagePackageAdded SQLite ] {
 				: $(baseURL)/sqlite-3.7.5-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				sqlite-3.7.5-2-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/sqlite-3.7.5-2-x86_gcc2.hpkg
+				sqlite-3.7.5-3-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/sqlite-3.7.5-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}

From a96531fc511e210c34cb054310b61b560a82a06c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 9 Apr 2013 22:12:22 +0200
Subject: [PATCH 0383/1170] package daemon: On changes write a file with the
 active packages

---
 .../private/package/PackagesDirectoryDefs.h   |  18 +++
 src/servers/package/Volume.cpp                | 128 +++++++++++++++++-
 src/servers/package/Volume.h                  |   6 +
 3 files changed, 149 insertions(+), 3 deletions(-)
 create mode 100644 headers/private/package/PackagesDirectoryDefs.h

diff --git a/headers/private/package/PackagesDirectoryDefs.h b/headers/private/package/PackagesDirectoryDefs.h
new file mode 100644
index 0000000000..dacd05b6dd
--- /dev/null
+++ b/headers/private/package/PackagesDirectoryDefs.h
@@ -0,0 +1,18 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef _PACKAGE__PRIVATE__PACKAGES_DIRECTORY_DEFS_H_
+#define _PACKAGE__PRIVATE__PACKAGES_DIRECTORY_DEFS_H_
+
+
+#define PACKAGES_DIRECTORY_CONFIG_DIRECTORY	"config"
+#define PACKAGES_DIRECTORY_ACTIVATION_FILE	"activated-packages"
+
+
+
+#endif	// _PACKAGE__PRIVATE__PACKAGES_DIRECTORY_DEFS_H_
+
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index f5082baab9..bd8ba7bd2b 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -16,6 +16,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -29,11 +30,18 @@
 
 #include 
 #include 
+#include 
 
 #include "DebugSupport.h"
 
 
-static const char* kPackageFileNameExtension = ".hpkg";
+static const char* const kPackageFileNameExtension = ".hpkg";
+static const char* const kConfigDirectoryName
+	= PACKAGES_DIRECTORY_CONFIG_DIRECTORY;
+static const char* const kActivationFileName
+	= PACKAGES_DIRECTORY_ACTIVATION_FILE;
+static const char* const kTemporaryActivationFileName
+	= PACKAGES_DIRECTORY_ACTIVATION_FILE ".tmp";
 
 
 // #pragma mark - Listener
@@ -493,6 +501,47 @@ fPackagesToBeActivated.size(), fPackagesToBeDeactivated.size());
 
 	fPackagesToBeActivated.clear();
 	fPackagesToBeDeactivated.clear();
+
+	// write the package activation file
+
+	// create the content
+	BString activationFileContent;
+	for (PackageFileNameHashTable::Iterator it
+			= fPackagesByFileName.GetIterator(); it.HasNext();) {
+		Package* package = it.Next();
+		if (package->IsActive())
+			activationFileContent << package->FileName() << '\n';
+	}
+
+	// open and write the temporary file
+	BFile activationFile;
+	BEntry activationFileEntry;
+	status_t error = _OpenPackagesFile(kConfigDirectoryName,
+		kTemporaryActivationFileName,
+		B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE, activationFile,
+		&activationFileEntry);
+	if (error != B_OK) {
+		ERROR("Volume::ProcessPendingPackageActivationChanges(): failed to "
+			"create activation file: %s\n", strerror(error));
+		return;
+	}
+
+	ssize_t bytesWritten = activationFile.Write(activationFileContent.String(),
+		activationFileContent.Length());
+	if (bytesWritten < 0) {
+		ERROR("Volume::ProcessPendingPackageActivationChanges(): failed to "
+			"write activation file: %s\n", strerror(bytesWritten));
+		return;
+	}
+
+	// rename the temporary file to the final file
+	error = activationFileEntry.Rename(kActivationFileName, true);
+	if (error != B_OK) {
+		ERROR("Volume::ProcessPendingPackageActivationChanges(): failed to "
+			"rename temporary activation file to final file: %s\n",
+			strerror(error));
+		return;
+	}
 }
 
 
@@ -672,8 +721,8 @@ Volume::_ReadPackagesDirectory()
 	BDirectory directory;
 	status_t error = directory.SetTo(&fPackagesDirectoryRef);
 	if (error != B_OK) {
-		ERROR("Volume::_ReadPackagesDirectory(): open packages directory: %s\n",
-			strerror(error));
+		ERROR("Volume::_ReadPackagesDirectory(): failed to open packages "
+			"directory: %s\n", strerror(error));
 		RETURN_ERROR(error);
 	}
 
@@ -793,3 +842,76 @@ Volume::_AddRepository(BSolver* solver, BSolverRepository& repository,
 
 	return B_OK;
 }
+
+
+status_t
+Volume::_OpenPackagesFile(const char* subDirectoryPath, const char* fileName,
+	uint32 openMode, BFile& _file, BEntry* _entry)
+{
+	BDirectory directory;
+	if (subDirectoryPath != NULL) {
+		status_t error = _OpenPackagesSubDirectory(subDirectoryPath,
+			(openMode & B_CREATE_FILE) != 0, directory);
+		if (error != B_OK) {
+			ERROR("Volume::_OpenPackagesFile(): failed to open packages "
+				"subdirectory \"%s\": %s\n", subDirectoryPath, strerror(error));
+			RETURN_ERROR(error);
+		}
+	} else {
+		status_t error = directory.SetTo(&fPackagesDirectoryRef);
+		if (error != B_OK) {
+			ERROR("Volume::_OpenPackagesFile(): failed to open packages "
+				"directory: %s\n", strerror(error));
+			RETURN_ERROR(error);
+		}
+	}
+
+	BEntry stackEntry;
+	BEntry& entry = _entry != NULL ? *_entry : stackEntry;
+	status_t error = entry.SetTo(&directory, fileName);
+	if (error != B_OK) {
+		ERROR("Volume::_OpenPackagesFile(): failed to get entry for file: %s",
+			strerror(error));
+		RETURN_ERROR(error);
+	}
+
+	return _file.SetTo(&entry, openMode);
+}
+
+
+status_t
+Volume::_OpenPackagesSubDirectory(const char* path, bool create,
+	BDirectory& _directory)
+{
+	// open the packages directory
+	BDirectory directory;
+	status_t error = directory.SetTo(&fPackagesDirectoryRef);
+	if (error != B_OK) {
+		ERROR("Volume::_OpenConfigSubDirectory(): failed to open packages "
+			"directory: %s\n", strerror(error));
+		RETURN_ERROR(error);
+	}
+
+	// If creating is not allowed, just try to open it.
+	if (!create)
+		RETURN_ERROR(_directory.SetTo(&directory, path));
+
+	// get an absolute path and create the subdirectory
+	BPath absolutePath;
+	error = absolutePath.SetTo(&directory, path);
+	if (error != B_OK) {
+		ERROR("Volume::_OpenConfigSubDirectory(): failed to get absolute path "
+			"for subdirectory \"%s\": %s\n", path, strerror(error));
+		RETURN_ERROR(error);
+	}
+
+	error = create_directory(absolutePath.Path(),
+		S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
+	if (error != B_OK) {
+		ERROR("Volume::_OpenConfigSubDirectory(): failed to create packages "
+			"subdirectory \"%s\": %s\n", path, strerror(error));
+		RETURN_ERROR(error);
+	}
+
+	RETURN_ERROR(_directory.SetTo(&directory, path));
+}
diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h
index ba95caac5a..1885b1d03d 100644
--- a/src/servers/package/Volume.h
+++ b/src/servers/package/Volume.h
@@ -113,6 +113,12 @@ private:
 									BSolverRepository& repository,
 							 		bool activeOnly, bool installed);
 
+			status_t			_OpenPackagesFile(const char* subDirectoryPath,
+									const char* fileName, uint32 openMode,
+									BFile& _file, BEntry* _entry = NULL);
+			status_t			_OpenPackagesSubDirectory(const char* path,
+									bool create, BDirectory& _directory);
+
 private:
 			BString				fPath;
 			PackageFSMountType	fMountType;

From 19dc1d084f13bed77863dd1be56e846c314dd546 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 9 Apr 2013 23:26:56 +0200
Subject: [PATCH 0384/1170] packagefs: Use the package activation file

If the file exists load only the packages specified in it. If it doesn't
exist or any kind of error occurs, fall back to loading all packages in
the packages directory.
---
 .../kernel/file_systems/packagefs/Volume.cpp  | 184 +++++++++++++++---
 .../kernel/file_systems/packagefs/Volume.h    |   4 +
 2 files changed, 160 insertions(+), 28 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 16126af844..21bc96fb5b 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -22,6 +22,7 @@
 #include 
 
 #include 
+#include 
 
 #include 
 #include 
@@ -64,6 +65,13 @@ const char* const* kHomeShineThroughDirectories
 // sanity limit for activation change request
 const size_t kMaxActivationRequestSize = 10 * 1024 * 1024;
 
+// sanity limit for activation file size
+const size_t kMaxActivationFileSize = 10 * 1024 * 1024;
+
+static const char* const kActivationFilePath
+	= PACKAGES_DIRECTORY_CONFIG_DIRECTORY "/"
+		PACKAGES_DIRECTORY_ACTIVATION_FILE;
+
 
 // #pragma mark - ShineThroughDirectory
 
@@ -291,12 +299,7 @@ Volume::~Volume()
 	}
 
 	// delete the packages
-	Package* package = fPackages.Clear(true);
-	while (package != NULL) {
-		Package* next = package->FileNameHashTableNext();
-		package->ReleaseReference();
-		package = next;
-	}
+	_RemoveAllPackages();
 
 	// delete all indices
 	Index* index = fIndices.Clear(true);
@@ -731,6 +734,124 @@ Volume::_AddInitialPackages()
 	dprintf("packagefs: Adding packages from \"%s\"\n",
 		fPackagesDirectory->Path());
 
+	// try reading the activation file
+	status_t error = _AddInitialPackagesFromActivationFile();
+	if (error != B_OK) {
+		INFORM("Loading packages from activation file failed. Loading all "
+			"packages in packages directory.\n");
+
+		// remove all packages already added
+		{
+			VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
+			VolumeWriteLocker volumeLocker(this);
+			_RemoveAllPackages();
+		}
+
+		// read the whole directory
+		error = _AddInitialPackagesFromDirectory();
+		if (error != B_OK)
+			RETURN_ERROR(error);
+	}
+
+	// add the packages to the node tree
+	VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
+	VolumeWriteLocker volumeLocker(this);
+	for (PackageFileNameHashTable::Iterator it = fPackages.GetIterator();
+		Package* package = it.Next();) {
+		error = _AddPackageContent(package, false);
+		if (error != B_OK) {
+			for (it.Rewind(); Package* activePackage = it.Next();) {
+				if (activePackage == package)
+					break;
+				_RemovePackageContent(activePackage, NULL, false);
+			}
+			RETURN_ERROR(error);
+		}
+	}
+
+	return B_OK;
+}
+
+
+status_t
+Volume::_AddInitialPackagesFromActivationFile()
+{
+	// try reading the activation file
+	int fd = openat(fPackagesDirectory->DirectoryFD(),
+		kActivationFilePath, O_RDONLY);
+	if (fd < 0) {
+		INFORM("Failed to open packages activation file: %s\n",
+			strerror(errno));
+		RETURN_ERROR(errno);
+	}
+	FileDescriptorCloser fdCloser(fd);
+
+	// read the whole file into memory to simplify things
+	struct stat st;
+	if (fstat(fd, &st) != 0) {
+		ERROR("Failed to stat packages activation file: %s\n",
+			strerror(errno));
+		RETURN_ERROR(errno);
+	}
+
+	if (st.st_size > kMaxActivationFileSize) {
+		ERROR("The packages activation file is too big.\n");
+		RETURN_ERROR(B_BAD_DATA);
+	}
+
+	char* fileContent = (char*)malloc(st.st_size + 1);
+	if (fileContent == NULL)
+		RETURN_ERROR(B_NO_MEMORY);
+	MemoryDeleter fileContentDeleter(fileContent);
+
+	ssize_t bytesRead = read(fd, fileContent, st.st_size);
+	if (bytesRead < 0) {
+		ERROR("Failed to read packages activation file: %s\n", strerror(errno));
+		RETURN_ERROR(errno);
+	}
+
+	if (bytesRead != st.st_size) {
+		ERROR("Failed to read whole packages activation file\n");
+		RETURN_ERROR(B_ERROR);
+	}
+
+	// null-terminate to simplify parsing
+	fileContent[st.st_size] = '\0';
+
+	// parse the file and add the respective packages
+	const char* packageName = fileContent;
+	char* const fileContentEnd = fileContent + st.st_size;
+	while (packageName < fileContentEnd) {
+		char* packageNameEnd = strchr(packageName, '\n');
+		if (packageNameEnd == NULL)
+			packageNameEnd = fileContentEnd;
+
+		// skip empty lines
+		if (packageName == packageNameEnd) {
+			packageName++;
+			continue;
+		}
+		*packageNameEnd = '\0';
+
+		if (packageNameEnd - packageName >= B_FILE_NAME_LENGTH) {
+			ERROR("Invalid packages activation file content.\n");
+			RETURN_ERROR(B_BAD_DATA);
+		}
+
+		status_t error = _LoadAndAddInitialPackage(packageName);
+		if (error != B_OK)
+			RETURN_ERROR(error);
+
+		packageName = packageNameEnd + 1;
+	}
+
+	return B_OK;
+}
+
+
+status_t
+Volume::_AddInitialPackagesFromDirectory()
+{
 	// iterate through the dir and create packages
 	int fd = dup(fPackagesDirectory->DirectoryFD());
 	if (fd < 0) {
@@ -758,32 +879,27 @@ Volume::_AddInitialPackages()
 			continue;
 		}
 
-		Package* package;
-		if (_LoadPackage(entry->d_name, package) != B_OK)
-			continue;
-		BReference packageReference(package, true);
-
-		VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
-		VolumeWriteLocker volumeLocker(this);
-		_AddPackage(package);
-
+		_LoadAndAddInitialPackage(entry->d_name);
 	}
 
-	// add the packages to the node tree
+	return B_OK;
+}
+
+
+status_t
+Volume::_LoadAndAddInitialPackage(const char* name)
+{
+	Package* package;
+	status_t error = _LoadPackage(name, package);
+	if (error != B_OK) {
+		ERROR("Failed to load package \"%s\": %s\n", name, strerror(error));
+		RETURN_ERROR(error);
+	}
+	BReference packageReference(package, true);
+
 	VolumeWriteLocker systemVolumeLocker(_SystemVolumeIfNotSelf());
 	VolumeWriteLocker volumeLocker(this);
-	for (PackageFileNameHashTable::Iterator it = fPackages.GetIterator();
-		Package* package = it.Next();) {
-		status_t error = _AddPackageContent(package, false);
-		if (error != B_OK) {
-			for (it.Rewind(); Package* activePackage = it.Next();) {
-				if (activePackage == package)
-					break;
-				_RemovePackageContent(activePackage, NULL, false);
-			}
-			RETURN_ERROR(error);
-		}
-	}
+	_AddPackage(package);
 
 	return B_OK;
 }
@@ -805,6 +921,18 @@ Volume::_RemovePackage(Package* package)
 }
 
 
+void
+Volume::_RemoveAllPackages()
+{
+	Package* package = fPackages.Clear(true);
+	while (package != NULL) {
+		Package* next = package->FileNameHashTableNext();
+		package->ReleaseReference();
+		package = next;
+	}
+}
+
+
 inline Package*
 Volume::_FindPackage(const char* fileName) const
 {
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.h b/src/add-ons/kernel/file_systems/packagefs/Volume.h
index 23caf19fb8..525a979ff3 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.h
@@ -111,9 +111,13 @@ private:
 
 private:
 			status_t			_AddInitialPackages();
+			status_t			_AddInitialPackagesFromActivationFile();
+			status_t			_AddInitialPackagesFromDirectory();
+			status_t			_LoadAndAddInitialPackage(const char* name);
 
 	inline	void				_AddPackage(Package* package);
 	inline	void				_RemovePackage(Package* package);
+			void				_RemoveAllPackages();
 	inline	Package*			_FindPackage(const char* fileName) const;
 
 			status_t			_AddPackageContent(Package* package,

From 40cbf171efee048cd28a69e791b2ebac38cad3c2 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 9 Apr 2013 23:35:57 +0200
Subject: [PATCH 0385/1170] packagefs: don't dup() the packages directory FD

Volume::_AddInitialPackagesFromDirectory(): Use openat() instead of
dup() to get a FD for the packages directory. Currently our fdopendir()
implementation doesn't use it directly anyway, but in theory it could
and would then change the state of the original FD.
---
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 21bc96fb5b..2e7af7d2e7 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -853,9 +853,9 @@ status_t
 Volume::_AddInitialPackagesFromDirectory()
 {
 	// iterate through the dir and create packages
-	int fd = dup(fPackagesDirectory->DirectoryFD());
+	int fd = openat(fPackagesDirectory->DirectoryFD(), ".", O_RDONLY);
 	if (fd < 0) {
-		ERROR("Failed to dup() packages directory FD: %s\n", strerror(errno));
+		ERROR("Failed to open packages directory: %s\n", strerror(errno));
 		RETURN_ERROR(errno);
 	}
 

From 50888ebdc02b3d14e775206e0abb4d2a64cb9580 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 10 Apr 2013 12:58:12 +0200
Subject: [PATCH 0386/1170] BSolverRepository: Add a change count

... so we can easily check whether the repository has changed since the
last time we used it.
---
 headers/os/package/solver/SolverRepository.h |  3 +++
 src/kits/package/solver/SolverRepository.cpp | 27 ++++++++++++++++----
 2 files changed, 25 insertions(+), 5 deletions(-)

diff --git a/headers/os/package/solver/SolverRepository.h b/headers/os/package/solver/SolverRepository.h
index 24dc961784..1cd7fa2120 100644
--- a/headers/os/package/solver/SolverRepository.h
+++ b/headers/os/package/solver/SolverRepository.h
@@ -63,6 +63,8 @@ public:
 			status_t			AddPackages(
 									BPackageInstallationLocation location);
 
+			uint64				ChangeCount() const;
+
 private:
 			typedef BObjectList PackageList;
 
@@ -71,6 +73,7 @@ private:
 			uint8				fPriority;
 			bool				fIsInstalled;
 			PackageList			fPackages;
+			uint64				fChangeCount;
 };
 
 
diff --git a/src/kits/package/solver/SolverRepository.cpp b/src/kits/package/solver/SolverRepository.cpp
index b78cb6d415..1e710178f4 100644
--- a/src/kits/package/solver/SolverRepository.cpp
+++ b/src/kits/package/solver/SolverRepository.cpp
@@ -27,7 +27,8 @@ BSolverRepository::BSolverRepository()
 	fName(),
 	fPriority(0),
 	fIsInstalled(false),
-	fPackages(kInitialPackageListSize, true)
+	fPackages(kInitialPackageListSize, true),
+	fChangeCount(0)
 {
 }
 
@@ -37,7 +38,8 @@ BSolverRepository::BSolverRepository(const BString& name)
 	fName(),
 	fPriority(0),
 	fIsInstalled(false),
-	fPackages(kInitialPackageListSize, true)
+	fPackages(kInitialPackageListSize, true),
+	fChangeCount(0)
 {
 	SetTo(name);
 }
@@ -48,7 +50,8 @@ BSolverRepository::BSolverRepository(BPackageInstallationLocation location)
 	fName(),
 	fPriority(0),
 	fIsInstalled(false),
-	fPackages(kInitialPackageListSize, true)
+	fPackages(kInitialPackageListSize, true),
+	fChangeCount(0)
 {
 	SetTo(location);
 }
@@ -59,7 +62,8 @@ BSolverRepository::BSolverRepository(BAllInstallationLocations)
 	fName(),
 	fPriority(0),
 	fIsInstalled(false),
-	fPackages(kInitialPackageListSize, true)
+	fPackages(kInitialPackageListSize, true),
+	fChangeCount(0)
 {
 	SetTo(B_ALL_INSTALLATION_LOCATIONS);
 }
@@ -70,7 +74,8 @@ BSolverRepository::BSolverRepository(const BRepositoryConfig& config)
 	fName(),
 	fPriority(0),
 	fIsInstalled(false),
-	fPackages(kInitialPackageListSize, true)
+	fPackages(kInitialPackageListSize, true),
+	fChangeCount(0)
 {
 	SetTo(config);
 }
@@ -171,6 +176,7 @@ BSolverRepository::Unset()
 	fPriority = 0;
 	fIsInstalled = false;
 	fPackages.MakeEmpty();
+	fChangeCount++;
 }
 
 
@@ -192,6 +198,7 @@ void
 BSolverRepository::SetInstalled(bool isInstalled)
 {
 	fIsInstalled = isInstalled;
+	fChangeCount++;
 }
 
 
@@ -213,6 +220,7 @@ void
 BSolverRepository::SetPriority(uint8 priority)
 {
 	fPriority = priority;
+	fChangeCount++;
 }
 
 
@@ -247,6 +255,8 @@ BSolverRepository::AddPackage(const BPackageInfo& info,
 		return B_NO_MEMORY;
 	}
 
+	fChangeCount++;
+
 	if (_package != NULL)
 		*_package = package;
 
@@ -274,4 +284,11 @@ BSolverRepository::AddPackages(BPackageInstallationLocation location)
 }
 
 
+uint64
+BSolverRepository::ChangeCount() const
+{
+	return fChangeCount;
+}
+
+
 }	// namespace BPackageKit

From 483d49968d847843721d7e0c3a043327fc29955b Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 10 Apr 2013 13:20:38 +0200
Subject: [PATCH 0387/1170] LibsolvSolver: Make repeated use of object possible

* _Solve(): Clean up the old solver before creating a new one.
* _AddRepositories(): Don't do anything, if the repositories haven't
  changed.
---
 src/kits/package/solver/LibsolvSolver.cpp | 130 +++++++++++++++-------
 src/kits/package/solver/LibsolvSolver.h   |   3 +
 2 files changed, 93 insertions(+), 40 deletions(-)

diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index 7e2a0769cd..af536af151 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -61,7 +61,8 @@ struct LibsolvSolver::RepositoryInfo {
 	RepositoryInfo(BSolverRepository* repository)
 		:
 		fRepository(repository),
-		fSolvRepo(NULL)
+		fSolvRepo(NULL),
+		fChangeCount(repository->ChangeCount() - 1)
 	{
 	}
 
@@ -80,9 +81,20 @@ struct LibsolvSolver::RepositoryInfo {
 		fSolvRepo = repo;
 	}
 
+	bool HasChanged() const
+	{
+		return fChangeCount != fRepository->ChangeCount();
+	}
+
+	void SetUnchanged()
+	{
+		fChangeCount = fRepository->ChangeCount();
+	}
+
 private:
 	BSolverRepository*	fRepository;
 	Repo*				fSolvRepo;
+	uint64				fChangeCount;
 };
 
 
@@ -135,6 +147,7 @@ LibsolvSolver::LibsolvSolver()
 	fSolver(NULL),
 	fRepositoryInfos(10, true),
 	fInstalledRepository(NULL),
+	fSolvablePackages(),
 	fProblems(10, true)
 {
 }
@@ -149,30 +162,7 @@ LibsolvSolver::~LibsolvSolver()
 status_t
 LibsolvSolver::Init()
 {
-	_Cleanup();
-
-	fPool = pool_create();
-
-	// Set the system architecture. We use what uname() returns unless we're on
-	// x86 gcc2.
-	{
-		const char* arch;
-		#ifdef __HAIKU_ARCH_X86
-			#if (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2
-				arch = "x86_gcc2";
-			#else
-				arch = "x86";
-			#endif
-		#else
-			struct utsname info;
-			if (uname(&info) != 0)
-				return errno;
-			arch = info.machine;
-		#endif
-
-		pool_setarchpolicy(fPool, arch);
-	}
-
+	// We do all initialization lazily.
 	return B_OK;
 }
 
@@ -211,16 +201,11 @@ LibsolvSolver::Install(const BSolverPackageSpecifierList& packages)
 	if (packages.IsEmpty())
 		return B_BAD_VALUE;
 
-// TODO: Clean up first?
-
 	// add repositories to pool
 	status_t error = _AddRepositories();
 	if (error != B_OK)
 		return error;
 
-	// prepare pool for solving
-	pool_createwhatprovides(fPool);
-
 	// add the packages to install to the job queue
 	SolvQueue jobs;
 
@@ -279,9 +264,6 @@ LibsolvSolver::VerifyInstallation()
 	if (error != B_OK)
 		return error;
 
-	// prepare pool for solving
-	pool_createwhatprovides(fPool);
-
 	// add the verify job to the job queue
 	SolvQueue jobs;
 	queue_push2(&jobs, SOLVER_SOLVABLE_ALL, 0);
@@ -310,7 +292,7 @@ LibsolvSolver::ProblemAt(int32 index) const
 status_t
 LibsolvSolver::GetResult(BSolverResult& _result)
 {
-	if (HasProblems())
+	if (fSolver == NULL || HasProblems())
 		return B_BAD_VALUE;
 
 	_result.MakeEmpty();
@@ -387,19 +369,46 @@ LibsolvSolver::GetResult(BSolverResult& _result)
 }
 
 
+status_t
+LibsolvSolver::_Init()
+{
+	_Cleanup();
+
+	fPool = pool_create();
+
+	// Set the system architecture. We use what uname() returns unless we're on
+	// x86 gcc2.
+	{
+		const char* arch;
+		#ifdef __HAIKU_ARCH_X86
+			#if (B_HAIKU_ABI & B_HAIKU_ABI_MAJOR) == B_HAIKU_ABI_GCC_2
+				arch = "x86_gcc2";
+			#else
+				arch = "x86";
+			#endif
+		#else
+			struct utsname info;
+			if (uname(&info) != 0)
+				return errno;
+			arch = info.machine;
+		#endif
+
+		pool_setarchpolicy(fPool, arch);
+	}
+
+	return B_OK;
+}
+
+
 void
 LibsolvSolver::_Cleanup()
 {
-	fProblems.MakeEmpty();
+	_CleanupSolver();
+
 	fSolvablePackages.clear();
 	fInstalledRepository = NULL;
 	fRepositoryInfos.MakeEmpty();
 
-	if (fSolver != NULL) {
-		solver_free(fSolver);
-		fSolver = NULL;
-	}
-
 	if (fPool != NULL) {
 		pool_free(fPool);
 		fPool = NULL;
@@ -407,9 +416,43 @@ LibsolvSolver::_Cleanup()
 }
 
 
+void
+LibsolvSolver::_CleanupSolver()
+{
+	fProblems.MakeEmpty();
+
+	if (fSolver != NULL) {
+		solver_free(fSolver);
+		fSolver = NULL;
+	}
+}
+
+
+bool
+LibsolvSolver::_HaveRepositoriesChanged() const
+{
+	int32 repositoryCount = fRepositoryInfos.CountItems();
+	for (int32 i = 0; i < repositoryCount; i++) {
+		RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
+		if (repositoryInfo->HasChanged())
+			return true;
+	}
+
+	return false;
+}
+
+
 status_t
 LibsolvSolver::_AddRepositories()
 {
+	if (fPool != NULL && !_HaveRepositoriesChanged())
+		return B_OK;
+
+	// something has changed -- re-create the pool
+	status_t error = _Init();
+	if (error != B_OK)
+		return error;
+
 	int32 repositoryCount = fRepositoryInfos.CountItems();
 	for (int32 i = 0; i < repositoryCount; i++) {
 		RepositoryInfo* repositoryInfo = fRepositoryInfos.ItemAt(i);
@@ -438,8 +481,13 @@ LibsolvSolver::_AddRepositories()
 
 		if (repository->IsInstalled())
 			pool_set_installed(fPool, repo);
+
+		repositoryInfo->SetUnchanged();
 	}
 
+	// create "provides" lookup
+	pool_createwhatprovides(fPool);
+
 	return B_OK;
 }
 
@@ -865,6 +913,8 @@ LibsolvSolver::_GetResolvableExpression(Id id,
 status_t
 LibsolvSolver::_Solve(Queue& jobs)
 {
+	_CleanupSolver();
+
 	// create the solver and solve
 	fSolver = solver_create(fPool);
 	solver_set_flag(fSolver, SOLVER_FLAG_SPLITPROVIDES, 1);
diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h
index 5eb4acbb71..81f99eb1aa 100644
--- a/src/kits/package/solver/LibsolvSolver.h
+++ b/src/kits/package/solver/LibsolvSolver.h
@@ -55,8 +55,11 @@ private:
 			typedef std::map SolvableMap;
 
 private:
+			status_t			_Init();
 			void				_Cleanup();
+			void				_CleanupSolver();
 
+			bool				_HaveRepositoriesChanged() const;
 			status_t			_AddRepositories();
 			RepositoryInfo*		_GetRepositoryInfo(
 									BSolverRepository* repository) const;

From 5776551d3dfa5c88bdebd65fd211aaebbb91e525 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Wed, 10 Apr 2013 14:41:30 +0200
Subject: [PATCH 0388/1170] pkgman: Move some classes into own file for reuse

Namely RepositoryBuilder and PackageInfoErrorListener.
---
 src/bin/pkgman/Jamfile                        |   4 +-
 src/bin/pkgman/PackageInfoErrorListener.cpp   |  27 +++
 src/bin/pkgman/PackageInfoErrorListener.h     |  31 ++++
 src/bin/pkgman/RepositoryBuilder.cpp          | 158 +++++++++++++++++
 src/bin/pkgman/RepositoryBuilder.h            |  57 ++++++
 .../pkgman/command_resolve_dependencies.cpp   | 167 +-----------------
 6 files changed, 277 insertions(+), 167 deletions(-)
 create mode 100644 src/bin/pkgman/PackageInfoErrorListener.cpp
 create mode 100644 src/bin/pkgman/PackageInfoErrorListener.h
 create mode 100644 src/bin/pkgman/RepositoryBuilder.cpp
 create mode 100644 src/bin/pkgman/RepositoryBuilder.h

diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile
index f6dfa06b37..db1206a47f 100644
--- a/src/bin/pkgman/Jamfile
+++ b/src/bin/pkgman/Jamfile
@@ -5,12 +5,14 @@ UsePrivateHeaders shared support ;
 BinCommand pkgman :
 	command_add_repo.cpp
 	command_drop_repo.cpp
-	command_resolve_dependencies.cpp
 	command_list_repos.cpp
 	command_refresh.cpp
+	command_resolve_dependencies.cpp
 	DecisionProvider.cpp
 	JobStateListener.cpp
+	PackageInfoErrorListener.cpp
 	pkgman.cpp
+	RepositoryBuilder.cpp
 	:
 	package be
 	$(TARGET_LIBSUPC++)
diff --git a/src/bin/pkgman/PackageInfoErrorListener.cpp b/src/bin/pkgman/PackageInfoErrorListener.cpp
new file mode 100644
index 0000000000..89639c3d1b
--- /dev/null
+++ b/src/bin/pkgman/PackageInfoErrorListener.cpp
@@ -0,0 +1,27 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include "PackageInfoErrorListener.h"
+
+#include 
+
+
+PackageInfoErrorListener::PackageInfoErrorListener(const BString& errorContext)
+	:
+	fErrorContext(errorContext)
+{
+}
+
+
+void
+PackageInfoErrorListener::OnError(const BString& message, int line, int column)
+{
+	fprintf(stderr, "%s: Parse error in line %d:%d: %s\n",
+		fErrorContext.String(), line, column, message.String());
+}
diff --git a/src/bin/pkgman/PackageInfoErrorListener.h b/src/bin/pkgman/PackageInfoErrorListener.h
new file mode 100644
index 0000000000..7bd9b1a865
--- /dev/null
+++ b/src/bin/pkgman/PackageInfoErrorListener.h
@@ -0,0 +1,31 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef PACKAGE_INFO_ERROR_LISTENER_H
+#define PACKAGE_INFO_ERROR_LISTENER_H
+
+
+#include 
+
+
+using namespace BPackageKit;
+
+
+class PackageInfoErrorListener : public BPackageInfo::ParseErrorListener {
+public:
+								PackageInfoErrorListener(
+									const BString& errorContext);
+
+	virtual	void				OnError(const BString& message, int line,
+									int column);
+
+private:
+			BString				fErrorContext;
+};
+
+
+#endif	// PACKAGE_INFO_ERROR_LISTENER_H
diff --git a/src/bin/pkgman/RepositoryBuilder.cpp b/src/bin/pkgman/RepositoryBuilder.cpp
new file mode 100644
index 0000000000..a307533c97
--- /dev/null
+++ b/src/bin/pkgman/RepositoryBuilder.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include "RepositoryBuilder.h"
+
+#include 
+#include 
+
+#include 
+#include 
+
+#include 
+
+#include "PackageInfoErrorListener.h"
+#include "pkgman.h"
+
+
+RepositoryBuilder::RepositoryBuilder(BSolverRepository& repository,
+	const BString& name, const BString& errorName)
+	:
+	fRepository(repository),
+	fErrorName(errorName.IsEmpty() ? name : errorName),
+	fPackagePaths(NULL)
+{
+	status_t error = fRepository.SetTo(name);
+	if (error != B_OK)
+		DIE(error, "failed to init %s repository", fErrorName.String());
+}
+
+
+RepositoryBuilder&
+RepositoryBuilder::SetPackagePathMap(PackagePathMap* packagePaths)
+{
+	fPackagePaths = packagePaths;
+	return *this;
+}
+
+
+RepositoryBuilder&
+RepositoryBuilder::AddPackage(const BPackageInfo& info,
+	const char* packageErrorName, BSolverPackage** _package)
+{
+	status_t error = fRepository.AddPackage(info, _package);
+	if (error != B_OK) {
+		DIE(error, "failed to add %s to %s repository",
+			packageErrorName != NULL
+				? packageErrorName
+				: (BString("package ") << info.Name()).String(),
+			fErrorName.String());
+	}
+	return *this;
+}
+
+
+RepositoryBuilder&
+RepositoryBuilder::AddPackage(const char* path, BSolverPackage** _package)
+{
+	// read a package info from the (HPKG or package info) file
+	BPackageInfo packageInfo;
+
+	size_t pathLength = strlen(path);
+	status_t error;
+	if (pathLength > 5 && strcmp(path + pathLength - 5, ".hpkg") == 0) {
+		// a package file
+		error = packageInfo.ReadFromPackageFile(path);
+	} else {
+		// a package info file (supposedly)
+		PackageInfoErrorListener errorListener(
+			"Error: failed to read package info");
+		error = packageInfo.ReadFromConfigFile(BEntry(path),
+			&errorListener);
+	}
+
+	if (error != B_OK)
+		DIE(errno, "failed to read package info from \"%s\"", path);
+
+	// add the package
+	BSolverPackage* package;
+	AddPackage(packageInfo, path, &package);
+
+	// enter the package path in the path map, if given
+	if (fPackagePaths != NULL)
+		(*fPackagePaths)[package] = path;
+
+	if (_package != NULL)
+		*_package = package;
+
+	return *this;
+}
+
+
+RepositoryBuilder&
+RepositoryBuilder::AddPackages(BPackageInstallationLocation location,
+	const char* locationErrorName)
+{
+	status_t error = fRepository.AddPackages(location);
+	if (error != B_OK) {
+		DIE(error, "failed to add %s packages to %s repository",
+			locationErrorName, fErrorName.String());
+	}
+	return *this;
+}
+
+
+RepositoryBuilder&
+RepositoryBuilder::AddPackagesDirectory(const char* path)
+{
+	// open directory
+	DIR* dir = opendir(path);
+	if (dir == NULL)
+		DIE(errno, "failed to open package directory \"%s\"", path);
+	CObjectDeleter dirCloser(dir, &closedir);
+
+	// iterate through directory entries
+	while (dirent* entry = readdir(dir)) {
+		// skip "." and ".."
+		const char* name = entry->d_name;
+		if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
+			continue;
+
+		// stat() the entry and skip any non-file
+		BPath entryPath;
+		status_t error = entryPath.SetTo(path, name);
+		if (error != B_OK)
+			DIE(errno, "failed to construct path");
+
+		struct stat st;
+		if (lstat(entryPath.Path(), &st) != 0)
+			DIE(errno, "failed to stat() %s", entryPath.Path());
+
+		if (!S_ISREG(st.st_mode))
+			continue;
+
+		AddPackage(entryPath.Path());
+	}
+
+	return *this;
+}
+
+
+RepositoryBuilder&
+RepositoryBuilder::AddToSolver(BSolver* solver, bool isInstalled)
+{
+	fRepository.SetInstalled(isInstalled);
+
+	status_t error = solver->AddRepository(&fRepository);
+	if (error != B_OK) {
+		DIE(error, "failed to add %s repository to solver",
+			fErrorName.String());
+	}
+	return *this;
+}
diff --git a/src/bin/pkgman/RepositoryBuilder.h b/src/bin/pkgman/RepositoryBuilder.h
new file mode 100644
index 0000000000..0b9e72af58
--- /dev/null
+++ b/src/bin/pkgman/RepositoryBuilder.h
@@ -0,0 +1,57 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef REPOSITORY_BUILDER_H
+#define REPOSITORY_BUILDER_H
+
+
+#include 
+
+#include 
+#include 
+#include 
+#include 
+
+
+using namespace BPackageKit;
+
+
+typedef std::map PackagePathMap;
+
+
+class RepositoryBuilder {
+private:
+			typedef RepositoryBuilder Builder;
+
+public:
+								RepositoryBuilder(BSolverRepository& repository,
+									const BString& name,
+									const BString& errorName = BString());
+
+			RepositoryBuilder&	SetPackagePathMap(PackagePathMap* packagePaths);
+
+			RepositoryBuilder&	AddPackage(const BPackageInfo& info,
+									const char* packageErrorName = NULL,
+									BSolverPackage** _package = NULL);
+			RepositoryBuilder&	AddPackage(const char* path,
+									BSolverPackage** _package = NULL);
+			RepositoryBuilder&	AddPackages(
+									BPackageInstallationLocation location,
+									const char* locationErrorName);
+			RepositoryBuilder&	AddPackagesDirectory(const char* path);
+
+			RepositoryBuilder&	AddToSolver(BSolver* solver,
+									bool isInstalled = false);
+
+private:
+			BSolverRepository&	fRepository;
+			BString				fErrorName;
+			PackagePathMap*		fPackagePaths;
+};
+
+
+#endif	// REPOSITORY_BUILDER_H
diff --git a/src/bin/pkgman/command_resolve_dependencies.cpp b/src/bin/pkgman/command_resolve_dependencies.cpp
index d71aed657f..9e67ced5a8 100644
--- a/src/bin/pkgman/command_resolve_dependencies.cpp
+++ b/src/bin/pkgman/command_resolve_dependencies.cpp
@@ -7,31 +7,21 @@
  */
 
 
-#include 
 #include 
 #include 
 #include 
 #include 
 #include 
 
-#include 
-
-#include 
-#include 
-#include 
-
-#include 
-#include 
-#include 
 #include 
 #include 
 #include 
-#include 
 #include 
 
 #include 
 
 #include "pkgman.h"
+#include "RepositoryBuilder.h"
 
 
 // TODO: internationalization!
@@ -40,9 +30,6 @@
 using namespace BPackageKit;
 
 
-typedef std::map PackagePathMap;
-
-
 static const char* kCommandUsage =
 	"Usage: %s resolve-dependencies   [  ] ...\n"
 	"Resolves and lists all packages a given package depends on. Fails, if\n"
@@ -71,158 +58,6 @@ print_command_usage_and_exit(bool error)
 }
 
 
-struct PackageInfoErrorListener : public BPackageInfo::ParseErrorListener {
-public:
-	PackageInfoErrorListener(const BString& errorContext)
-		:
-		fErrorContext(errorContext)
-	{
-	}
-
-	virtual void OnError(const BString& message, int line, int column)
-	{
-		fprintf(stderr, "%s: Parse error in line %d:%d: %s\n",
-			fErrorContext.String(), line, column, message.String());
-	}
-
-private:
-	BString	fErrorContext;
-};
-
-
-struct RepositoryBuilder {
-	RepositoryBuilder(BSolverRepository& repository, const BString& name,
-		const BString& errorName = BString())
-		:
-		fRepository(repository),
-		fErrorName(errorName.IsEmpty() ? name : errorName),
-		fPackagePaths(NULL)
-	{
-		status_t error = fRepository.SetTo(name);
-		if (error != B_OK)
-			DIE(error, "failed to init %s repository", fErrorName.String());
-	}
-
-	RepositoryBuilder& SetPackagePathMap(PackagePathMap* packagePaths)
-	{
-		fPackagePaths = packagePaths;
-		return *this;
-	}
-
-	RepositoryBuilder& AddPackage(const BPackageInfo& info,
-		const char* packageErrorName = NULL, BSolverPackage** _package = NULL)
-	{
-		status_t error = fRepository.AddPackage(info, _package);
-		if (error != B_OK) {
-			DIE(error, "failed to add %s to %s repository",
-				packageErrorName != NULL
-					? packageErrorName
-					: (BString("package ") << info.Name()).String(),
-				fErrorName.String());
-		}
-		return *this;
-	}
-
-	RepositoryBuilder& AddPackage(const char* path,
-		BSolverPackage** _package = NULL)
-	{
-		// read a package info from the (HPKG or package info) file
-		BPackageInfo packageInfo;
-
-		size_t pathLength = strlen(path);
-		status_t error;
-		if (pathLength > 5 && strcmp(path + pathLength - 5, ".hpkg") == 0) {
-			// a package file
-			error = packageInfo.ReadFromPackageFile(path);
-		} else {
-			// a package info file (supposedly)
-			PackageInfoErrorListener errorListener(
-				"Error: failed to read package info");
-			error = packageInfo.ReadFromConfigFile(BEntry(path),
-				&errorListener);
-		}
-
-		if (error != B_OK)
-			DIE(errno, "failed to read package info from \"%s\"", path);
-
-		// add the package
-		BSolverPackage* package;
-		AddPackage(packageInfo, path, &package);
-
-		// enter the package path in the path map, if given
-		if (fPackagePaths != NULL)
-			(*fPackagePaths)[package] = path;
-
-		if (_package != NULL)
-			*_package = package;
-
-		return *this;
-	}
-
-	RepositoryBuilder& AddPackages(BPackageInstallationLocation location,
-		const char* locationErrorName)
-	{
-		status_t error = fRepository.AddPackages(location);
-		if (error != B_OK) {
-			DIE(error, "failed to add %s packages to %s repository",
-				locationErrorName, fErrorName.String());
-		}
-		return *this;
-	}
-
-	RepositoryBuilder& AddPackagesDirectory(const char* path)
-	{
-		// open directory
-		DIR* dir = opendir(path);
-		if (dir == NULL)
-			DIE(errno, "failed to open package directory \"%s\"", path);
-		CObjectDeleter dirCloser(dir, &closedir);
-
-		// iterate through directory entries
-		while (dirent* entry = readdir(dir)) {
-			// skip "." and ".."
-			const char* name = entry->d_name;
-			if (strcmp(name, ".") == 0 || strcmp(name, "..") == 0)
-				continue;
-
-			// stat() the entry and skip any non-file
-			BPath entryPath;
-			status_t error = entryPath.SetTo(path, name);
-			if (error != B_OK)
-				DIE(errno, "failed to construct path");
-
-			struct stat st;
-			if (lstat(entryPath.Path(), &st) != 0)
-				DIE(errno, "failed to stat() %s", entryPath.Path());
-
-			if (!S_ISREG(st.st_mode))
-				continue;
-
-			AddPackage(entryPath.Path());
-		}
-
-		return *this;
-	}
-
-	RepositoryBuilder& AddToSolver(BSolver* solver, bool isInstalled = false)
-	{
-		fRepository.SetInstalled(isInstalled);
-
-		status_t error = solver->AddRepository(&fRepository);
-		if (error != B_OK) {
-			DIE(error, "failed to add %s repository to solver",
-				fErrorName.String());
-		}
-		return *this;
-	}
-
-private:
-	BSolverRepository&	fRepository;
-	BString				fErrorName;
-	PackagePathMap*		fPackagePaths;
-};
-
-
 static void
 check_problems(BSolver* solver, const char* errorContext)
 {

From 1a34656b57ddfb178fe00903e74ad24882d83bc6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 11 Apr 2013 00:36:10 +0200
Subject: [PATCH 0389/1170] BPackageVersion: Make version string constructor
 explicit

---
 headers/os/package/PackageVersion.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/headers/os/package/PackageVersion.h b/headers/os/package/PackageVersion.h
index 12a80d198b..63a53f4d1d 100644
--- a/headers/os/package/PackageVersion.h
+++ b/headers/os/package/PackageVersion.h
@@ -23,7 +23,7 @@ public:
 								BPackageVersion();
 								BPackageVersion(
 									const BPackageVersionData& data);
-								BPackageVersion(const BString& versionString,
+	explicit					BPackageVersion(const BString& versionString,
 									bool releaseIsOptional = true);
 								BPackageVersion(const BString& major,
 									const BString& minor, const BString& micro,

From 6c6460e1f644e5b48e7fc4528d33219fe13f270e Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 11 Apr 2013 00:37:25 +0200
Subject: [PATCH 0390/1170] BPackageInfo: Add GetConfigString() and ToString()

---
 headers/os/package/PackageInfo.h |   4 +
 src/kits/package/PackageInfo.cpp | 269 +++++++++++++++++++++++++++++++
 2 files changed, 273 insertions(+)

diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h
index 25383886fe..4d9e3f5d98 100644
--- a/headers/os/package/PackageInfo.h
+++ b/headers/os/package/PackageInfo.h
@@ -137,6 +137,9 @@ public:
 
 			void				Clear();
 
+			status_t			GetConfigString(BString& _string) const;
+			BString				ToString() const;
+
 public:
 	static	status_t			GetArchitectureByName(const BString& name,
 									BPackageArchitecture& _architecture);
@@ -153,6 +156,7 @@ public:
 private:
 			class Parser;
 			friend class Parser;
+			struct StringBuilder;
 
 private:
 			BString				fName;
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 41f39b4e94..4a1ae56026 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -57,6 +57,9 @@ struct ParseError {
 }	// anonymous namespace
 
 
+// #pragma mark - Parser
+
+
 /*
  * Parses a ".PackageInfo" file and fills a BPackageInfo object with the
  * package info elements found.
@@ -870,6 +873,235 @@ BPackageInfo::kArchitectureNames[B_PACKAGE_ARCHITECTURE_ENUM_COUNT] = {
 };
 
 
+// #pragma mark - StringBuilder
+
+
+struct BPackageInfo::StringBuilder {
+	StringBuilder()
+		:
+		fData(),
+		fError(B_OK)
+	{
+	}
+
+	status_t Error() const
+	{
+		return fError;
+	}
+
+	status_t GetString(BString& _string) const
+	{
+		if (fError != B_OK) {
+			_string = BString();
+			return fError;
+		}
+
+		_string.SetTo((const char*)fData.Buffer(), fData.BufferLength());
+		return (size_t)_string.Length() == fData.BufferLength()
+			? B_OK : B_NO_MEMORY;
+	}
+
+	template
+	StringBuilder& Write(const char* attribute, Value value)
+	{
+		if (_IsValueEmpty(value))
+			return *this;
+
+		_Write(attribute);
+		_Write('\t');
+		_WriteValue(value);
+		_Write('\n');
+		return *this;
+	}
+
+	StringBuilder& WriteFlags(const char* attribute, uint32 flags)
+	{
+		if ((flags & B_PACKAGE_FLAG_APPROVE_LICENSE) == 0
+			&& (flags & B_PACKAGE_FLAG_SYSTEM_PACKAGE) == 0) {
+			return *this;
+		}
+
+		_Write(attribute);
+		_Write('\t');
+
+		if ((flags & B_PACKAGE_FLAG_APPROVE_LICENSE) == 0)
+			_Write(" approve_license");
+		if ((flags & B_PACKAGE_FLAG_SYSTEM_PACKAGE) == 0)
+			_Write(" system_package");
+
+		_Write('\n');
+		return *this;
+	}
+
+private:
+	void _WriteValue(const char* value)
+	{
+		_WriteMaybeQuoted(value);
+	}
+
+	void _WriteValue(const BPackageVersion& value)
+	{
+		if (fError != B_OK)
+			return;
+
+		if (value.InitCheck() != B_OK) {
+			fError = B_BAD_VALUE;
+			return;
+		}
+
+		_Write(value.ToString());
+	}
+
+	void _WriteValue(const BStringList& value)
+	{
+		int32 count = value.CountStrings();
+		if (count == 1) {
+			_WriteMaybeQuoted(value.StringAt(0));
+		} else {
+			_Write("{\n", 2);
+
+			int32 count = value.CountStrings();
+			for (int32 i = 0; i < count; i++) {
+				_Write('\t');
+				_WriteMaybeQuoted(value.StringAt(i));
+				_Write('\n');
+			}
+
+			_Write('}');
+		}
+	}
+
+	template
+	void _WriteValue(const BObjectList& value)
+	{
+		int32 count = value.CountItems();
+		if (count == 1) {
+			_Write(value.ItemAt(0)->ToString());
+		} else {
+			_Write("{\n", 2);
+
+			int32 count = value.CountItems();
+			for (int32 i = 0; i < count; i++) {
+				_Write('\t');
+				_Write(value.ItemAt(i)->ToString());
+				_Write('\n');
+			}
+
+			_Write('}');
+		}
+	}
+
+	static inline bool _IsValueEmpty(const char* value)
+	{
+		return value[0] == '\0';
+	}
+
+	static inline bool _IsValueEmpty(const BPackageVersion& value)
+	{
+		return false;
+	}
+
+	template
+	static inline bool _IsValueEmpty(const List& value)
+	{
+		return value.IsEmpty();
+	}
+
+	void _WriteMaybeQuoted(const char* data)
+	{
+		// check whether quoting is needed
+		bool needsQuoting = false;
+		bool needsEscaping = false;
+		for (const char* it = data; *it != '\0'; it++) {
+			if (isalnum(*it) || *it == '.' || *it == '-' || *it == '_'
+				|| *it == ':' || *it == '+') {
+				continue;
+			}
+
+			needsQuoting = true;
+
+			if (*it == '\t' || *it == '\n' || *it == '"' || *it == '\\') {
+				needsEscaping = true;
+				break;
+			}
+		}
+
+		if (!needsQuoting) {
+			_Write(data);
+			return;
+		}
+
+		// we need quoting
+		_Write('"');
+
+		// escape the string, if necessary
+		if (needsEscaping) {
+			const char* start = data;
+			const char* end = data;
+			while (*end != '\0') {
+				char replacement[2];
+				switch (*end) {
+					case '\t':
+						replacement[1] = 't';
+						break;
+					case '\n':
+						replacement[1] = 'n';
+						break;
+					case '"':
+					case '\\':
+						replacement[1] = *end;
+						break;
+					default:
+						end++;
+						continue;
+				}
+
+				if (start < end)
+					_Write(start, end - start);
+
+				replacement[0] = '\\';
+				_Write(replacement, 2);
+			}
+		} else
+			_Write(data);
+
+		_Write('"');
+	}
+
+	inline void _Write(char data)
+	{
+		_Write(&data, 1);
+	}
+
+	inline void _Write(const char* data)
+	{
+		_Write(data, strlen(data));
+	}
+
+	inline void _Write(const BString& data)
+	{
+		_Write(data, data.Length());
+	}
+
+	void _Write(const void* data, size_t size)
+	{
+		if (fError == B_OK) {
+			ssize_t bytesWritten = fData.Write(data, size);
+			if (bytesWritten < 0)
+				fError = bytesWritten;
+		}
+	}
+
+private:
+	BMallocIO	fData;
+	status_t	fError;
+};
+
+
+// #pragma mark - BPackageInfo
+
+
+
 BPackageInfo::BPackageInfo()
 	:
 	fFlags(0),
@@ -1392,6 +1624,43 @@ BPackageInfo::Clear()
 }
 
 
+status_t
+BPackageInfo::GetConfigString(BString& _string) const
+{
+	return StringBuilder()
+		.Write("name", fName)
+		.Write("version", fVersion)
+		.Write("summary", fSummary)
+		.Write("description", fDescription)
+		.Write("vendor", fVendor)
+		.Write("packager", fPackager)
+		.Write("architecture", kArchitectureNames[fArchitecture])
+		.Write("copyrights", fCopyrightList)
+		.Write("licenses", fLicenseList)
+		.Write("urls", fURLList)
+		.Write("source-urls", fSourceURLList)
+		.Write("provides", fProvidesList)
+		.Write("requires", fRequiresList)
+		.Write("supplements", fSupplementsList)
+		.Write("conflicts", fConflictsList)
+		.Write("freshens", fFreshensList)
+		.Write("replaces", fReplacesList)
+		.WriteFlags("flags", fFlags)
+		.Write("checksum", fChecksum)
+		.GetString(_string);
+	// Note: fInstallPath can not be specified via .PackageInfo.
+}
+
+
+BString
+BPackageInfo::ToString() const
+{
+	BString string;
+	GetConfigString(string);
+	return string;
+}
+
+
 /*static*/ status_t
 BPackageInfo::GetArchitectureByName(const BString& name,
 	BPackageArchitecture& _architecture)

From b254217a09a45fe317ae8b8e9ad9a8ddfc3df4b0 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 11 Apr 2013 00:59:48 +0200
Subject: [PATCH 0391/1170] package daemon: Properly qualify private package
 headers

... instead of adding the private package header directory to the
include paths.
---
 src/servers/package/Jamfile    | 2 +-
 src/servers/package/Root.h     | 2 +-
 src/servers/package/Volume.cpp | 2 +-
 src/servers/package/Volume.h   | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/servers/package/Jamfile b/src/servers/package/Jamfile
index 05425898e9..4125ab17ba 100644
--- a/src/servers/package/Jamfile
+++ b/src/servers/package/Jamfile
@@ -1,7 +1,7 @@
 SubDir HAIKU_TOP src servers package ;
 
 UsePrivateSystemHeaders ;
-UsePrivateHeaders app kernel package shared ;
+UsePrivateHeaders app kernel shared ;
 
 Server package_daemon
  	:
diff --git a/src/servers/package/Root.h b/src/servers/package/Root.h
index 4709d32f86..d4fb807ddd 100644
--- a/src/servers/package/Root.h
+++ b/src/servers/package/Root.h
@@ -16,7 +16,7 @@
 
 #include 
 
-#include 
+#include 
 
 #include "JobQueue.h"
 #include "Volume.h"
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index bd8ba7bd2b..697b122411 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -30,7 +30,7 @@
 
 #include 
 #include 
-#include 
+#include 
 
 #include "DebugSupport.h"
 
diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h
index 1885b1d03d..2b5f2ce281 100644
--- a/src/servers/package/Volume.h
+++ b/src/servers/package/Volume.h
@@ -15,7 +15,7 @@
 #include 
 #include 
 
-#include 
+#include 
 #include 
 
 #include "Package.h"

From 62f7022a8294bbd5407826c0bb8b071975ed90d5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 11 Apr 2013 02:03:25 +0200
Subject: [PATCH 0392/1170] package kit: get active packages list from daemon

* daemon: Implement private message protocol to retrieve the active
  packages.
* BPackageRoster::GetActivePackages(): Get the active packages list
  from the daemon.
---
 headers/private/package/PackageDaemonDefs.h | 37 +++++++++
 src/kits/package/PackageRoster.cpp          | 61 ++++++--------
 src/servers/package/PackageDaemon.cpp       | 22 +++++-
 src/servers/package/Root.cpp                | 88 ++++++++++++++++++++-
 src/servers/package/Root.h                  |  8 ++
 src/servers/package/Volume.cpp              | 24 ++++++
 src/servers/package/Volume.h                |  1 +
 7 files changed, 201 insertions(+), 40 deletions(-)
 create mode 100644 headers/private/package/PackageDaemonDefs.h

diff --git a/headers/private/package/PackageDaemonDefs.h b/headers/private/package/PackageDaemonDefs.h
new file mode 100644
index 0000000000..ccb74b7df6
--- /dev/null
+++ b/headers/private/package/PackageDaemonDefs.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef _PACKAGE__PRIVATE__PACKAGE_DAEMON_DEFS_H_
+#define _PACKAGE__PRIVATE__PACKAGE_DAEMON_DEFS_H_
+
+
+namespace BPackageKit {
+namespace BPrivate {
+
+
+#define PACKAGE_DAEMON_APP_SIGNATURE "application/x-vnd.haiku-package_daemon"
+
+
+// message codes for requests to and replies from the daemon
+enum {
+	MESSAGE_GET_PACKAGES		= 'PKGG',
+		// "location": int32
+		//		the respective installation location constant
+	MESSAGE_GET_PACKAGES_REPLY	= 'PKGR'
+		// "active packages": string[]
+		//		file names of the active packages (no path)
+		// "inactive packages": string[]
+		//		file names of the inactive packages (no path)
+	
+};
+
+
+#endif	// _PACKAGE__PRIVATE__PACKAGE_DAEMON_DEFS_H_
+
+
+}	// namespace BPrivate
+}	// namespace BPackageKit
diff --git a/src/kits/package/PackageRoster.cpp b/src/kits/package/PackageRoster.cpp
index 5ee0451718..62b4bb90ad 100644
--- a/src/kits/package/PackageRoster.cpp
+++ b/src/kits/package/PackageRoster.cpp
@@ -14,6 +14,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -26,6 +27,10 @@
 
 #include 
 
+#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
+#	include 
+#endif
+
 
 namespace BPackageKit {
 
@@ -206,63 +211,45 @@ BPackageRoster::GetActivePackages(BPackageInstallationLocation location,
 			return B_BAD_VALUE;
 	}
 
-	// find the package links directory
-	BPath packageLinksPath;
-	status_t error = find_directory(B_PACKAGE_LINKS_DIRECTORY,
-		&packageLinksPath);
+	// get the package daemon's address
+	status_t error;
+	BMessenger messenger(PACKAGE_DAEMON_APP_SIGNATURE, -1, &error);
 	if (error != B_OK)
 		return error;
 
+	// request a list of packages
+	BMessage request(BPackageKit::BPrivate::MESSAGE_GET_PACKAGES);
+	error = request.AddInt32("location", location);
+	if (error != B_OK)
+		return error;
+
+	BMessage reply;
+	messenger.SendMessage(&request, &reply);
+	if (reply.what != BPackageKit::BPrivate::MESSAGE_GET_PACKAGES_REPLY)
+		return B_ERROR;
+
 	// find and open the packages directory
 	BPath packagesDirPath;
 	error = find_directory(packagesDirectory, &packagesDirPath);
 	if (error != B_OK)
 		return error;
 
-	BDirectory directory;
-	error = directory.SetTo(packagesDirPath.Path());
-	if (error != B_OK)
-		return error;
-
-	// TODO: Implement that correctly be reading the activation files/directory!
-
 	// iterate through the packages
-	char buffer[sizeof(dirent) + B_FILE_NAME_LENGTH];
-	dirent* entry = (dirent*)&buffer;
-	while (directory.GetNextDirents(entry, sizeof(buffer), 1) == 1) {
-		if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0)
-			continue;
-
+	const char* packageFileName;
+	for (int32 i = 0;
+		reply.FindString("active packages", i, &packageFileName) == B_OK; i++) {
 		// get the full package file path
 		BPath packagePath;
-		error = packagePath.SetTo(packagesDirPath.Path(), entry->d_name);
+		error = packagePath.SetTo(packagesDirPath.Path(), packageFileName);
 		if (error != B_OK)
 			continue;
 
 		// read the package info from the file
-		BPackageReader packageReader(NULL);
-		error = packageReader.Init(packagePath.Path());
-		if (error != B_OK)
-			continue;
-
 		BPackageInfo info;
-		BPackageInfoContentHandler handler(info);
-		error = packageReader.ParseContent(&handler);
+		error = info.ReadFromPackageFile(packagePath.Path());
 		if (error != B_OK || info.InitCheck() != B_OK)
 			continue;
 
-		// check whether the package is really active by verifying that a
-		// package link exists for it
-		BString packageLinkName(info.Name());
-		packageLinkName << '-' << info.Version().ToString();
-		BPath packageLinkPath;
-		struct stat st;
-		if (packageLinkPath.SetTo(packageLinksPath.Path(), packageLinkName)
-				!= B_OK
-			|| lstat(packageLinkPath.Path(), &st) != 0) {
-			continue;
-		}
-
 		// add the info
 		error = packageInfos.AddInfo(info);
 		if (error != B_OK)
diff --git a/src/servers/package/PackageDaemon.cpp b/src/servers/package/PackageDaemon.cpp
index 4380102f5c..e5ebee0515 100644
--- a/src/servers/package/PackageDaemon.cpp
+++ b/src/servers/package/PackageDaemon.cpp
@@ -16,15 +16,19 @@
 #include 
 
 #include 
+#include 
 
 #include "DebugSupport.h"
 #include "Root.h"
 #include "Volume.h"
 
 
+using namespace BPackageKit::BPrivate;
+
+
 PackageDaemon::PackageDaemon(status_t* _error)
 	:
-	BServer("application/x-vnd.haiku-package_daemon", false, _error),
+	BServer(PACKAGE_DAEMON_APP_SIGNATURE, false, _error),
 	fSystemRoot(NULL),
 	fRoots(10, true),
 	fVolumeWatcher()
@@ -34,7 +38,6 @@ PackageDaemon::PackageDaemon(status_t* _error)
 
 PackageDaemon::~PackageDaemon()
 {
-//	delete fSystemRoot;
 }
 
 
@@ -56,6 +59,11 @@ PackageDaemon::Init()
 		_RegisterVolume(device);
 	}
 
+	// find the system root
+	struct stat st;
+	if (stat("/boot", &st) == 0)
+		fSystemRoot = _FindRoot(node_ref(st.st_dev, st.st_ino));
+
 	return B_OK;
 }
 
@@ -76,6 +84,16 @@ PackageDaemon::MessageReceived(BMessage* message)
 				_HandleVolumeUnmounted(message);
 			break;
 		}
+
+		case MESSAGE_GET_PACKAGES:
+		{
+			if (fSystemRoot == NULL)
+				break;
+
+			fSystemRoot->HandleGetPackagesRequest(DetachCurrentMessage());
+			break;
+		}
+
 		default:
 			BServer::MessageReceived(message);
 			break;
diff --git a/src/servers/package/Root.cpp b/src/servers/package/Root.cpp
index 012f5d0276..b2d63b4bf5 100644
--- a/src/servers/package/Root.cpp
+++ b/src/servers/package/Root.cpp
@@ -11,8 +11,12 @@
 
 #include 
 #include 
+#include 
 #include 
 
+#include 
+#include 
+
 #include "DebugSupport.h"
 
 
@@ -38,11 +42,34 @@ private:
 };
 
 
+// #pragma mark - VolumeJob
+
+
+struct Root::HandleGetPackagesJob : public Job {
+	HandleGetPackagesJob(Root* root, BMessage* message)
+		:
+		fRoot(root),
+		fMessage(message)
+	{
+	}
+
+	virtual void Do()
+	{
+		fRoot->_HandleGetPackagesRequest(fMessage.Get());
+	}
+
+private:
+	Root*					fRoot;
+	ObjectDeleter	fMessage;
+};
+
+
 // #pragma mark - Root
 
 
 Root::Root()
 	:
+	fLock("packagefs root"),
 	fNodeRef(),
 	fPath(),
 	fSystemVolume(NULL),
@@ -68,11 +95,15 @@ Root::Init(const node_ref& nodeRef)
 {
 	fNodeRef = nodeRef;
 
-	// init job queue and spawn job runner thread
+	// init members and spawn job runner thread
 	status_t error = fJobQueue.Init();
 	if (error != B_OK)
 		RETURN_ERROR(error);
 
+	error = fLock.InitCheck();
+	if (error != B_OK)
+		RETURN_ERROR(error);
+
 	fJobRunner = spawn_thread(&_JobRunnerEntry, "job runner", B_NORMAL_PRIORITY,
 		this);
 	if (fJobRunner < 0)
@@ -112,6 +143,8 @@ Root::Init(const node_ref& nodeRef)
 status_t
 Root::RegisterVolume(Volume* volume)
 {
+	AutoLocker locker(fLock);
+
 	Volume** volumeToSet = _GetVolume(volume->MountType());
 	if (volumeToSet == NULL)
 		return B_BAD_VALUE;
@@ -142,6 +175,8 @@ Root::RegisterVolume(Volume* volume)
 void
 Root::UnregisterVolume(Volume* volume)
 {
+	AutoLocker locker(fLock);
+
 	Volume** volumeToSet = _GetVolume(volume->MountType());
 	if (volumeToSet == NULL || *volumeToSet != volume) {
 		ERROR("Root::UnregisterVolume(): can't unregister unknown volume at "
@@ -160,6 +195,8 @@ Root::UnregisterVolume(Volume* volume)
 Volume*
 Root::FindVolume(dev_t deviceID) const
 {
+	AutoLocker locker(fLock);
+
 	Volume* volumes[] = { fSystemVolume, fCommonVolume, fHomeVolume };
 	for (size_t i = 0; i < sizeof(volumes) / sizeof(volumes[0]); i++) {
 		Volume* volume = volumes[i];
@@ -171,6 +208,20 @@ Root::FindVolume(dev_t deviceID) const
 }
 
 
+void
+Root::HandleGetPackagesRequest(BMessage* message)
+{
+	HandleGetPackagesJob* job
+		= new(std::nothrow) HandleGetPackagesJob(this, message);
+	if (job == NULL) {
+		delete message;
+		return;
+	}
+
+	_QueueJob(job);
+}
+
+
 void
 Root::VolumeNodeMonitorEventOccurred(Volume* volume)
 {
@@ -235,8 +286,11 @@ void
 Root::_InitPackages(Volume* volume)
 {
 	if (volume->InitPackages(this) == B_OK) {
+		AutoLocker locker(fLock);
 		Volume* nextVolume = _NextVolumeFor(volume);
 		Volume* nextNextVolume = _NextVolumeFor(nextVolume);
+		locker.Unlock();
+
 		volume->InitialVerify(nextVolume, nextNextVolume);
 	}
 }
@@ -259,6 +313,38 @@ Root::_ProcessNodeMonitorEvents(Volume* volume)
 }
 
 
+void
+Root::_HandleGetPackagesRequest(BMessage* message)
+{
+	int32 location;
+	if (message->FindInt32("location", &location) != B_OK
+		|| location < 0
+		|| location >= B_PACKAGE_INSTALLATION_LOCATION_ENUM_COUNT) {
+		return;
+	}
+
+	// get the volume and let it handle the message
+	AutoLocker locker(fLock);
+	Volume* volume;
+	switch ((BPackageInstallationLocation)location) {
+		case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM:
+			volume = fSystemVolume;
+			break;
+		case B_PACKAGE_INSTALLATION_LOCATION_COMMON:
+			volume = fCommonVolume;
+			break;
+		case B_PACKAGE_INSTALLATION_LOCATION_HOME:
+			volume = fHomeVolume;
+			break;
+		default:
+			return;
+	}
+
+	if (volume != NULL)
+		volume->HandleGetPackagesRequest(message);
+}
+
+
 status_t
 Root::_QueueJob(Job* job)
 {
diff --git a/src/servers/package/Root.h b/src/servers/package/Root.h
index d4fb807ddd..ad84421aa9 100644
--- a/src/servers/package/Root.h
+++ b/src/servers/package/Root.h
@@ -9,6 +9,7 @@
 #define ROOT_H
 
 
+#include 
 #include 
 #include 
 #include 
@@ -40,6 +41,8 @@ public:
 
 			Volume*				FindVolume(dev_t deviceID) const;
 
+			void				HandleGetPackagesRequest(BMessage* message);
+
 private:
 	// Volume::Listener
 	virtual	void				VolumeNodeMonitorEventOccurred(Volume* volume);
@@ -49,6 +52,9 @@ protected:
 
 private:
 			struct VolumeJob;
+			struct HandleGetPackagesJob;
+
+			friend struct HandleGetPackagesJob;
 
 private:
 			Volume**			_GetVolume(PackageFSMountType mountType);
@@ -57,6 +63,7 @@ private:
 			void				_InitPackages(Volume* volume);
 			void				_DeleteVolume(Volume* volume);
 			void				_ProcessNodeMonitorEvents(Volume* volume);
+			void				_HandleGetPackagesRequest(BMessage* message);
 
 			status_t			_QueueJob(Job* job);
 
@@ -64,6 +71,7 @@ private:
 			status_t			_JobRunner();
 
 private:
+	mutable	BLocker				fLock;
 			node_ref			fNodeRef;
 			BString				fPath;
 			Volume*				fSystemVolume;
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index 697b122411..e4f75d15dc 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -30,11 +30,15 @@
 
 #include 
 #include 
+#include 
 #include 
 
 #include "DebugSupport.h"
 
 
+using namespace BPackageKit::BPrivate;
+
+
 static const char* const kPackageFileNameExtension = ".hpkg";
 static const char* const kConfigDirectoryName
 	= PACKAGES_DIRECTORY_CONFIG_DIRECTORY;
@@ -43,6 +47,8 @@ static const char* const kActivationFileName
 static const char* const kTemporaryActivationFileName
 	= PACKAGES_DIRECTORY_ACTIVATION_FILE ".tmp";
 
+static bigtime_t kCommunicationTimeout = 1000000;
+
 
 // #pragma mark - Listener
 
@@ -328,6 +334,24 @@ INFORM("Volume::InitialVerify(%p, %p)\n", nextVolume, nextNextVolume);
 }
 
 
+void
+Volume::HandleGetPackagesRequest(BMessage* message)
+{
+	BMessage reply(MESSAGE_GET_PACKAGES_REPLY);
+
+	for (PackageFileNameHashTable::Iterator it
+			= fPackagesByFileName.GetIterator(); it.HasNext();) {
+		Package* package = it.Next();
+		const char* fieldName = package->IsActive()
+			? "active packages" : "inactive packages";
+		if (reply.AddString(fieldName, package->FileName()) != B_OK)
+			return;
+	}
+
+	message->SendReply(&reply, (BHandler*)NULL, kCommunicationTimeout);
+}
+
+
 void
 Volume::Unmounted()
 {
diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h
index 2b5f2ce281..404f6c4a57 100644
--- a/src/servers/package/Volume.h
+++ b/src/servers/package/Volume.h
@@ -48,6 +48,7 @@ public:
 									bool activeOnly);
 			void				InitialVerify(Volume* nextVolume,
 									Volume* nextNextVolume);
+			void				HandleGetPackagesRequest(BMessage* message);
 
 			void				Unmounted();
 

From a78a2540a820ca541177fce1d454d3aa7073715c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 11 Apr 2013 17:21:27 +0200
Subject: [PATCH 0393/1170] LibsolvSolver: Fix the lazy re-/initialization

* _Init() was a bit too enthusiastic, throwing really everything away.
  So, after calling it at the beginning of _AddRepositories() there
  wouldn't be any repositories anymore.
* Rename _Init() to _InitPool() to make its purpose clearer.
* Pull a _CleanupPool() out of _Cleanup() that only deletes the pool
  and anything depending on it.
* RepositoryInfo::HasChanged(): Always consider changed when there's no
  libsolv repo yet.
---
 src/kits/package/solver/LibsolvSolver.cpp | 32 ++++++++++++++++++-----
 src/kits/package/solver/LibsolvSolver.h   |  3 ++-
 2 files changed, 27 insertions(+), 8 deletions(-)

diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index af536af151..2a2926f859 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -62,7 +62,7 @@ struct LibsolvSolver::RepositoryInfo {
 		:
 		fRepository(repository),
 		fSolvRepo(NULL),
-		fChangeCount(repository->ChangeCount() - 1)
+		fChangeCount(repository->ChangeCount())
 	{
 	}
 
@@ -83,7 +83,7 @@ struct LibsolvSolver::RepositoryInfo {
 
 	bool HasChanged() const
 	{
-		return fChangeCount != fRepository->ChangeCount();
+		return fChangeCount != fRepository->ChangeCount() || fSolvRepo == NULL;
 	}
 
 	void SetUnchanged()
@@ -162,6 +162,8 @@ LibsolvSolver::~LibsolvSolver()
 status_t
 LibsolvSolver::Init()
 {
+	_Cleanup();
+
 	// We do all initialization lazily.
 	return B_OK;
 }
@@ -370,9 +372,9 @@ LibsolvSolver::GetResult(BSolverResult& _result)
 
 
 status_t
-LibsolvSolver::_Init()
+LibsolvSolver::_InitPool()
 {
-	_Cleanup();
+	_CleanupPool();
 
 	fPool = pool_create();
 
@@ -403,12 +405,28 @@ LibsolvSolver::_Init()
 void
 LibsolvSolver::_Cleanup()
 {
-	_CleanupSolver();
+	_CleanupPool();
 
-	fSolvablePackages.clear();
 	fInstalledRepository = NULL;
 	fRepositoryInfos.MakeEmpty();
 
+}
+
+
+void
+LibsolvSolver::_CleanupPool()
+{
+	// clean up solver data
+	_CleanupSolver();
+
+	// clean up our data structures that depend on/refer to libsolv pool data
+	fSolvablePackages.clear();
+
+	int32 repositoryCount = fRepositoryInfos.CountItems();
+	for (int32 i = 0; i < repositoryCount; i++)
+		fRepositoryInfos.ItemAt(i)->SetSolvRepo(NULL);
+
+	// delete the pool
 	if (fPool != NULL) {
 		pool_free(fPool);
 		fPool = NULL;
@@ -449,7 +467,7 @@ LibsolvSolver::_AddRepositories()
 		return B_OK;
 
 	// something has changed -- re-create the pool
-	status_t error = _Init();
+	status_t error = _InitPool();
 	if (error != B_OK)
 		return error;
 
diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h
index 81f99eb1aa..5ae160264c 100644
--- a/src/kits/package/solver/LibsolvSolver.h
+++ b/src/kits/package/solver/LibsolvSolver.h
@@ -55,8 +55,9 @@ private:
 			typedef std::map SolvableMap;
 
 private:
-			status_t			_Init();
+			status_t			_InitPool();
 			void				_Cleanup();
+			void				_CleanupPool();
 			void				_CleanupSolver();
 
 			bool				_HaveRepositoriesChanged() const;

From fc57db481fa36695457bc355ca9710c91d53ab1d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 11 Apr 2013 17:30:08 +0200
Subject: [PATCH 0394/1170] BSolver/LibsolvSolver: Add FindPackages()

Given a search string it finds all matching packages.
---
 headers/os/package/solver/Solver.h        | 14 +++++
 src/kits/package/solver/LibsolvSolver.cpp | 74 +++++++++++++++++++++++
 src/kits/package/solver/LibsolvSolver.h   |  5 ++
 3 files changed, 93 insertions(+)

diff --git a/headers/os/package/solver/Solver.h b/headers/os/package/solver/Solver.h
index 2f1160b871..5403baa88e 100644
--- a/headers/os/package/solver/Solver.h
+++ b/headers/os/package/solver/Solver.h
@@ -6,12 +6,14 @@
 #define _PACKAGE__SOLVER_H_
 
 
+#include 
 #include 
 
 
 namespace BPackageKit {
 
 
+class BSolverPackage;
 class BSolverPackageSpecifierList;
 class BSolverProblem;
 class BSolverRepository;
@@ -19,6 +21,14 @@ class BSolverResult;
 
 
 class BSolver {
+public:
+			// FindPackages() flags
+			enum {
+				B_FIND_CASE_INSENSITIVE		= 0x01,
+				B_FIND_IN_SUMMARY			= 0x02,
+				B_FIND_IN_DESCRIPTION		= 0x04
+			};
+
 public:
 	virtual						~BSolver();
 
@@ -29,6 +39,10 @@ public:
 	virtual	status_t			AddRepository(
 									BSolverRepository* repository) = 0;
 
+	virtual	status_t			FindPackages(const char* searchString,
+									uint32 flags,
+									BObjectList& _packages) = 0;
+
 	virtual	status_t			Install(
 									const BSolverPackageSpecifierList&
 										packages) = 0;
diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index 2a2926f859..a1ab43ca0b 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -57,6 +57,20 @@ struct LibsolvSolver::SolvQueue : Queue {
 };
 
 
+struct LibsolvSolver::SolvDataIterator : Dataiterator {
+	SolvDataIterator(Pool* pool, Repo* repo, Id solvableId, Id keyname,
+		const char* match, int flags)
+	{
+		dataiterator_init(this, pool, repo, solvableId, keyname, match, flags);
+	}
+
+	~SolvDataIterator()
+	{
+		dataiterator_free(this);
+	}
+};
+
+
 struct LibsolvSolver::RepositoryInfo {
 	RepositoryInfo(BSolverRepository* repository)
 		:
@@ -197,6 +211,66 @@ LibsolvSolver::AddRepository(BSolverRepository* repository)
 }
 
 
+status_t
+LibsolvSolver::FindPackages(const char* searchString, uint32 flags,
+	BObjectList& _packages)
+{
+	// add repositories to pool
+	status_t error = _AddRepositories();
+	if (error != B_OK)
+		return error;
+
+	// create data iterator
+	int iteratorFlags = SEARCH_SUBSTRING;
+	if ((flags & B_FIND_CASE_INSENSITIVE) != 0)
+		iteratorFlags |= SEARCH_NOCASE;
+
+	SolvDataIterator iterator(fPool, 0, 0, 0, searchString, iteratorFlags);
+
+	// search package names
+	dataiterator_set_keyname(&iterator, SOLVABLE_NAME);
+	dataiterator_set_search(&iterator, 0, 0);
+
+	SolvQueue selection;
+	while (dataiterator_step(&iterator))
+		queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
+
+	// search package summaries
+	if ((flags & B_FIND_IN_SUMMARY) != 0) {
+		dataiterator_set_keyname(&iterator, SOLVABLE_SUMMARY);
+		dataiterator_set_search(&iterator, 0, 0);
+
+		while (dataiterator_step(&iterator))
+			queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
+	}
+
+	// search package description
+	if ((flags & B_FIND_IN_DESCRIPTION) != 0) {
+		dataiterator_set_keyname(&iterator, SOLVABLE_DESCRIPTION);
+		dataiterator_set_search(&iterator, 0, 0);
+
+		while (dataiterator_step(&iterator))
+			queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
+	}
+
+	// get solvables	
+	SolvQueue solvables;
+	selection_solvables(fPool, &selection, &solvables);
+
+	// get packages
+	for (int i = 0; i < solvables.count; i++) {
+		BSolverPackage* package = _GetPackage(solvables.elements[i]);
+		if (package == NULL)
+			return B_ERROR;
+
+		if (!_packages.AddItem(package))
+			return B_NO_MEMORY;
+	}
+
+	return B_OK;
+}
+
+
 status_t
 LibsolvSolver::Install(const BSolverPackageSpecifierList& packages)
 {
diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h
index 5ae160264c..eaecd8fdc5 100644
--- a/src/kits/package/solver/LibsolvSolver.h
+++ b/src/kits/package/solver/LibsolvSolver.h
@@ -34,6 +34,10 @@ public:
 
 	virtual	status_t			AddRepository(BSolverRepository* repository);
 
+	virtual	status_t			FindPackages(const char* searchString,
+									uint32 flags,
+									BObjectList& _packages);
+
 	virtual	status_t			Install(
 									const BSolverPackageSpecifierList&
 										packages);
@@ -46,6 +50,7 @@ public:
 
 private:
 			struct SolvQueue;
+			struct SolvDataIterator;
 			struct RepositoryInfo;
 			struct Problem;
 			struct Solution;

From 789867563ad6e4730b470bfe2b8b7314aa671756 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 11 Apr 2013 17:32:17 +0200
Subject: [PATCH 0395/1170] pkgman RepositoryBuilder: Add BRepositoryConfig
 constructor

---
 src/bin/pkgman/RepositoryBuilder.cpp | 13 +++++++++++++
 src/bin/pkgman/RepositoryBuilder.h   |  2 ++
 2 files changed, 15 insertions(+)

diff --git a/src/bin/pkgman/RepositoryBuilder.cpp b/src/bin/pkgman/RepositoryBuilder.cpp
index a307533c97..1b7e0e9b1a 100644
--- a/src/bin/pkgman/RepositoryBuilder.cpp
+++ b/src/bin/pkgman/RepositoryBuilder.cpp
@@ -34,6 +34,19 @@ RepositoryBuilder::RepositoryBuilder(BSolverRepository& repository,
 }
 
 
+RepositoryBuilder::RepositoryBuilder(BSolverRepository& repository,
+	const BRepositoryConfig& config)
+	:
+	fRepository(repository),
+	fErrorName(fRepository.Name()),
+	fPackagePaths(NULL)
+{
+	status_t error = fRepository.SetTo(config);
+	if (error != B_OK)
+		DIE(error, "failed to init %s repository", fErrorName.String());
+}
+
+
 RepositoryBuilder&
 RepositoryBuilder::SetPackagePathMap(PackagePathMap* packagePaths)
 {
diff --git a/src/bin/pkgman/RepositoryBuilder.h b/src/bin/pkgman/RepositoryBuilder.h
index 0b9e72af58..d3c72ad9a6 100644
--- a/src/bin/pkgman/RepositoryBuilder.h
+++ b/src/bin/pkgman/RepositoryBuilder.h
@@ -31,6 +31,8 @@ public:
 								RepositoryBuilder(BSolverRepository& repository,
 									const BString& name,
 									const BString& errorName = BString());
+								RepositoryBuilder(BSolverRepository& repository,
+									const BRepositoryConfig& config);
 
 			RepositoryBuilder&	SetPackagePathMap(PackagePathMap* packagePaths);
 

From dd46d9816332a8936534aeeb26613c5269b75a6a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 11 Apr 2013 17:33:23 +0200
Subject: [PATCH 0396/1170] pkgman: Add "search" command

---
 src/bin/pkgman/Jamfile            |   1 +
 src/bin/pkgman/command_search.cpp | 247 ++++++++++++++++++++++++++++++
 src/bin/pkgman/pkgman.cpp         |   7 +-
 src/bin/pkgman/pkgman.h           |   3 +-
 4 files changed, 255 insertions(+), 3 deletions(-)
 create mode 100644 src/bin/pkgman/command_search.cpp

diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile
index db1206a47f..de9b873e36 100644
--- a/src/bin/pkgman/Jamfile
+++ b/src/bin/pkgman/Jamfile
@@ -8,6 +8,7 @@ BinCommand pkgman :
 	command_list_repos.cpp
 	command_refresh.cpp
 	command_resolve_dependencies.cpp
+	command_search.cpp
 	DecisionProvider.cpp
 	JobStateListener.cpp
 	PackageInfoErrorListener.cpp
diff --git a/src/bin/pkgman/command_search.cpp b/src/bin/pkgman/command_search.cpp
new file mode 100644
index 0000000000..069489ea37
--- /dev/null
+++ b/src/bin/pkgman/command_search.cpp
@@ -0,0 +1,247 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include 
+
+#include "pkgman.h"
+#include "RepositoryBuilder.h"
+
+
+// TODO: internationalization!
+// The printing code will need serious attention wrt. dealing with UTF-8 and,
+// even worse, full-width characters.
+
+
+using namespace BPackageKit;
+
+
+typedef std::map PackagePathMap;
+
+
+static const char* kCommandUsage =
+	"Usage: %s search \n"
+	"Searches for packages matching .\n"
+	"\n"
+	"Options:\n"
+	"  -i, --installed-only\n"
+	"    Only find installed packages.\n"
+	"  -u, --uninstalled-only\n"
+	"    Only find not installed packages.\n"
+	"\n"
+;
+
+
+static void
+print_command_usage_and_exit(bool error)
+{
+    fprintf(error ? stderr : stdout, kCommandUsage, kProgramName);
+    exit(error ? 1 : 0);
+}
+
+
+static int
+get_terminal_width()
+{
+    int fd = fileno(stdout);
+    struct winsize windowSize;
+	if (isatty(fd) == 1 && ioctl(fd, TIOCGWINSZ, &windowSize) == 0)
+		return windowSize.ws_col;
+	
+    return INT_MAX;
+}
+
+
+int
+command_search(int argc, const char* const* argv)
+{
+	bool installedOnly = false;
+	bool uninstalledOnly = false;
+
+	while (true) {
+		static struct option sLongOptions[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ "installed-only", no_argument, 0, 'i' },
+			{ "uninstalled-only", no_argument, 0, 'u' },
+			{ 0, 0, 0, 0 }
+		};
+
+		opterr = 0; // don't print errors
+		int c = getopt_long(argc, (char**)argv, "hu", sLongOptions, NULL);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'h':
+				print_command_usage_and_exit(false);
+				break;
+
+			case 'i':
+				installedOnly = true;
+				uninstalledOnly = false;
+				break;
+
+			case 'u':
+				uninstalledOnly = true;
+				installedOnly = false;
+				break;
+
+			default:
+				print_command_usage_and_exit(true);
+				break;
+		}
+	}
+
+	// The remaining argument is the search string.
+	if (argc != optind + 1)
+		print_command_usage_and_exit(true);
+
+	const char* searchString = argv[optind++];
+
+	// create the solver
+	BSolver* solver;
+	status_t error = BSolver::Create(solver);
+	if (error != B_OK)
+		DIE(error, "failed to create solver");
+
+	// add repositories
+
+	// installed
+	BSolverRepository systemRepository;
+	BSolverRepository commonRepository;
+	BSolverRepository homeRepository;
+	if (!uninstalledOnly) {
+		RepositoryBuilder(systemRepository, "system")
+			.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, "system")
+			.AddToSolver(solver, false);
+		RepositoryBuilder(commonRepository, "common")
+			.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common")
+			.AddToSolver(solver, false);
+//		RepositoryBuilder(homeRepository, "home")
+//			.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_HOME, "home")
+//			.AddToSolver(solver, false);
+	}
+
+	// not installed
+	BObjectList uninstalledRepositories(10, true);
+
+	if (!installedOnly) {
+		BPackageRoster roster;
+		BStringList repositoryNames;
+		error = roster.GetRepositoryNames(repositoryNames);
+		if (error != B_OK)
+			WARN(error, "failed to get repository names");
+
+		int32 repositoryNameCount = repositoryNames.CountStrings();
+		for (int32 i = 0; i < repositoryNameCount; i++) {
+			const BString& name = repositoryNames.StringAt(i);
+			BRepositoryConfig config;
+			error = roster.GetRepositoryConfig(name, &config);
+			if (error != B_OK) {
+				WARN(error, "failed to get config for repository \"%s\". "
+					"Skipping.", name.String());
+				continue;
+			}
+
+			BSolverRepository* repository = new(std::nothrow) BSolverRepository;
+			if (repository == NULL
+				|| !uninstalledRepositories.AddItem(repository)) {
+				DIE(B_NO_MEMORY, "out of memory");
+			}
+
+			RepositoryBuilder(*repository, config)
+				.AddToSolver(solver, false);
+		}
+	}
+
+	// search
+	BObjectList packages;
+	error = solver->FindPackages(searchString,
+		BSolver::B_FIND_CASE_INSENSITIVE | BSolver::B_FIND_IN_SUMMARY
+			| BSolver::B_FIND_IN_DESCRIPTION, packages);
+	if (error != B_OK)
+		DIE(error, "searching packages failed");
+
+	if (packages.IsEmpty()) {
+		printf("No matching packages found.\n");
+		return 0;
+	}
+
+	// print table
+
+	// determine column widths
+	BString installedColumnTitle("Installed");
+	BString nameColumnTitle("Name");
+	BString descriptionColumnTitle("Description");
+
+	int installedColumnWidth = installedColumnTitle.Length();
+	int nameColumnWidth = nameColumnTitle.Length();
+	int descriptionColumnWidth = descriptionColumnTitle.Length();
+
+	int32 packageCount = packages.CountItems();
+	for (int32 i = 0; i < packageCount; i++) {
+		BSolverPackage* package = packages.ItemAt(i);
+		nameColumnWidth = std::max(nameColumnWidth,
+			(int)package->Name().Length());
+		descriptionColumnWidth = std::max(descriptionColumnWidth,
+			(int)package->Info().Summary().Length());
+	}
+
+	// print header
+	BString header;
+	header.SetToFormat("%-*s  %-*s  %s",
+		installedColumnWidth, installedColumnTitle.String(),
+		nameColumnWidth, nameColumnTitle.String(),
+		descriptionColumnTitle.String());
+	printf("%s\n", header.String());
+
+	int minLineWidth = header.Length();
+	int lineWidth = minLineWidth + descriptionColumnWidth
+		- descriptionColumnTitle.Length();
+	int terminalWidth = get_terminal_width();
+	if (lineWidth > terminalWidth) {
+		// truncate description
+		int actualLineWidth = std::max(minLineWidth, terminalWidth);
+		descriptionColumnWidth -= lineWidth - actualLineWidth;
+		lineWidth = actualLineWidth;
+	}
+
+	header.SetTo('-', lineWidth);
+	printf("%s\n", header.String());
+
+	// print packages
+	for (int32 i = 0; i < packageCount; i++) {
+		BSolverPackage* package = packages.ItemAt(i);
+
+		const char* installed = "";
+		if (package->Repository() == &systemRepository)
+			installed = "system";
+		else if (package->Repository() == &commonRepository)
+			installed = "common";
+		else if (package->Repository() == &homeRepository)
+			installed = "home";
+
+		printf("%-*s  %-*s  %-*.*s\n",
+			installedColumnWidth, installed,
+			nameColumnWidth, package->Name().String(),
+			descriptionColumnWidth, descriptionColumnWidth,
+			package->Info().Summary().String());
+	}
+
+	return 0;
+}
diff --git a/src/bin/pkgman/pkgman.cpp b/src/bin/pkgman/pkgman.cpp
index 6942008f4b..66117001fa 100644
--- a/src/bin/pkgman/pkgman.cpp
+++ b/src/bin/pkgman/pkgman.cpp
@@ -36,6 +36,9 @@ static const char* kUsage =
 	"  resolve-dependencies   [  ] ...\n"
 	"    Resolves all packages a given package depends on.\n"
 	"\n"
+	"  search \n"
+	"    Searches for packages matching .\n"
+	"\n"
 	"Common Options:\n"
 	"  -h, --help   - Print this usage info.\n"
 ;
@@ -71,8 +74,8 @@ main(int argc, const char* const* argv)
 	if (strcmp(command, "resolve-dependencies") == 0)
 		return command_resolve_dependencies(argc - 1, argv + 1);
 
-//	if (strcmp(command, "search") == 0)
-//		return command_search(argc - 1, argv + 1);
+	if (strcmp(command, "search") == 0)
+		return command_search(argc - 1, argv + 1);
 
 	if (strcmp(command, "help") == 0)
 		print_usage_and_exit(false);
diff --git a/src/bin/pkgman/pkgman.h b/src/bin/pkgman/pkgman.h
index 9808903fd3..c2a2fe9d6e 100644
--- a/src/bin/pkgman/pkgman.h
+++ b/src/bin/pkgman/pkgman.h
@@ -35,10 +35,11 @@ do {																\
 
 void	print_usage_and_exit(bool error);
 int		command_add_repo(int argc, const char* const* argv);
-int		command_resolve_dependencies(int argc, const char* const* argv);  
 int		command_drop_repo(int argc, const char* const* argv);
 int		command_list_repos(int argc, const char* const* argv);
 int		command_refresh(int argc, const char* const* argv);
+int		command_resolve_dependencies(int argc, const char* const* argv);  
+int		command_search(int argc, const char* const* argv);  
 
 
 #endif	// PKGMAN_H

From eb13a353e39799c58dd2a8704e8553ba18a7b1d3 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 11 Apr 2013 17:44:58 +0200
Subject: [PATCH 0397/1170] Rename "packages" subdir "config" to
 "administrative"

... to avoid the impression that it contains something the user can
play with.
---
 headers/private/package/PackagesDirectoryDefs.h      | 2 +-
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 2 +-
 src/servers/package/Volume.cpp                       | 6 +++---
 3 files changed, 5 insertions(+), 5 deletions(-)

diff --git a/headers/private/package/PackagesDirectoryDefs.h b/headers/private/package/PackagesDirectoryDefs.h
index dacd05b6dd..698f670b0c 100644
--- a/headers/private/package/PackagesDirectoryDefs.h
+++ b/headers/private/package/PackagesDirectoryDefs.h
@@ -9,7 +9,7 @@
 #define _PACKAGE__PRIVATE__PACKAGES_DIRECTORY_DEFS_H_
 
 
-#define PACKAGES_DIRECTORY_CONFIG_DIRECTORY	"config"
+#define PACKAGES_DIRECTORY_ADMIN_DIRECTORY	"administrative"
 #define PACKAGES_DIRECTORY_ACTIVATION_FILE	"activated-packages"
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 2e7af7d2e7..426d851f3d 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -69,7 +69,7 @@ const size_t kMaxActivationRequestSize = 10 * 1024 * 1024;
 const size_t kMaxActivationFileSize = 10 * 1024 * 1024;
 
 static const char* const kActivationFilePath
-	= PACKAGES_DIRECTORY_CONFIG_DIRECTORY "/"
+	= PACKAGES_DIRECTORY_ADMIN_DIRECTORY "/"
 		PACKAGES_DIRECTORY_ACTIVATION_FILE;
 
 
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index e4f75d15dc..abc5732f7b 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -40,8 +40,8 @@ using namespace BPackageKit::BPrivate;
 
 
 static const char* const kPackageFileNameExtension = ".hpkg";
-static const char* const kConfigDirectoryName
-	= PACKAGES_DIRECTORY_CONFIG_DIRECTORY;
+static const char* const kAdminDirectoryName
+	= PACKAGES_DIRECTORY_ADMIN_DIRECTORY;
 static const char* const kActivationFileName
 	= PACKAGES_DIRECTORY_ACTIVATION_FILE;
 static const char* const kTemporaryActivationFileName
@@ -540,7 +540,7 @@ fPackagesToBeActivated.size(), fPackagesToBeDeactivated.size());
 	// open and write the temporary file
 	BFile activationFile;
 	BEntry activationFileEntry;
-	status_t error = _OpenPackagesFile(kConfigDirectoryName,
+	status_t error = _OpenPackagesFile(kAdminDirectoryName,
 		kTemporaryActivationFileName,
 		B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE, activationFile,
 		&activationFileEntry);

From 663e351cb468e889ffcd08c07fc867b3002a1c91 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 11 Apr 2013 23:36:12 +0200
Subject: [PATCH 0398/1170] BSolver/pkgman: Support for searching in provides

* BSolver/LibsolvSolver:
  * Add B_FIND_IN_NAME and make searching in the names explicit.
  * Add B_FIND_IN_PROVIDES to search the packages' provides list.
* pkgman: Also search in provides.
---
 headers/os/package/solver/Solver.h        |  6 ++++--
 src/bin/pkgman/command_search.cpp         |  6 ++++--
 src/kits/package/solver/LibsolvSolver.cpp | 21 ++++++++++++++++-----
 3 files changed, 24 insertions(+), 9 deletions(-)

diff --git a/headers/os/package/solver/Solver.h b/headers/os/package/solver/Solver.h
index 5403baa88e..c283b3e993 100644
--- a/headers/os/package/solver/Solver.h
+++ b/headers/os/package/solver/Solver.h
@@ -25,8 +25,10 @@ public:
 			// FindPackages() flags
 			enum {
 				B_FIND_CASE_INSENSITIVE		= 0x01,
-				B_FIND_IN_SUMMARY			= 0x02,
-				B_FIND_IN_DESCRIPTION		= 0x04
+				B_FIND_IN_NAME				= 0x02,
+				B_FIND_IN_SUMMARY			= 0x04,
+				B_FIND_IN_DESCRIPTION		= 0x08,
+				B_FIND_IN_PROVIDES			= 0x10
 			};
 
 public:
diff --git a/src/bin/pkgman/command_search.cpp b/src/bin/pkgman/command_search.cpp
index 069489ea37..41334e26ac 100644
--- a/src/bin/pkgman/command_search.cpp
+++ b/src/bin/pkgman/command_search.cpp
@@ -172,8 +172,10 @@ command_search(int argc, const char* const* argv)
 	// search
 	BObjectList packages;
 	error = solver->FindPackages(searchString,
-		BSolver::B_FIND_CASE_INSENSITIVE | BSolver::B_FIND_IN_SUMMARY
-			| BSolver::B_FIND_IN_DESCRIPTION, packages);
+		BSolver::B_FIND_CASE_INSENSITIVE | BSolver::B_FIND_IN_NAME
+			| BSolver::B_FIND_IN_SUMMARY | BSolver::B_FIND_IN_DESCRIPTION
+			| BSolver::B_FIND_IN_PROVIDES,
+		packages);
 	if (error != B_OK)
 		DIE(error, "searching packages failed");
 
diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index a1ab43ca0b..66c3a78e24 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -226,14 +226,16 @@ LibsolvSolver::FindPackages(const char* searchString, uint32 flags,
 		iteratorFlags |= SEARCH_NOCASE;
 
 	SolvDataIterator iterator(fPool, 0, 0, 0, searchString, iteratorFlags);
+	SolvQueue selection;
 
 	// search package names
-	dataiterator_set_keyname(&iterator, SOLVABLE_NAME);
-	dataiterator_set_search(&iterator, 0, 0);
+	if ((flags & B_FIND_IN_NAME) != 0) {
+		dataiterator_set_keyname(&iterator, SOLVABLE_NAME);
+		dataiterator_set_search(&iterator, 0, 0);
 
-	SolvQueue selection;
-	while (dataiterator_step(&iterator))
-		queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
+		while (dataiterator_step(&iterator))
+			queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
+	}
 
 	// search package summaries
 	if ((flags & B_FIND_IN_SUMMARY) != 0) {
@@ -253,6 +255,15 @@ LibsolvSolver::FindPackages(const char* searchString, uint32 flags,
 			queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
 	}
 
+	// search package provides
+	if ((flags & B_FIND_IN_PROVIDES) != 0) {
+		dataiterator_set_keyname(&iterator, SOLVABLE_PROVIDES);
+		dataiterator_set_search(&iterator, 0, 0);
+
+		while (dataiterator_step(&iterator))
+			queue_push2(&selection, SOLVER_SOLVABLE, iterator.solvid);
+	}
+
 	// get solvables	
 	SolvQueue solvables;
 	selection_solvables(fPool, &selection, &solvables);

From 01758ed3323e22359f685ffb37ef42a3b856fd66 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 12 Apr 2013 00:21:49 +0200
Subject: [PATCH 0399/1170] Rework SolverPackageSpecifier

* It no longer consists of a BPackageResolvableExpression and a
  repository. Instead it can now either refer to a package directly or
  consist of a search string.
* SolverPackageSpecifierList: Add AppendSpecifier() convenience
  versions.
* Adjust LibsolvSolver and pkgman accordingly.
---
 .../package/solver/SolverPackageSpecifier.h   | 32 ++++---
 .../solver/SolverPackageSpecifierList.h       |  5 +-
 .../pkgman/command_resolve_dependencies.cpp   |  6 +-
 src/kits/package/solver/LibsolvSolver.cpp     | 88 +++++++++++++------
 src/kits/package/solver/LibsolvSolver.h       |  3 +
 .../package/solver/SolverPackageSpecifier.cpp | 50 ++++++-----
 .../solver/SolverPackageSpecifierList.cpp     | 14 +++
 7 files changed, 132 insertions(+), 66 deletions(-)

diff --git a/headers/os/package/solver/SolverPackageSpecifier.h b/headers/os/package/solver/SolverPackageSpecifier.h
index cfef5849a2..0f4dd89754 100644
--- a/headers/os/package/solver/SolverPackageSpecifier.h
+++ b/headers/os/package/solver/SolverPackageSpecifier.h
@@ -6,38 +6,44 @@
 #define _PACKAGE__SOLVER_PACKAGE_SPECIFIER_H_
 
 
-#include 
+#include 
 
 
 namespace BPackageKit {
 
 
-class BSolverRepository;
+class BSolverPackage;
 
 
 class BSolverPackageSpecifier {
+public:
+			enum BType {
+				B_UNSPECIFIED,
+				B_PACKAGE,
+				B_SELECT_STRING
+			};
+
 public:
 								BSolverPackageSpecifier();
-								BSolverPackageSpecifier(
-									const BPackageResolvableExpression&
-										expression);
-								BSolverPackageSpecifier(
-									BSolverRepository* repository,
-									const BPackageResolvableExpression&
-										expression);
+	explicit					BSolverPackageSpecifier(
+									BSolverPackage* package);
+	explicit					BSolverPackageSpecifier(
+									const BString& selectString);
 								BSolverPackageSpecifier(
 									const BSolverPackageSpecifier& other);
 								~BSolverPackageSpecifier();
 
-			BSolverRepository*	Repository() const;
-			const BPackageResolvableExpression& Expression() const;
+			BType				Type() const;
+			BSolverPackage*		Package() const;
+			const BString&		SelectString() const;
 
 			BSolverPackageSpecifier& operator=(
 									const BSolverPackageSpecifier& other);
 
 private:
-			BSolverRepository*	fRepository;
-			BPackageResolvableExpression fExpression;
+			BType				fType;
+			BSolverPackage*		fPackage;
+			BString				fSelectString;
 };
 
 
diff --git a/headers/os/package/solver/SolverPackageSpecifierList.h b/headers/os/package/solver/SolverPackageSpecifierList.h
index 7a2bf581e1..9a4d582c47 100644
--- a/headers/os/package/solver/SolverPackageSpecifierList.h
+++ b/headers/os/package/solver/SolverPackageSpecifierList.h
@@ -6,12 +6,13 @@
 #define _PACKAGE__SOLVER_PACKAGE_SPECIFIER_LIST_H_
 
 
-#include 
+#include 
 
 
 namespace BPackageKit {
 
 
+class BSolverPackage;
 class BSolverPackageSpecifier;
 
 
@@ -28,6 +29,8 @@ public:
 
 			bool				AppendSpecifier(
 									const BSolverPackageSpecifier& specifier);
+			bool				AppendSpecifier(BSolverPackage* package);
+			bool				AppendSpecifier(const BString& selectString);
 			void				MakeEmpty();
 
 			BSolverPackageSpecifierList& operator=(
diff --git a/src/bin/pkgman/command_resolve_dependencies.cpp b/src/bin/pkgman/command_resolve_dependencies.cpp
index 9e67ced5a8..e585f6dea4 100644
--- a/src/bin/pkgman/command_resolve_dependencies.cpp
+++ b/src/bin/pkgman/command_resolve_dependencies.cpp
@@ -182,12 +182,8 @@ command_resolve_dependencies(int argc, const char* const* argv)
 
 	// resolve
 	BSolverPackageSpecifierList packagesToInstall;
-	if (!packagesToInstall.AppendSpecifier(
-			BSolverPackageSpecifier(&dummyRepository,
-				BPackageResolvableExpression(
-					specifiedPackage->Info().Name())))) {
+	if (!packagesToInstall.AppendSpecifier(specifiedPackage))
 		DIE(B_NO_MEMORY, "failed to add specified package");
-	}
 
 	error = solver->Install(packagesToInstall);
 	if (error != B_OK)
diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index 66c3a78e24..a8efa8e37b 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -162,6 +162,7 @@ LibsolvSolver::LibsolvSolver()
 	fRepositoryInfos(10, true),
 	fInstalledRepository(NULL),
 	fSolvablePackages(),
+	fPackageSolvables(),
 	fProblems(10, true)
 {
 }
@@ -299,38 +300,61 @@ LibsolvSolver::Install(const BSolverPackageSpecifierList& packages)
 	int32 packageCount = packages.CountSpecifiers();
 	for (int32 i = 0; i < packageCount; i++) {
 		const BSolverPackageSpecifier& specifier = *packages.SpecifierAt(i);
-
-		// find matching packages
-		SolvQueue matchingPackages;
-
-		int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB
-			| SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL;
-// TODO: All flags needed/useful?
-		/*int matchFlags =*/ selection_make(fPool, &matchingPackages,
-			specifier.Expression().Name(), flags);
-// TODO: Don't just match the name, but also the version, if given!
-		if (matchingPackages.count == 0)
-			return B_NAME_NOT_FOUND;
-
-		// restrict to the matching repository
-		if (BSolverRepository* repository = specifier.Repository()) {
-			RepositoryInfo* repositoryInfo = _GetRepositoryInfo(repository);
-			if (repositoryInfo == NULL)
+		switch (specifier.Type()) {
+			case BSolverPackageSpecifier::B_UNSPECIFIED:
 				return B_BAD_VALUE;
 
-			SolvQueue repoFilter;
-			queue_push2(&repoFilter,
-				SOLVER_SOLVABLE_REPO/* | SOLVER_SETREPO | SOLVER_SETVENDOR*/,
-				repositoryInfo->SolvRepo()->repoid);
+			case BSolverPackageSpecifier::B_PACKAGE:
+			{
+				BSolverPackage* package = specifier.Package();
+				Solvable* solvable;
+				if (package == NULL
+					|| (solvable = _GetSolvable(package)) == NULL) {
+					return B_BAD_VALUE;
+				}
 
-			selection_filter(fPool, &matchingPackages, &repoFilter);
+				queue_push2(&jobs, SOLVER_SOLVABLE,
+					fPool->solvables - solvable);
+				break;
+			}
+			
+			case BSolverPackageSpecifier::B_SELECT_STRING:
+			{
+				// find matching packages
+				SolvQueue matchingPackages;
+		
+				int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB
+					| SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL;
+				/*int matchFlags =*/ selection_make(fPool, &matchingPackages,
+					specifier.SelectString().String(), flags);
+				if (matchingPackages.count == 0)
+					return B_NAME_NOT_FOUND;
+// TODO: We might want to add support for restricting to certain repositories.
+#if 0		
+				// restrict to the matching repository
+				if (BSolverRepository* repository = specifier.Repository()) {
+					RepositoryInfo* repositoryInfo
+						= _GetRepositoryInfo(repository);
+					if (repositoryInfo == NULL)
+						return B_BAD_VALUE;
 
-			if (matchingPackages.count == 0)
-				return B_NAME_NOT_FOUND;
+					SolvQueue repoFilter;
+					queue_push2(&repoFilter,
+						SOLVER_SOLVABLE_REPO
+							/* | SOLVER_SETREPO | SOLVER_SETVENDOR*/,
+						repositoryInfo->SolvRepo()->repoid);
+
+					selection_filter(fPool, &matchingPackages, &repoFilter);
+
+					if (matchingPackages.count == 0)
+						return B_NAME_NOT_FOUND;
+				}
+#endif
+
+				for (int j = 0; j < matchingPackages.count; j++)
+					queue_push(&jobs, matchingPackages.elements[j]);
+			}
 		}
-
-		for (int j = 0; j < matchingPackages.count; j++)
-			queue_push(&jobs, matchingPackages.elements[j]);
 	}
 
 	// set jobs' solver mode and solve
@@ -506,6 +530,7 @@ LibsolvSolver::_CleanupPool()
 
 	// clean up our data structures that depend on/refer to libsolv pool data
 	fSolvablePackages.clear();
+	fPackageSolvables.clear();
 
 	int32 repositoryCount = fRepositoryInfos.CountItems();
 	for (int32 i = 0; i < repositoryCount; i++)
@@ -575,6 +600,7 @@ LibsolvSolver::_AddRepositories()
 
 			try {
 				fSolvablePackages[solvable] = package;
+				fPackageSolvables[package] = solvable;
 			} catch (std::bad_alloc&) {
 				return B_NO_MEMORY;
 			}
@@ -625,6 +651,14 @@ LibsolvSolver::_GetPackage(Id solvableId) const
 }
 
 
+Solvable*
+LibsolvSolver::_GetSolvable(BSolverPackage* package) const
+{
+	PackageMap::const_iterator it = fPackageSolvables.find(package);
+	return it != fPackageSolvables.end() ? it->second : NULL;
+}
+
+
 status_t
 LibsolvSolver::_AddProblem(Id problemId)
 {
diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h
index eaecd8fdc5..48f76f83fb 100644
--- a/src/kits/package/solver/LibsolvSolver.h
+++ b/src/kits/package/solver/LibsolvSolver.h
@@ -58,6 +58,7 @@ private:
 			typedef BObjectList RepositoryInfoList;
 			typedef BObjectList ProblemList;
 			typedef std::map SolvableMap;
+			typedef std::map PackageMap;
 
 private:
 			status_t			_InitPool();
@@ -71,6 +72,7 @@ private:
 									BSolverRepository* repository) const;
 			BSolverPackage*		_GetPackage(Solvable* solvable) const;
 			BSolverPackage*		_GetPackage(Id solvableId) const;
+			Solvable*			_GetSolvable(BSolverPackage* package) const;
 
 			status_t			_AddProblem(Id problemId);
 			status_t			_AddSolution(Problem* problem, Id solutionId);
@@ -94,6 +96,7 @@ private:
 			RepositoryInfoList	fRepositoryInfos;
 			RepositoryInfo*		fInstalledRepository;
 			SolvableMap			fSolvablePackages;
+			PackageMap			fPackageSolvables;
 			ProblemList			fProblems;
 };
 
diff --git a/src/kits/package/solver/SolverPackageSpecifier.cpp b/src/kits/package/solver/SolverPackageSpecifier.cpp
index c1469d422a..1e3b61d21e 100644
--- a/src/kits/package/solver/SolverPackageSpecifier.cpp
+++ b/src/kits/package/solver/SolverPackageSpecifier.cpp
@@ -15,26 +15,27 @@ namespace BPackageKit {
 
 BSolverPackageSpecifier::BSolverPackageSpecifier()
 	:
-	fRepository(NULL),
-	fExpression()
+	fType(B_UNSPECIFIED),
+	fPackage(NULL),
+	fSelectString()
 {
 }
 
 
-BSolverPackageSpecifier::BSolverPackageSpecifier(
-	const BPackageResolvableExpression& expression)
+BSolverPackageSpecifier::BSolverPackageSpecifier(BSolverPackage* package)
 	:
-	fRepository(NULL),
-	fExpression(expression)
+	fType(B_PACKAGE),
+	fPackage(package),
+	fSelectString()
 {
 }
 
 
-BSolverPackageSpecifier::BSolverPackageSpecifier(BSolverRepository* repository,
-	const BPackageResolvableExpression& expression)
+BSolverPackageSpecifier::BSolverPackageSpecifier(const BString& selectString)
 	:
-	fRepository(repository),
-	fExpression(expression)
+	fType(B_SELECT_STRING),
+	fPackage(NULL),
+	fSelectString()
 {
 }
 
@@ -42,8 +43,9 @@ BSolverPackageSpecifier::BSolverPackageSpecifier(BSolverRepository* repository,
 BSolverPackageSpecifier::BSolverPackageSpecifier(
 	const BSolverPackageSpecifier& other)
 	:
-	fRepository(other.fRepository),
-	fExpression(other.fExpression)
+	fType(other.fType),
+	fPackage(other.fPackage),
+	fSelectString(other.fSelectString)
 {
 }
 
@@ -53,25 +55,33 @@ BSolverPackageSpecifier::~BSolverPackageSpecifier()
 }
 
 
-BSolverRepository*
-BSolverPackageSpecifier::Repository() const
+BSolverPackageSpecifier::BType
+BSolverPackageSpecifier::Type() const
 {
-	return fRepository;
+	return fType;
 }
 
 
-const BPackageResolvableExpression&
-BSolverPackageSpecifier::Expression() const
+BSolverPackage*
+BSolverPackageSpecifier::Package() const
 {
-	return fExpression;
+	return fPackage;
+}
+
+
+const BString&
+BSolverPackageSpecifier::SelectString() const
+{
+	return fSelectString;
 }
 
 
 BSolverPackageSpecifier&
 BSolverPackageSpecifier::operator=(const BSolverPackageSpecifier& other)
 {
-	fRepository = other.fRepository;
-	fExpression = other.fExpression;
+	fType = other.fType;
+	fPackage = other.fPackage;
+	fSelectString = other.fSelectString;
 	return *this;
 }
 
diff --git a/src/kits/package/solver/SolverPackageSpecifierList.cpp b/src/kits/package/solver/SolverPackageSpecifierList.cpp
index 6544179079..69a968354b 100644
--- a/src/kits/package/solver/SolverPackageSpecifierList.cpp
+++ b/src/kits/package/solver/SolverPackageSpecifierList.cpp
@@ -101,6 +101,20 @@ BSolverPackageSpecifierList::AppendSpecifier(
 }
 
 
+bool
+BSolverPackageSpecifierList::AppendSpecifier(BSolverPackage* package)
+{
+	return AppendSpecifier(BSolverPackageSpecifier(package));
+}
+
+
+bool
+BSolverPackageSpecifierList::AppendSpecifier(const BString& selectString)
+{
+	return AppendSpecifier(BSolverPackageSpecifier(selectString));
+}
+
+
 void
 BSolverPackageSpecifierList::MakeEmpty()
 {

From 38e528bbc1c368456c8b8a94d6f21081934cc4f9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 12 Apr 2013 01:48:53 +0200
Subject: [PATCH 0400/1170] pkgman: C++-ify the command handling

There's now a Command class that must be derived and registered with
a CommandManager, all simplified by a REGISTER_COMMAND macro. That gets
rid of the print_command_usage_and_exit() function copy for every
command, moves the short usage texts to the command implementations,
and avoids any repetition of the command name. When implementing a new
command only a new source file needs to be created, nothing else needs
to be touched.
---
 src/bin/pkgman/Command.cpp                    | 107 ++++++++++++++++++
 src/bin/pkgman/Command.h                      |  86 ++++++++++++++
 src/bin/pkgman/Jamfile                        |   1 +
 src/bin/pkgman/command_add_repo.cpp           |  27 +++--
 src/bin/pkgman/command_drop_repo.cpp          |  27 +++--
 src/bin/pkgman/command_list_repos.cpp         |  27 +++--
 src/bin/pkgman/command_refresh.cpp            |  26 ++---
 .../pkgman/command_resolve_dependencies.cpp   |  28 ++---
 src/bin/pkgman/command_search.cpp             |  27 +++--
 src/bin/pkgman/pkgman.cpp                     |  62 ++++------
 src/bin/pkgman/pkgman.h                       |   6 -
 11 files changed, 293 insertions(+), 131 deletions(-)
 create mode 100644 src/bin/pkgman/Command.cpp
 create mode 100644 src/bin/pkgman/Command.h

diff --git a/src/bin/pkgman/Command.cpp b/src/bin/pkgman/Command.cpp
new file mode 100644
index 0000000000..31c4b48c8f
--- /dev/null
+++ b/src/bin/pkgman/Command.cpp
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include "Command.h"
+
+#include 
+
+
+static int
+compare_commands_by_name(const Command* a, const Command* b)
+{
+	return a->Name().Compare(b->Name());
+}
+
+
+// #pragma mark - Command
+
+
+Command::Command(const BString& name, const BString& shortUsage,
+	const BString& longUsage)
+	:
+	fName(name),
+	fShortUsage(shortUsage),
+	fLongUsage(longUsage)
+{
+	fShortUsage.ReplaceAll("%command%", fName);
+	fLongUsage.ReplaceAll("%command%", fName);
+}
+
+
+Command::~Command()
+{
+}
+
+
+void
+Command::Init(const char* programName)
+{
+	fShortUsage.ReplaceAll("%program%", programName);
+	fLongUsage.ReplaceAll("%program%", programName);
+}
+
+
+void
+Command::PrintUsage(bool error) const
+{
+	fprintf(error ? stderr : stdout, "%s", fLongUsage.String());
+}
+
+
+void
+Command::PrintUsageAndExit(bool error) const
+{
+	PrintUsage(error);
+	exit(error ? 1 : 0);
+}
+
+
+// #pragma mark - CommandManager
+
+
+/*static*/ CommandManager*
+CommandManager::Default()
+{
+	static CommandManager* manager = new CommandManager;
+	return manager;
+}
+
+
+void
+CommandManager::RegisterCommand(Command* command)
+{
+	fCommands.AddItem(command);
+}
+
+
+void
+CommandManager::InitCommands(const char* programName)
+{
+	for (int32 i = 0; Command* command = fCommands.ItemAt(i); i++)
+		command->Init(programName);
+
+	fCommands.SortItems(&compare_commands_by_name);
+}
+
+
+void
+CommandManager::GetCommands(const char* prefix, CommandList& _commands)
+{
+	for (int32 i = 0; Command* command = fCommands.ItemAt(i); i++) {
+		if (command->Name().StartsWith(prefix))
+			_commands.AddItem(command);
+	}
+}
+
+
+CommandManager::CommandManager()
+	:
+	fCommands(20, true)
+{
+}
diff --git a/src/bin/pkgman/Command.h b/src/bin/pkgman/Command.h
new file mode 100644
index 0000000000..4d9c6ccc23
--- /dev/null
+++ b/src/bin/pkgman/Command.h
@@ -0,0 +1,86 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef COMMAND_H
+#define COMMAND_H
+
+
+#include 
+#include 
+
+
+class Command {
+public:
+								Command(const BString& name,
+									const BString& shortUsage,
+									const BString& longUsage);
+	virtual						~Command();
+
+			void				Init(const char* programName);
+
+			const BString&		Name() const		{ return fName; }
+			const BString&		ShortUsage() const	{ return fShortUsage; }
+			const BString&		LongUsage() const	{ return fName; }
+
+			void				PrintUsage(bool error) const;
+			void				PrintUsageAndExit(bool error) const;
+
+	virtual	int					Execute(int argc, const char* const* argv) = 0;
+
+private:
+			BString				fName;
+			BString				fShortUsage;
+			BString				fLongUsage;
+};
+
+
+typedef BObjectList CommandList;
+
+
+class CommandManager {
+public:
+	static	CommandManager*		Default();
+
+			void				RegisterCommand(Command* command);
+			void				InitCommands(const char* programName);
+
+			const CommandList&	Commands() const
+									{ return fCommands; }
+			void				GetCommands(const char* prefix,
+									CommandList& _commands);
+
+private:
+								CommandManager();
+
+private:
+			CommandList			fCommands;
+};
+
+
+template
+struct CommandRegistrar {
+	CommandRegistrar()
+	{
+		CommandManager::Default()->RegisterCommand(new CommandType);
+	}
+};
+
+
+#define DEFINE_COMMAND(className, name, shortUsage, longUsage)	\
+	struct className : Command {								\
+		className()												\
+			:													\
+			Command(name, shortUsage, longUsage)				\
+		{														\
+		}														\
+																\
+		virtual int Execute(int argc, const char* const* argv);	\
+	};															\
+	static CommandRegistrar sRegister##className;
+
+
+#endif	// COMMAND_H
diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile
index de9b873e36..c985ecfa51 100644
--- a/src/bin/pkgman/Jamfile
+++ b/src/bin/pkgman/Jamfile
@@ -3,6 +3,7 @@ SubDir HAIKU_TOP src bin pkgman ;
 UsePrivateHeaders shared support ;
 
 BinCommand pkgman :
+	Command.cpp
 	command_add_repo.cpp
 	command_drop_repo.cpp
 	command_list_repos.cpp
diff --git a/src/bin/pkgman/command_add_repo.cpp b/src/bin/pkgman/command_add_repo.cpp
index ba34b524c2..b63583bf9e 100644
--- a/src/bin/pkgman/command_add_repo.cpp
+++ b/src/bin/pkgman/command_add_repo.cpp
@@ -16,6 +16,7 @@
 #include 
 #include 
 
+#include "Command.h"
 #include "DecisionProvider.h"
 #include "JobStateListener.h"
 #include "pkgman.h"
@@ -27,23 +28,21 @@ using namespace BPackageKit;
 // TODO: internationalization!
 
 
-static const char* kCommandUsage =
-	"Usage: %s add-repo  [ ...]\n"
+static const char* const kShortUsage =
+	"  %command% \n"
+	"    Adds the repository with the given .\n";
+
+static const char* const kLongUsage =
+	"Usage: %program% %command%  [ ...]\n"
 	"Adds one or more repositories by downloading them from the given URL(s).\n"
-	"\n"
-;
+	"\n";
 
 
-static void
-print_command_usage_and_exit(bool error)
-{
-    fprintf(error ? stderr : stdout, kCommandUsage, kProgramName);
-    exit(error ? 1 : 0);
-}
+DEFINE_COMMAND(AddRepoCommand, "add-repo", kShortUsage, kLongUsage)
 
 
 int
-command_add_repo(int argc, const char* const* argv)
+AddRepoCommand::Execute(int argc, const char* const* argv)
 {
 	bool asUserRepository = false;
 
@@ -61,7 +60,7 @@ command_add_repo(int argc, const char* const* argv)
 
 		switch (c) {
 			case 'h':
-				print_command_usage_and_exit(false);
+				PrintUsageAndExit(false);
 				break;
 
 			case 'u':
@@ -69,14 +68,14 @@ command_add_repo(int argc, const char* const* argv)
 				break;
 
 			default:
-				print_command_usage_and_exit(true);
+				PrintUsageAndExit(true);
 				break;
 		}
 	}
 
 	// The remaining arguments are repo URLs, i. e. at least one more argument.
 	if (argc < optind + 1)
-		print_command_usage_and_exit(true);
+		PrintUsageAndExit(true);
 
 	const char* const* repoURLs = argv + optind;
 	int urlCount = argc - optind;
diff --git a/src/bin/pkgman/command_drop_repo.cpp b/src/bin/pkgman/command_drop_repo.cpp
index fecdd87e9a..e026757b8c 100644
--- a/src/bin/pkgman/command_drop_repo.cpp
+++ b/src/bin/pkgman/command_drop_repo.cpp
@@ -14,6 +14,7 @@
 #include 
 #include 
 
+#include "Command.h"
 #include "DecisionProvider.h"
 #include "JobStateListener.h"
 #include "pkgman.h"
@@ -25,23 +26,21 @@ using namespace BPackageKit;
 // TODO: internationalization!
 
 
-static const char* kCommandUsage =
-	"Usage: %s drop-repo \n"
+static const char* const kShortUsage =
+	"  %command% \n"
+	"    Drops the repository with the given .\n";
+
+static const char* const kLongUsage =
+	"Usage: %program% %command% \n"
 	"Drops (i.e. removes) the repository with the given name.\n"
-	"\n"
-;
+	"\n";
 
 
-static void
-print_command_usage_and_exit(bool error)
-{
-    fprintf(error ? stderr : stdout, kCommandUsage, kProgramName);
-    exit(error ? 1 : 0);
-}
+DEFINE_COMMAND(DropRepoCommand, "drop-repo", kShortUsage, kLongUsage)
 
 
 int
-command_drop_repo(int argc, const char* const* argv)
+DropRepoCommand::Execute(int argc, const char* const* argv)
 {
 	bool yesMode = false;
 
@@ -59,7 +58,7 @@ command_drop_repo(int argc, const char* const* argv)
 
 		switch (c) {
 			case 'h':
-				print_command_usage_and_exit(false);
+				PrintUsageAndExit(false);
 				break;
 
 			case 'y':
@@ -67,14 +66,14 @@ command_drop_repo(int argc, const char* const* argv)
 				break;
 
 			default:
-				print_command_usage_and_exit(true);
+				PrintUsageAndExit(true);
 				break;
 		}
 	}
 
 	// The remaining argument is a repo name, i. e. one more argument.
 	if (argc != optind + 1)
-		print_command_usage_and_exit(true);
+		PrintUsageAndExit(true);
 
 	const char* repoName = argv[optind];
 
diff --git a/src/bin/pkgman/command_list_repos.cpp b/src/bin/pkgman/command_list_repos.cpp
index 244404dca2..e0465121ac 100644
--- a/src/bin/pkgman/command_list_repos.cpp
+++ b/src/bin/pkgman/command_list_repos.cpp
@@ -21,6 +21,7 @@
 #include 
 #include 
 
+#include "Command.h"
 #include "pkgman.h"
 
 
@@ -30,24 +31,22 @@
 using namespace BPackageKit;
 
 
-static const char* kCommandUsage =
+static const char* const kShortUsage =
+	"  %command%\n"
+	"    Lists all repositories.\n";
+
+static const char* const kLongUsage =
 	"Usage:\n"
-	"    %s list-repos [options]\n"
+	"    %program% %command% [options]\n"
 	"Lists all configured package repositories.\n"
-	"\n"
-;
+	"\n";
 
 
-static void
-print_command_usage_and_exit(bool error)
-{
-    fprintf(error ? stderr : stdout, kCommandUsage, kProgramName);
-    exit(error ? 1 : 0);
-}
+DEFINE_COMMAND(ListReposCommand, "list-repos", kShortUsage, kLongUsage)
 
 
 int
-command_list_repos(int argc, const char* const* argv)
+ListReposCommand::Execute(int argc, const char* const* argv)
 {
 	bool verbose = false;
 
@@ -65,7 +64,7 @@ command_list_repos(int argc, const char* const* argv)
 
 		switch (c) {
 			case 'h':
-				print_command_usage_and_exit(false);
+				PrintUsageAndExit(false);
 				break;
 
 			case 'v':
@@ -73,14 +72,14 @@ command_list_repos(int argc, const char* const* argv)
 				break;
 
 			default:
-				print_command_usage_and_exit(true);
+				PrintUsageAndExit(true);
 				break;
 		}
 	}
 
 	// No remaining arguments.
 	if (argc != optind)
-		print_command_usage_and_exit(true);
+		PrintUsageAndExit(true);
 
 	BStringList repositoryNames(20);
 	BPackageRoster roster;
diff --git a/src/bin/pkgman/command_refresh.cpp b/src/bin/pkgman/command_refresh.cpp
index 176f5d2878..50764c99c6 100644
--- a/src/bin/pkgman/command_refresh.cpp
+++ b/src/bin/pkgman/command_refresh.cpp
@@ -15,6 +15,7 @@
 #include 
 #include 
 
+#include "Command.h"
 #include "DecisionProvider.h"
 #include "JobStateListener.h"
 #include "pkgman.h"
@@ -26,23 +27,22 @@ using namespace BPackageKit;
 // TODO: internationalization!
 
 
-static const char* kCommandUsage =
-	"Usage: %s refresh [ ...]\n"
+static const char* const kShortUsage =
+	"  %command% [ ...]\n"
+	"    Refreshes all or just the given repositories.\n";
+
+static const char* const kLongUsage =
+	"Usage: %program% %command% [ ...]\n"
 	"Refreshes all or just the given repositories.\n"
-	"\n"
-;
+	"\n";
 
 
-static void
-print_command_usage_and_exit(bool error)
-{
-    fprintf(error ? stderr : stdout, kCommandUsage, kProgramName);
-    exit(error ? 1 : 0);
-}
+DEFINE_COMMAND(RefreshCommand, "refresh", kShortUsage, kLongUsage)
+
 
 
 int
-command_refresh(int argc, const char* const* argv)
+RefreshCommand::Execute(int argc, const char* const* argv)
 {
 	while (true) {
 		static struct option sLongOptions[] = {
@@ -57,11 +57,11 @@ command_refresh(int argc, const char* const* argv)
 
 		switch (c) {
 			case 'h':
-				print_command_usage_and_exit(false);
+				PrintUsageAndExit(false);
 				break;
 
 			default:
-				print_command_usage_and_exit(true);
+				PrintUsageAndExit(true);
 				break;
 		}
 	}
diff --git a/src/bin/pkgman/command_resolve_dependencies.cpp b/src/bin/pkgman/command_resolve_dependencies.cpp
index e585f6dea4..73882332d3 100644
--- a/src/bin/pkgman/command_resolve_dependencies.cpp
+++ b/src/bin/pkgman/command_resolve_dependencies.cpp
@@ -20,6 +20,7 @@
 
 #include 
 
+#include "Command.h"
 #include "pkgman.h"
 #include "RepositoryBuilder.h"
 
@@ -30,8 +31,12 @@
 using namespace BPackageKit;
 
 
-static const char* kCommandUsage =
-	"Usage: %s resolve-dependencies   [  ] ...\n"
+static const char* const kShortUsage =
+	"  %command%   [  ] ...\n"
+	"    Resolves all packages a given package depends on.\n";
+
+static const char* const kLongUsage =
+	"Usage: %program% %command%   [  ] ...\n"
 	"Resolves and lists all packages a given package depends on. Fails, if\n"
 	"not all dependencies could be resolved.\n"
 	"\n"
@@ -46,16 +51,11 @@ static const char* kCommandUsage =
 	"  \n"
 	"    Can follow a  to specify the priority of that\n"
 	"    repository. The default priority is 0.\n"
-	"\n"
-;
+	"\n";
 
 
-static void
-print_command_usage_and_exit(bool error)
-{
-    fprintf(error ? stderr : stdout, kCommandUsage, kProgramName);
-    exit(error ? 1 : 0);
-}
+DEFINE_COMMAND(ResolveDependenciesCommand, "resolve-dependencies", kShortUsage,
+	kLongUsage)
 
 
 static void
@@ -107,7 +107,7 @@ verify_result(const BSolverResult& result, BSolverPackage* specifiedPackage)
 
 
 int
-command_resolve_dependencies(int argc, const char* const* argv)
+ResolveDependenciesCommand::Execute(int argc, const char* const* argv)
 {
 	while (true) {
 		static struct option sLongOptions[] = {
@@ -122,11 +122,11 @@ command_resolve_dependencies(int argc, const char* const* argv)
 
 		switch (c) {
 			case 'h':
-				print_command_usage_and_exit(false);
+				PrintUsageAndExit(false);
 				break;
 
 			default:
-				print_command_usage_and_exit(true);
+				PrintUsageAndExit(true);
 				break;
 		}
 	}
@@ -134,7 +134,7 @@ command_resolve_dependencies(int argc, const char* const* argv)
 	// The remaining arguments are the package (info) file and the repository
 	// directories (at least one), optionally with priorities.
 	if (argc < optind + 2)
-		print_command_usage_and_exit(true);
+		PrintUsageAndExit(true);
 
 	const char* packagePath = argv[optind++];
 	int repositoryDirectoryCount = argc - optind;
diff --git a/src/bin/pkgman/command_search.cpp b/src/bin/pkgman/command_search.cpp
index 41334e26ac..f65db3eefc 100644
--- a/src/bin/pkgman/command_search.cpp
+++ b/src/bin/pkgman/command_search.cpp
@@ -19,6 +19,7 @@
 
 #include 
 
+#include "Command.h"
 #include "pkgman.h"
 #include "RepositoryBuilder.h"
 
@@ -34,8 +35,12 @@ using namespace BPackageKit;
 typedef std::map PackagePathMap;
 
 
-static const char* kCommandUsage =
-	"Usage: %s search \n"
+static const char* const kShortUsage =
+	"  %command% \n"
+	"    Searches for packages matching .\n";
+
+static const char* const kLongUsage =
+	"Usage: %program% %command% \n"
 	"Searches for packages matching .\n"
 	"\n"
 	"Options:\n"
@@ -43,16 +48,10 @@ static const char* kCommandUsage =
 	"    Only find installed packages.\n"
 	"  -u, --uninstalled-only\n"
 	"    Only find not installed packages.\n"
-	"\n"
-;
+	"\n";
 
 
-static void
-print_command_usage_and_exit(bool error)
-{
-    fprintf(error ? stderr : stdout, kCommandUsage, kProgramName);
-    exit(error ? 1 : 0);
-}
+DEFINE_COMMAND(SearchCommand, "search", kShortUsage, kLongUsage)
 
 
 static int
@@ -68,7 +67,7 @@ get_terminal_width()
 
 
 int
-command_search(int argc, const char* const* argv)
+SearchCommand::Execute(int argc, const char* const* argv)
 {
 	bool installedOnly = false;
 	bool uninstalledOnly = false;
@@ -88,7 +87,7 @@ command_search(int argc, const char* const* argv)
 
 		switch (c) {
 			case 'h':
-				print_command_usage_and_exit(false);
+				PrintUsageAndExit(false);
 				break;
 
 			case 'i':
@@ -102,14 +101,14 @@ command_search(int argc, const char* const* argv)
 				break;
 
 			default:
-				print_command_usage_and_exit(true);
+				PrintUsageAndExit(true);
 				break;
 		}
 	}
 
 	// The remaining argument is the search string.
 	if (argc != optind + 1)
-		print_command_usage_and_exit(true);
+		PrintUsageAndExit(true);
 
 	const char* searchString = argv[optind++];
 
diff --git a/src/bin/pkgman/pkgman.cpp b/src/bin/pkgman/pkgman.cpp
index 66117001fa..eddf6fbbf3 100644
--- a/src/bin/pkgman/pkgman.cpp
+++ b/src/bin/pkgman/pkgman.cpp
@@ -11,34 +11,19 @@
 #include 
 #include 
 
+#include "Command.h"
+
 
 extern const char* __progname;
 const char* kProgramName = __progname;
 
 
-static const char* kUsage =
+static const char* const kUsage =
 	"Usage: %s  \n"
-	"Creates, inspects, or extracts a Haiku package.\n"
+	"Manages packages and package repository.\n"
 	"\n"
 	"Commands:\n"
-	"  add-repo \n"
-	"    Adds the repository with the given .\n"
-	"\n"
-	"  drop-repo \n"
-	"    Drops the repository with the given .\n"
-	"\n"
-	"  list-repos\n"
-	"    Lists all repositories.\n"
-	"\n"
-	"  refresh [ ...]\n"
-	"    Refreshes all or just the given repositories.\n"
-	"\n"
-	"  resolve-dependencies   [  ] ...\n"
-	"    Resolves all packages a given package depends on.\n"
-	"\n"
-	"  search \n"
-	"    Searches for packages matching .\n"
-	"\n"
+	"%s"
 	"Common Options:\n"
 	"  -h, --help   - Print this usage info.\n"
 ;
@@ -47,7 +32,14 @@ static const char* kUsage =
 void
 print_usage_and_exit(bool error)
 {
-    fprintf(error ? stderr : stdout, kUsage, kProgramName);
+	BString commandsUsage;
+	const CommandList& commands = CommandManager::Default()->Commands();
+	for (int32 i = 0; Command* command = commands.ItemAt(i); i++)
+		commandsUsage << command->ShortUsage() << '\n';
+
+    fprintf(error ? stderr : stdout, kUsage, kProgramName,
+    	commandsUsage.String());
+
     exit(error ? 1 : 0);
 }
 
@@ -55,33 +47,19 @@ print_usage_and_exit(bool error)
 int
 main(int argc, const char* const* argv)
 {
+	CommandManager::Default()->InitCommands(kProgramName);
+
 	if (argc < 2)
 		print_usage_and_exit(true);
 
 	const char* command = argv[1];
-	if (strncmp(command, "add-r", 5) == 0)
-		return command_add_repo(argc - 1, argv + 1);
-
-	if (strncmp(command, "drop-r", 6) == 0)
-		return command_drop_repo(argc - 1, argv + 1);
-
-	if (strncmp(command, "list-r", 6) == 0)
-		return command_list_repos(argc - 1, argv + 1);
-
-	if (strncmp(command, "refr", 4) == 0)
-		return command_refresh(argc - 1, argv + 1);
-
-	if (strcmp(command, "resolve-dependencies") == 0)
-		return command_resolve_dependencies(argc - 1, argv + 1);
-
-	if (strcmp(command, "search") == 0)
-		return command_search(argc - 1, argv + 1);
-
 	if (strcmp(command, "help") == 0)
 		print_usage_and_exit(false);
-	else
+
+	CommandList commands;
+	CommandManager::Default()->GetCommands(command, commands);
+	if (commands.CountItems() != 1)
 		print_usage_and_exit(true);
 
-	// never gets here
-	return 0;
+	return commands.ItemAt(0)->Execute(argc - 1, argv + 1);
 }
diff --git a/src/bin/pkgman/pkgman.h b/src/bin/pkgman/pkgman.h
index c2a2fe9d6e..eb308853c0 100644
--- a/src/bin/pkgman/pkgman.h
+++ b/src/bin/pkgman/pkgman.h
@@ -34,12 +34,6 @@ do {																\
 
 
 void	print_usage_and_exit(bool error);
-int		command_add_repo(int argc, const char* const* argv);
-int		command_drop_repo(int argc, const char* const* argv);
-int		command_list_repos(int argc, const char* const* argv);
-int		command_refresh(int argc, const char* const* argv);
-int		command_resolve_dependencies(int argc, const char* const* argv);  
-int		command_search(int argc, const char* const* argv);  
 
 
 #endif	// PKGMAN_H

From 115eae73712eb0cc26ffba34235383d3c2a1a080 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 12 Apr 2013 12:27:32 +0200
Subject: [PATCH 0401/1170] LibsolvSolver::Install(): Fix broken B_PACKAGE case

---
 src/kits/package/solver/LibsolvSolver.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index a8efa8e37b..885f76e82c 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -314,7 +314,7 @@ LibsolvSolver::Install(const BSolverPackageSpecifierList& packages)
 				}
 
 				queue_push2(&jobs, SOLVER_SOLVABLE,
-					fPool->solvables - solvable);
+					solvable - fPool->solvables);
 				break;
 			}
 			

From 334a5a566c49d247cd8b4491cd3c94748f7df18b Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 12 Apr 2013 13:42:27 +0200
Subject: [PATCH 0402/1170] BSolverRepository: Change priority from uint8 to
 int32

This allows us to specifies priorities below and above the user
definable range.
---
 headers/os/package/solver/SolverRepository.h | 7 ++++---
 src/kits/package/solver/LibsolvSolver.cpp    | 2 +-
 src/kits/package/solver/SolverRepository.cpp | 4 ++--
 3 files changed, 7 insertions(+), 6 deletions(-)

diff --git a/headers/os/package/solver/SolverRepository.h b/headers/os/package/solver/SolverRepository.h
index 1cd7fa2120..2d470d131b 100644
--- a/headers/os/package/solver/SolverRepository.h
+++ b/headers/os/package/solver/SolverRepository.h
@@ -51,8 +51,9 @@ public:
 
 			BString				Name() const;
 
-			uint8				Priority() const;
-			void				SetPriority(uint8 priority);
+			int32				Priority() const;
+			void				SetPriority(int32 priority);
+									// negative priority is fine
 
 			bool				IsEmpty() const;
 			int32				CountPackages() const;
@@ -70,7 +71,7 @@ private:
 
 private:
 			BString				fName;
-			uint8				fPriority;
+			int32				fPriority;
 			bool				fIsInstalled;
 			PackageList			fPackages;
 			uint64				fChangeCount;
diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index 885f76e82c..d6a0935856 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -588,7 +588,7 @@ LibsolvSolver::_AddRepositories()
 		Repo* repo = repo_create(fPool, repository->Name());
 		repositoryInfo->SetSolvRepo(repo);
 
-		repo->priority = 256 - repository->Priority();
+		repo->priority = -1 - repository->Priority();
 		repo->appdata = (void*)repositoryInfo;
 
 		int32 packageCount = repository->CountPackages();
diff --git a/src/kits/package/solver/SolverRepository.cpp b/src/kits/package/solver/SolverRepository.cpp
index 1e710178f4..b968dc3217 100644
--- a/src/kits/package/solver/SolverRepository.cpp
+++ b/src/kits/package/solver/SolverRepository.cpp
@@ -209,7 +209,7 @@ BSolverRepository::Name() const
 }
 
 
-uint8
+int32
 BSolverRepository::Priority() const
 {
 	return fPriority;
@@ -217,7 +217,7 @@ BSolverRepository::Priority() const
 
 
 void
-BSolverRepository::SetPriority(uint8 priority)
+BSolverRepository::SetPriority(int32 priority)
 {
 	fPriority = priority;
 	fChangeCount++;

From 71293f8b03be4d9d14d32a134ac5177e62187728 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 12 Apr 2013 14:21:08 +0200
Subject: [PATCH 0403/1170] BSolverPackageSpecifier: Fix string constructor

---
 src/kits/package/solver/SolverPackageSpecifier.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/kits/package/solver/SolverPackageSpecifier.cpp b/src/kits/package/solver/SolverPackageSpecifier.cpp
index 1e3b61d21e..686e7532dd 100644
--- a/src/kits/package/solver/SolverPackageSpecifier.cpp
+++ b/src/kits/package/solver/SolverPackageSpecifier.cpp
@@ -35,7 +35,7 @@ BSolverPackageSpecifier::BSolverPackageSpecifier(const BString& selectString)
 	:
 	fType(B_SELECT_STRING),
 	fPackage(NULL),
-	fSelectString()
+	fSelectString(selectString)
 {
 }
 

From 0d8ed3f2a8f240750c15e9dfec09fb2e20b7160a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 12 Apr 2013 14:21:54 +0200
Subject: [PATCH 0404/1170] BSolver::Install(): Add optional unmatched
 specifier return param

---
 headers/os/package/solver/Solver.h        |  5 ++++-
 src/kits/package/solver/LibsolvSolver.cpp | 11 +++++++++--
 src/kits/package/solver/LibsolvSolver.h   |  4 +++-
 3 files changed, 16 insertions(+), 4 deletions(-)

diff --git a/headers/os/package/solver/Solver.h b/headers/os/package/solver/Solver.h
index c283b3e993..90c0045281 100644
--- a/headers/os/package/solver/Solver.h
+++ b/headers/os/package/solver/Solver.h
@@ -14,6 +14,7 @@ namespace BPackageKit {
 
 
 class BSolverPackage;
+class BSolverPackageSpecifier;
 class BSolverPackageSpecifierList;
 class BSolverProblem;
 class BSolverRepository;
@@ -47,7 +48,9 @@ public:
 
 	virtual	status_t			Install(
 									const BSolverPackageSpecifierList&
-										packages) = 0;
+										packages,
+									const BSolverPackageSpecifier** _unmatched
+										= NULL) = 0;
 	virtual	status_t			VerifyInstallation() = 0;
 
 			bool				HasProblems() const
diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index d6a0935856..460befd544 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -284,8 +284,12 @@ LibsolvSolver::FindPackages(const char* searchString, uint32 flags,
 
 
 status_t
-LibsolvSolver::Install(const BSolverPackageSpecifierList& packages)
+LibsolvSolver::Install(const BSolverPackageSpecifierList& packages,
+	const BSolverPackageSpecifier** _unmatched)
 {
+	if (_unmatched != NULL)
+		*_unmatched = NULL;
+
 	if (packages.IsEmpty())
 		return B_BAD_VALUE;
 
@@ -327,8 +331,11 @@ LibsolvSolver::Install(const BSolverPackageSpecifierList& packages)
 					| SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL;
 				/*int matchFlags =*/ selection_make(fPool, &matchingPackages,
 					specifier.SelectString().String(), flags);
-				if (matchingPackages.count == 0)
+				if (matchingPackages.count == 0) {
+					if (_unmatched != NULL)
+						*_unmatched = &specifier;
 					return B_NAME_NOT_FOUND;
+				}
 // TODO: We might want to add support for restricting to certain repositories.
 #if 0		
 				// restrict to the matching repository
diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h
index 48f76f83fb..09c6dbacfc 100644
--- a/src/kits/package/solver/LibsolvSolver.h
+++ b/src/kits/package/solver/LibsolvSolver.h
@@ -40,7 +40,9 @@ public:
 
 	virtual	status_t			Install(
 									const BSolverPackageSpecifierList&
-										packages);
+										packages,
+									const BSolverPackageSpecifier** _unmatched
+										= NULL);
 	virtual	status_t			VerifyInstallation();
 
 	virtual	int32				CountProblems() const;

From 0d50fa87ec909d6d81190d187596163264c59d94 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 12 Apr 2013 15:29:50 +0200
Subject: [PATCH 0405/1170] pkgman: Add beginnings of the "install" command

So far it only solves the dependencies and prints the result. No
problem handling, no actual installation.
---
 src/bin/pkgman/Jamfile             |   1 +
 src/bin/pkgman/command_install.cpp | 226 +++++++++++++++++++++++++++++
 2 files changed, 227 insertions(+)
 create mode 100644 src/bin/pkgman/command_install.cpp

diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile
index c985ecfa51..cb8328a9f2 100644
--- a/src/bin/pkgman/Jamfile
+++ b/src/bin/pkgman/Jamfile
@@ -6,6 +6,7 @@ BinCommand pkgman :
 	Command.cpp
 	command_add_repo.cpp
 	command_drop_repo.cpp
+	command_install.cpp
 	command_list_repos.cpp
 	command_refresh.cpp
 	command_resolve_dependencies.cpp
diff --git a/src/bin/pkgman/command_install.cpp b/src/bin/pkgman/command_install.cpp
new file mode 100644
index 0000000000..c62a6ffd1e
--- /dev/null
+++ b/src/bin/pkgman/command_install.cpp
@@ -0,0 +1,226 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+#include 
+#include 
+#include 
+//#include 
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+
+#include "Command.h"
+#include "pkgman.h"
+#include "RepositoryBuilder.h"
+
+
+// TODO: internationalization!
+
+
+using namespace BPackageKit;
+
+
+static const char* const kShortUsage =
+	"  %command%  ...\n"
+	"    Installs one or more packages.\n";
+
+static const char* const kLongUsage =
+	"Usage: %program% %command%  ...\n"
+	"Installs the specified packages.\n"
+	"\n"
+	"Options:\n"
+	"  -H, --home\n"
+	"    Install the packages in the user's home directory. Default is to.\n"
+	"    install in the common directory.\n"
+	"\n";
+
+
+DEFINE_COMMAND(InstallCommand, "install", kShortUsage, kLongUsage)
+
+
+int
+InstallCommand::Execute(int argc, const char* const* argv)
+{
+	bool installInHome = false;
+
+	while (true) {
+		static struct option sLongOptions[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ "home", no_argument, 0, 'H' },
+			{ 0, 0, 0, 0 }
+		};
+
+		opterr = 0; // don't print errors
+		int c = getopt_long(argc, (char**)argv, "hu", sLongOptions, NULL);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'h':
+				PrintUsageAndExit(false);
+				break;
+
+			case 'H':
+				installInHome = true;
+				break;
+
+			default:
+				PrintUsageAndExit(true);
+				break;
+		}
+	}
+
+	// The remaining arguments are the packages to be installed.
+	if (argc < optind + 1)
+		PrintUsageAndExit(true);
+
+	int packageCount = argc - optind;
+	const char* const* packages = argv + optind;
+
+// TODO: Refresh repositories.
+
+	// create the solver
+	BSolver* solver;
+	status_t error = BSolver::Create(solver);
+	if (error != B_OK)
+		DIE(error, "failed to create solver");
+
+	// add repositories
+
+	// We add only the repository of our actual installation location as the
+	// "installed" repository. The repositories for the more general
+	// installation locations are added as regular repositories, but with better
+	// priorities than the actual (remote) repositories. This prevents the solver
+	// from showing conflicts when a package in a more specific installation
+	// location overrides a package in a more general one. Instead any
+	// requirement that is already installed in a more general installation
+	// location will turn up as to be installed as well. But we can easily
+	// filter those out.
+	BSolverRepository systemRepository;
+	RepositoryBuilder(systemRepository, "system")
+		.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, "system")
+		.AddToSolver(solver, false);
+	systemRepository.SetPriority(-1);
+
+	BSolverRepository commonRepository;
+	RepositoryBuilder(commonRepository, "common")
+		.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common")
+		.AddToSolver(solver, !installInHome);
+
+	BSolverRepository homeRepository;
+	if (installInHome) {
+		commonRepository.SetPriority(-2);
+		RepositoryBuilder(homeRepository, "home")
+			.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_HOME, "home")
+			.AddToSolver(solver, true);
+	}
+
+	// other repositories
+	BObjectList otherRepositories(10, true);
+	BPackageRoster roster;
+	BStringList repositoryNames;
+	error = roster.GetRepositoryNames(repositoryNames);
+	if (error != B_OK)
+		WARN(error, "failed to get repository names");
+
+	int32 repositoryNameCount = repositoryNames.CountStrings();
+	for (int32 i = 0; i < repositoryNameCount; i++) {
+		const BString& name = repositoryNames.StringAt(i);
+		BRepositoryConfig config;
+		error = roster.GetRepositoryConfig(name, &config);
+		if (error != B_OK) {
+			WARN(error, "failed to get config for repository \"%s\". Skipping.",
+				name.String());
+			continue;
+		}
+
+		BSolverRepository* repository = new(std::nothrow) BSolverRepository;
+		if (repository == NULL || !otherRepositories.AddItem(repository))
+			DIE(B_NO_MEMORY, "out of memory");
+
+		RepositoryBuilder(*repository, config)
+			.AddToSolver(solver, false);
+	}
+
+	// solve
+	BSolverPackageSpecifierList packagesToInstall;
+	for (int i = 0; i < packageCount; i++) {
+		if (!packagesToInstall.AppendSpecifier(packages[i]))
+			DIE(B_NO_MEMORY, "failed to add specified package");
+	}
+
+	const BSolverPackageSpecifier* unmatchedSpecifier;
+	error = solver->Install(packagesToInstall, &unmatchedSpecifier);
+	if (error != B_OK) {
+		if (unmatchedSpecifier != NULL) {
+			DIE(error, "failed to find a match for \"%s\"",
+				unmatchedSpecifier->SelectString().String());
+		} else
+			DIE(error, "failed to compute packages to install");
+	}
+
+	// deal with problems
+	while (solver->HasProblems()) {
+		printf("Encountered problems:\n");
+
+		int32 problemCount = solver->CountProblems();
+		for (int32 i = 0; i < problemCount; i++) {
+			BSolverProblem* problem = solver->ProblemAt(i);
+			printf("  %" B_PRId32 ": %s\n", i + 1,
+				problem->ToString().String());
+
+			int32 solutionCount = problem->CountSolutions();
+			for (int32 k = 0; k < solutionCount; k++) {
+				const BSolverProblemSolution* solution = problem->SolutionAt(k);
+				printf("    solution %" B_PRId32 ":\n", k + 1);
+				int32 elementCount = solution->CountElements();
+				for (int32 l = 0; l < elementCount; l++) {
+					const BSolverProblemSolutionElement* element
+						= solution->ElementAt(l);
+					printf("      - %s\n", element->ToString().String());
+				}
+			}
+		}
+// TODO: Allow the user to select solutions!
+exit(1);
+	}
+
+	// print result
+	BSolverResult result;
+	error = solver->GetResult(result);
+	if (error != B_OK)
+		DIE(error, "failed to compute packages to install");
+
+	printf("transaction:\n");
+	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
+			i++) {
+		BSolverPackage* package = element->Package();
+		switch (element->Type()) {
+			case BSolverResultElement::B_TYPE_INSTALL:
+				printf("  install package %s from repository %s\n",
+					package->VersionedName().String(),
+					package->Repository()->Name().String());
+				break;
+			case BSolverResultElement::B_TYPE_UNINSTALL:
+				printf("  uninstall package %s\n",
+					package->VersionedName().String());
+				break;
+		}
+	}
+
+	return 0;
+}

From 82ce8682f25a392be5c06a5a6cf534f5bb962c4a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 13 Apr 2013 02:04:00 +0200
Subject: [PATCH 0406/1170] Add missing build header Referenceable.h

---
 headers/build/private/shared/Referenceable.h | 1 +
 1 file changed, 1 insertion(+)
 create mode 100644 headers/build/private/shared/Referenceable.h

diff --git a/headers/build/private/shared/Referenceable.h b/headers/build/private/shared/Referenceable.h
new file mode 100644
index 0000000000..a374cceba9
--- /dev/null
+++ b/headers/build/private/shared/Referenceable.h
@@ -0,0 +1 @@
+#include <../private/shared/Referenceable.h>

From 711a2a6eea557acfd3b0737ec428334ef40155b9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 13 Apr 2013 02:08:43 +0200
Subject: [PATCH 0407/1170] BPackageInfoSet: Add copy constructor, assignment
 operator

* Implement copy-on-write support.
* Add copy constructor and assignment operator.
* Remove Init(). Initialize lazily instead. Since AddInfo() can fail
  and we check initialization anyway, there's no point in having an
  explicit Init(). Given that there was only one invocation of Init()
  in the package kit and its users, it was very likely missing in some
  places.
* Fix a few places where we ignored that the PackageMap actually
  contains lists of PackageInfo objects.
---
 headers/os/package/PackageInfoSet.h  |  12 +-
 src/kits/package/PackageInfoSet.cpp  | 188 ++++++++++++++++++++-------
 src/kits/package/RepositoryCache.cpp |   6 +-
 3 files changed, 148 insertions(+), 58 deletions(-)

diff --git a/headers/os/package/PackageInfoSet.h b/headers/os/package/PackageInfoSet.h
index f2545ff73e..35fbbdc2be 100644
--- a/headers/os/package/PackageInfoSet.h
+++ b/headers/os/package/PackageInfoSet.h
@@ -21,16 +21,20 @@ public:
 
 public:
 								BPackageInfoSet();
+								BPackageInfoSet(const BPackageInfoSet& other);
 	virtual						~BPackageInfoSet();
 
-			status_t			Init();
-
 			status_t			AddInfo(const BPackageInfo& info);
 			void				MakeEmpty();
 
 			uint32				CountInfos() const;
 			Iterator			GetIterator() const;
 
+			BPackageInfoSet&	operator=(const BPackageInfoSet& other);
+
+private:
+			bool				_CopyOnWrite();
+
 private:
 			struct PackageInfo;
 			struct PackageInfoHashDefinition;
@@ -46,7 +50,7 @@ private:
 class BPackageInfoSet::Iterator {
 public:
 								Iterator();
-								Iterator(const BPackageInfoSet* set);
+								Iterator(const PackageMap* map);
 
 			bool				HasNext() const;
 			const BPackageInfo*	Next();
@@ -55,7 +59,7 @@ private:
 			friend class BRepositoryCache;
 
 private:
-			const BPackageInfoSet* fSet;
+			const PackageMap*	fMap;
 			PackageInfo*		fNextInfo;
 };
 
diff --git a/src/kits/package/PackageInfoSet.cpp b/src/kits/package/PackageInfoSet.cpp
index 315cedcd92..997e1dced5 100644
--- a/src/kits/package/PackageInfoSet.cpp
+++ b/src/kits/package/PackageInfoSet.cpp
@@ -12,6 +12,10 @@
 
 #include 
 
+#include 
+
+#include 
+
 #include 
 
 #include 
@@ -33,6 +37,16 @@ struct BPackageInfoSet::PackageInfo : public BPackageInfo {
 		listNext(NULL)
 	{
 	}
+
+	void DeleteList()
+	{
+		PackageInfo* info = this;
+		while (info != NULL) {
+			PackageInfo* next = info->listNext;
+			delete info;
+			info = next;
+		}
+	}
 };
 
 
@@ -68,8 +82,8 @@ struct BPackageInfoSet::PackageInfoHashDefinition {
 // #pragma mark - PackageMap
 
 
-struct BPackageInfoSet::PackageMap
-	: public BOpenHashTable {
+struct BPackageInfoSet::PackageMap : public BReferenceable,
+	public BOpenHashTable {
 
 	PackageMap()
 		:
@@ -79,12 +93,34 @@ struct BPackageInfoSet::PackageMap
 
 	~PackageMap()
 	{
-		PackageInfo* info = Clear(true);
-		while (info != NULL) {
-			PackageInfo* next = info->hashNext;
-			delete info;
-			info = next;
+		DeleteAllPackageInfos();
+	}
+
+	static PackageMap* Create()
+	{
+		PackageMap* map = new(std::nothrow) PackageMap;
+		if (map == NULL || map->Init() != B_OK) {
+			delete map;
+			return NULL;
 		}
+
+		return map;
+	}
+
+	PackageMap* Clone() const
+	{
+		PackageMap* newMap = Create();
+		if (newMap == NULL)
+			return NULL;
+		ObjectDeleter newMapDeleter(newMap);
+
+		for (BPackageInfoSet::Iterator it(this); it.HasNext();) {
+			const BPackageInfo* info = it.Next();
+			if (newMap->AddNewPackageInfo(*info) != B_OK)
+				return NULL;
+		}
+
+		return newMapDeleter.Detach();
 	}
 
 	void AddPackageInfo(PackageInfo* info)
@@ -98,6 +134,32 @@ struct BPackageInfoSet::PackageMap
 		fCount++;
 	}
 
+	status_t AddNewPackageInfo(const BPackageInfo& oldInfo)
+	{
+		PackageInfo* info = new(std::nothrow) PackageInfo(oldInfo);
+		if (info == NULL)
+			return B_NO_MEMORY;
+		ObjectDeleter infoDeleter(info);
+	
+		status_t error = info->InitCheck();
+		if (error != B_OK)
+			return error;
+	
+		AddPackageInfo(infoDeleter.Detach());
+	
+		return B_OK;
+	}
+
+	void DeleteAllPackageInfos()
+	{
+		PackageInfo* info = Clear(true);
+		while (info != NULL) {
+			PackageInfo* next = info->hashNext;
+			info->DeleteList();
+			info = next;
+		}
+	}
+
 	uint32 CountPackageInfos() const
 	{
 		return fCount;
@@ -113,19 +175,20 @@ private:
 
 BPackageInfoSet::Iterator::Iterator()
 	:
-	fSet(NULL),
+	fMap(NULL),
 	fNextInfo(NULL)
 {
 }
 
 
-BPackageInfoSet::Iterator::Iterator(const BPackageInfoSet* set)
+BPackageInfoSet::Iterator::Iterator(const PackageMap* map)
 	:
-	fSet(set),
-	fNextInfo(fSet->fPackageMap->GetIterator().Next())
+	fMap(map),
+	fNextInfo(map->GetIterator().Next())
 {
 }
 
+
 bool
 BPackageInfoSet::Iterator::HasNext() const
 {
@@ -145,7 +208,7 @@ BPackageInfoSet::Iterator::Next()
 		} else {
 			// get next in hash table
 			PackageMap::Iterator iterator
-				= fSet->fPackageMap->GetIterator(fNextInfo->Name());
+				= fMap->GetIterator(fNextInfo->Name());
 			iterator.Next();
 			fNextInfo = iterator.Next();
 		}
@@ -160,64 +223,52 @@ BPackageInfoSet::Iterator::Next()
 
 BPackageInfoSet::BPackageInfoSet()
 	:
-	fPackageMap(new(std::nothrow) PackageMap)
+	fPackageMap(NULL)
 {
 }
 
 
 BPackageInfoSet::~BPackageInfoSet()
 {
-	MakeEmpty();
-	delete fPackageMap;
+	if (fPackageMap != NULL)
+		fPackageMap->ReleaseReference();
+}
+
+
+BPackageInfoSet::BPackageInfoSet(const BPackageInfoSet& other)
+	:
+	fPackageMap(other.fPackageMap)
+{
+	if (fPackageMap != NULL)
+		fPackageMap->AcquireReference();
 }
 
 
 status_t
-BPackageInfoSet::Init()
+BPackageInfoSet::AddInfo(const BPackageInfo& info)
 {
-	return fPackageMap->Init();
-}
-
-
-status_t
-BPackageInfoSet::AddInfo(const BPackageInfo& _info)
-{
-	if (fPackageMap == NULL)
-		return B_NO_INIT;
-
-	PackageInfo* info = new(std::nothrow) PackageInfo(_info);
-	if (info == NULL)
+	if (!_CopyOnWrite())
 		return B_NO_MEMORY;
 
-	status_t error = info->InitCheck();
-	if (error != B_OK) {
-		delete info;
-		return error;
-	}
-
-	if (PackageInfo* oldInfo = fPackageMap->Lookup(info->Name())) {
-		// TODO: Check duplicates?
-		info->listNext = oldInfo->listNext;
-		oldInfo->listNext = info;
-	} else
-		fPackageMap->Insert(info);
-
-	return B_OK;
+	return fPackageMap->AddNewPackageInfo(info);
 }
 
 
 void
 BPackageInfoSet::MakeEmpty()
 {
-	if (fPackageMap == NULL)
+	if (fPackageMap == NULL || fPackageMap->CountPackageInfos() == 0)
 		return;
 
-	PackageInfo* info = fPackageMap->Clear(true);
-	while (info != NULL) {
-		PackageInfo* next = info->hashNext;
-		delete info;
-		info = next;
+	// If our map is shared, just set it to NULL.
+	if (fPackageMap->CountReferences() != 1) {
+		fPackageMap->ReleaseReference();
+		fPackageMap = NULL;
+		return;
 	}
+
+	// Our map is not shared -- make it empty.
+	fPackageMap->DeleteAllPackageInfos();
 }
 
 
@@ -234,7 +285,46 @@ BPackageInfoSet::CountInfos() const
 BPackageInfoSet::Iterator
 BPackageInfoSet::GetIterator() const
 {
-	return Iterator(this);
+	return Iterator(fPackageMap);
+}
+
+
+BPackageInfoSet&
+BPackageInfoSet::operator=(const BPackageInfoSet& other)
+{
+	if (other.fPackageMap == fPackageMap)
+		return *this;
+
+	if (fPackageMap != NULL)
+		fPackageMap->ReleaseReference();
+
+	fPackageMap = other.fPackageMap;
+
+	if (fPackageMap != NULL)
+		fPackageMap->AcquireReference();
+
+	return *this;
+}
+
+
+bool
+BPackageInfoSet::_CopyOnWrite()
+{
+	if (fPackageMap == NULL) {
+		fPackageMap = PackageMap::Create();
+		return fPackageMap != NULL;
+	}
+
+	if (fPackageMap->CountReferences() == 1)
+		return true;
+
+	PackageMap* newMap = fPackageMap->Clone();
+	if (newMap == NULL)
+		return false;
+
+	fPackageMap->ReleaseReference();
+	fPackageMap = newMap;
+	return true;
 }
 
 
diff --git a/src/kits/package/RepositoryCache.cpp b/src/kits/package/RepositoryCache.cpp
index d6f5b2759b..c62c204997 100644
--- a/src/kits/package/RepositoryCache.cpp
+++ b/src/kits/package/RepositoryCache.cpp
@@ -243,15 +243,11 @@ BRepositoryCache::SetTo(const BEntry& entry)
 	fPackages.MakeEmpty();
 	fEntry.Unset();
 
-	// init package info set
-	status_t result = fPackages.Init();
-	if (result != B_OK)
-		return result;
-
 	// get cache file path
 	fEntry = entry;
 
 	BPath repositoryCachePath;
+	status_t result;
 	if ((result = entry.GetPath(&repositoryCachePath)) != B_OK)
 		return result;
 

From bbb2dc237a6a82b22dc0a93542078e39b2046d17 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 13 Apr 2013 14:39:35 +0200
Subject: [PATCH 0408/1170] Add BReferenceable to libbe_build

Unbreaks the build on non-Haiku build platforms
---
 src/build/libbe/support/Jamfile | 1 +
 1 file changed, 1 insertion(+)

diff --git a/src/build/libbe/support/Jamfile b/src/build/libbe/support/Jamfile
index afa735e866..495ea54f37 100644
--- a/src/build/libbe/support/Jamfile
+++ b/src/build/libbe/support/Jamfile
@@ -15,6 +15,7 @@ BuildPlatformMergeObjectPIC support_kit.o :
 	List.cpp
 	Locker.cpp
 	PointerList.cpp
+	Referenceable.cpp
 	String.cpp
 	StringList.cpp
 ;

From 8a4ebe2c469333d0cabc9a9a6d353d4b42f61d6c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 14 Apr 2013 14:09:11 +0200
Subject: [PATCH 0409/1170] Make BPackageInfo archivable

---
 headers/os/package/PackageInfo.h |  55 +++-
 src/kits/package/PackageInfo.cpp | 487 ++++++++++++++++++++++++++++++-
 2 files changed, 531 insertions(+), 11 deletions(-)

diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h
index 4d9e3f5d98..1a34a388f5 100644
--- a/headers/os/package/PackageInfo.h
+++ b/headers/os/package/PackageInfo.h
@@ -6,6 +6,7 @@
 #define _PACKAGE__PACKAGE_INFO_H_
 
 
+#include 
 #include 
 #include 
 #include 
@@ -31,7 +32,7 @@ namespace BPackageKit {
  * these elements have been parsed from a ".PackageInfo" file.
  * Alternatively, they can be read from an existing package file.
  */
-class BPackageInfo {
+class BPackageInfo : public BArchivable {
 public:
 			struct ParseErrorListener {
 				virtual	~ParseErrorListener();
@@ -40,7 +41,9 @@ public:
 
 public:
 								BPackageInfo();
-								~BPackageInfo();
+								BPackageInfo(BMessage* archive,
+									status_t* _error = NULL);
+	virtual						~BPackageInfo();
 
 			status_t			ReadFromConfigFile(
 									const BEntry& packageInfoEntry,
@@ -137,6 +140,10 @@ public:
 
 			void				Clear();
 
+	virtual	status_t 			Archive(BMessage* archive,
+									bool deep = true) const;
+	static 	BArchivable*		Instantiate(BMessage* archive);
+
 			status_t			GetConfigString(BString& _string) const;
 			BString				ToString() const;
 
@@ -157,6 +164,36 @@ private:
 			class Parser;
 			friend class Parser;
 			struct StringBuilder;
+			struct FieldName;
+
+			typedef BObjectList ResolvableList;
+			typedef BObjectList
+				ResolvableExpressionList;
+
+private:
+	static	status_t			_AddVersion(BMessage* archive,
+									const char* field,
+									const BPackageVersion& version);
+	static	status_t			_AddStringList(BMessage* archive,
+									const char* field, const BStringList& list);
+	static	status_t			_AddResolvables(BMessage* archive,
+									const char* field,
+									const ResolvableList& resolvables);
+	static	status_t			_AddResolvableExpressions(BMessage* archive,
+									const char* field,
+									const ResolvableExpressionList&
+										expressions);
+	static	status_t			_ExtractVersion(BMessage* archive,
+									const char* field, int32 index,
+									BPackageVersion& _version);
+	static	status_t			_ExtractStringList(BMessage* archive,
+									const char* field, BStringList& _list);
+	static	status_t			_ExtractResolvables(BMessage* archive,
+									const char* field,
+									ResolvableList& _resolvables);
+	static	status_t			_ExtractResolvableExpressions(BMessage* archive,
+									const char* field,
+									ResolvableExpressionList& _expressions);
 
 private:
 			BString				fName;
@@ -167,7 +204,7 @@ private:
 
 			uint32				fFlags;
 
-			BPackageArchitecture	fArchitecture;
+			BPackageArchitecture fArchitecture;
 
 			BPackageVersion		fVersion;
 
@@ -176,14 +213,12 @@ private:
 			BStringList			fURLList;
 			BStringList			fSourceURLList;
 
-			BObjectList	fProvidesList;
+			ResolvableList		fProvidesList;
 
-			BObjectList	fRequiresList;
-			BObjectList	fSupplementsList;
-
-			BObjectList	fConflictsList;
-
-			BObjectList	fFreshensList;
+			ResolvableExpressionList fRequiresList;
+			ResolvableExpressionList fSupplementsList;
+			ResolvableExpressionList fConflictsList;
+			ResolvableExpressionList fFreshensList;
 
 			BStringList			fReplacesList;
 
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 4a1ae56026..6ff7cf9f79 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -1098,12 +1098,58 @@ private:
 };
 
 
-// #pragma mark - BPackageInfo
+// #pragma mark - FieldName
 
 
+struct BPackageInfo::FieldName {
+	FieldName(const char* prefix, const char* suffix)
+	{
+		size_t prefixLength = strlen(prefix);
+		size_t suffixLength = strlen(suffix);
+		if (prefixLength + suffixLength >= sizeof(fFieldName)) {
+			fFieldName[0] = '\0';
+			return;
+		}
+
+		memcpy(fFieldName, prefix, prefixLength);
+		memcpy(fFieldName + prefixLength, suffix, suffixLength);
+		fFieldName[prefixLength + suffixLength] = '\0';
+	}
+
+	bool ReplaceSuffix(size_t prefixLength, const char* suffix)
+	{
+		size_t suffixLength = strlen(suffix);
+		if (prefixLength + suffixLength >= sizeof(fFieldName)) {
+			fFieldName[0] = '\0';
+			return false;
+		}
+
+		memcpy(fFieldName + prefixLength, suffix, suffixLength);
+		fFieldName[prefixLength + suffixLength] = '\0';
+		return true;
+	}
+
+	bool IsValid() const
+	{
+		return fFieldName[0] != '\0';
+	}
+
+	operator const char*()
+	{
+		return fFieldName;
+	}
+
+private:
+	char	fFieldName[64];
+};
+
+
+// #pragma mark - BPackageInfo
+
 
 BPackageInfo::BPackageInfo()
 	:
+	BArchivable(),
 	fFlags(0),
 	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
 	fCopyrightList(5),
@@ -1120,6 +1166,65 @@ BPackageInfo::BPackageInfo()
 }
 
 
+BPackageInfo::BPackageInfo(BMessage* archive, status_t* _error)
+	:
+	BArchivable(archive),
+	fFlags(0),
+	fArchitecture(B_PACKAGE_ARCHITECTURE_ENUM_COUNT),
+	fCopyrightList(5),
+	fLicenseList(5),
+	fURLList(5),
+	fSourceURLList(5),
+	fProvidesList(20, true),
+	fRequiresList(20, true),
+	fSupplementsList(20, true),
+	fConflictsList(5, true),
+	fFreshensList(5, true),
+	fReplacesList(5)
+{
+	status_t error;
+	int32 architecture;
+	if ((error = archive->FindString("name", &fName)) == B_OK
+		&& (error = archive->FindString("summary", &fSummary)) == B_OK
+		&& (error = archive->FindString("description", &fDescription)) == B_OK
+		&& (error = archive->FindString("vendor", &fVendor)) == B_OK
+		&& (error = archive->FindString("packager", &fPackager)) == B_OK
+		&& (error = archive->FindUInt32("flags", &fFlags)) == B_OK
+		&& (error = archive->FindInt32("architecture", &architecture)) == B_OK
+		&& (error = _ExtractVersion(archive, "version", 0, fVersion)) == B_OK
+		&& (error = _ExtractStringList(archive, "copyrights", fCopyrightList))
+			== B_OK
+		&& (error = _ExtractStringList(archive, "licenses", fLicenseList))
+			== B_OK
+		&& (error = _ExtractStringList(archive, "urls", fURLList)) == B_OK
+		&& (error = _ExtractStringList(archive, "source-urls", fSourceURLList))
+			== B_OK
+		&& (error = _ExtractResolvables(archive, "provides", fProvidesList))
+			== B_OK
+		&& (error = _ExtractResolvableExpressions(archive, "requires",
+			fRequiresList)) == B_OK
+		&& (error = _ExtractResolvableExpressions(archive, "supplements",
+			fSupplementsList)) == B_OK
+		&& (error = _ExtractResolvableExpressions(archive, "conflicts",
+			fConflictsList)) == B_OK
+		&& (error = _ExtractResolvableExpressions(archive, "freshens",
+			fFreshensList)) == B_OK
+		&& (error = _ExtractStringList(archive, "replaces", fReplacesList))
+			== B_OK
+		&& (error = archive->FindString("checksum", &fChecksum)) == B_OK
+		&& (error = archive->FindString("install-path", &fInstallPath)) == B_OK) {
+		if (architecture >= 0
+			|| architecture <= B_PACKAGE_ARCHITECTURE_ENUM_COUNT) {
+			fArchitecture = (BPackageArchitecture)architecture;
+		} else
+			error = B_BAD_DATA;
+	}
+
+	if (_error != NULL)
+		*_error = error;
+}
+
+
 BPackageInfo::~BPackageInfo()
 {
 }
@@ -1624,6 +1729,55 @@ BPackageInfo::Clear()
 }
 
 
+status_t
+BPackageInfo::Archive(BMessage* archive, bool deep) const
+{
+	status_t error = BArchivable::Archive(archive, deep);
+	if (error != B_OK)
+		return error;
+
+	if ((error = archive->AddString("name", fName)) != B_OK
+		|| (error = archive->AddString("summary", fSummary)) != B_OK
+		|| (error = archive->AddString("description", fDescription)) != B_OK
+		|| (error = archive->AddString("vendor", fVendor)) != B_OK
+		|| (error = archive->AddString("packager", fPackager)) != B_OK
+		|| (error = archive->AddUInt32("flags", fFlags)) != B_OK
+		|| (error = archive->AddInt32("architecture", fArchitecture)) != B_OK
+		|| (error = _AddVersion(archive, "version", fVersion)) != B_OK
+		|| (error = _AddStringList(archive, "copyrights", fCopyrightList))
+			!= B_OK
+		|| (error = _AddStringList(archive, "licenses", fLicenseList)) != B_OK
+		|| (error = _AddStringList(archive, "urls", fURLList)) != B_OK
+		|| (error = _AddStringList(archive, "source-urls", fSourceURLList))
+			!= B_OK
+		|| (error = _AddResolvables(archive, "provides", fProvidesList)) != B_OK
+		|| (error = _AddResolvableExpressions(archive, "requires",
+			fRequiresList)) != B_OK
+		|| (error = _AddResolvableExpressions(archive, "supplements",
+			fSupplementsList)) != B_OK
+		|| (error = _AddResolvableExpressions(archive, "conflicts",
+			fConflictsList)) != B_OK
+		|| (error = _AddResolvableExpressions(archive, "freshens",
+			fFreshensList)) != B_OK
+		|| (error = _AddStringList(archive, "replaces", fReplacesList)) != B_OK
+		|| (error = archive->AddString("checksum", fChecksum)) != B_OK
+		|| (error = archive->AddString("install-path", fInstallPath)) != B_OK) {
+		return error;
+	}
+
+	return B_OK;
+}
+
+
+/*static*/ BArchivable*
+BPackageInfo::Instantiate(BMessage* archive)
+{
+	if (validate_instantiation(archive, "BPackageInfo"))
+		return new(std::nothrow) BPackageInfo(archive);
+	return NULL;
+}
+
+
 status_t
 BPackageInfo::GetConfigString(BString& _string) const
 {
@@ -1683,4 +1837,335 @@ BPackageInfo::ParseVersionString(const BString& string, bool releaseIsOptional,
 }
 
 
+/*static*/ status_t
+BPackageInfo::_AddVersion(BMessage* archive, const char* field,
+	const BPackageVersion& version)
+{
+	// Storing BPackageVersion::ToString() would be nice, but the corresponding
+	// constructor only works for valid versions and we might want to store
+	// invalid versions as well.
+
+	// major
+	size_t fieldLength = strlen(field);
+	FieldName fieldName(field, ":major");
+	if (!fieldName.IsValid())
+		return B_BAD_VALUE;
+
+	status_t error = archive->AddString(fieldName, version.Major());
+	if (error != B_OK)
+		return error;
+
+	// minor
+	if (!fieldName.ReplaceSuffix(fieldLength, ":minor"))
+		return B_BAD_VALUE;
+
+	error = archive->AddString(fieldName, version.Minor());
+	if (error != B_OK)
+		return error;
+
+	// micro
+	if (!fieldName.ReplaceSuffix(fieldLength, ":micro"))
+		return B_BAD_VALUE;
+
+	error = archive->AddString(fieldName, version.Micro());
+	if (error != B_OK)
+		return error;
+
+	// pre-release
+	if (!fieldName.ReplaceSuffix(fieldLength, ":pre"))
+		return B_BAD_VALUE;
+
+	error = archive->AddString(fieldName, version.PreRelease());
+	if (error != B_OK)
+		return error;
+
+	// revision
+	if (!fieldName.ReplaceSuffix(fieldLength, ":revision"))
+		return B_BAD_VALUE;
+
+	return archive->AddUInt8(fieldName, version.Release());
+}
+
+
+/*static*/ status_t
+BPackageInfo::_AddStringList(BMessage* archive, const char* field,
+	const BStringList& list)
+{
+	int32 count = list.CountStrings();
+	for (int32 i = 0; i < count; i++) {
+		status_t error = archive->AddString(field, list.StringAt(i));
+		if (error != B_OK)
+			return error;
+	}
+
+	return B_OK;
+}
+
+
+/*static*/ status_t
+BPackageInfo::_AddResolvables(BMessage* archive, const char* field,
+	const ResolvableList& resolvables)
+{
+	// construct the field names we need
+	FieldName nameField(field, ":name");
+	FieldName typeField(field, ":type");
+	FieldName versionField(field, ":version");
+	FieldName compatibleVersionField(field, ":compat");
+
+	if (!nameField.IsValid() || !typeField.IsValid() || !versionField.IsValid()
+		|| !compatibleVersionField.IsValid()) {
+		return B_BAD_VALUE;
+	}
+
+	// add fields
+	int32 count = resolvables.CountItems();
+	for (int32 i = 0; i < count; i++) {
+		const BPackageResolvable* resolvable = resolvables.ItemAt(i);
+		status_t error;
+		if ((error = archive->AddString(nameField, resolvable->Name())) != B_OK
+			|| (error = archive->AddInt32(typeField, resolvable->Type()))
+				!= B_OK
+			|| (error = _AddVersion(archive, versionField,
+				resolvable->Version())) != B_OK
+			|| (error = _AddVersion(archive, compatibleVersionField,
+				resolvable->CompatibleVersion())) != B_OK) {
+			return error;
+		}
+	}
+
+	return B_OK;
+}
+
+
+/*static*/ status_t
+BPackageInfo::_AddResolvableExpressions(BMessage* archive, const char* field,
+	const ResolvableExpressionList& expressions)
+{
+	// construct the field names we need
+	FieldName nameField(field, ":name");
+	FieldName operatorField(field, ":operator");
+	FieldName versionField(field, ":version");
+
+	if (!nameField.IsValid() || !operatorField.IsValid()
+		|| !versionField.IsValid()) {
+		return B_BAD_VALUE;
+	}
+
+	// add fields
+	int32 count = expressions.CountItems();
+	for (int32 i = 0; i < count; i++) {
+		const BPackageResolvableExpression* expression = expressions.ItemAt(i);
+		status_t error;
+		if ((error = archive->AddString(nameField, expression->Name())) != B_OK
+			|| (error = archive->AddInt32(operatorField,
+				expression->Operator())) != B_OK
+			|| (error = _AddVersion(archive, versionField,
+				expression->Version())) != B_OK) {
+			return error;
+		}
+	}
+
+	return B_OK;
+}
+
+
+/*static*/ status_t
+BPackageInfo::_ExtractVersion(BMessage* archive, const char* field, int32 index,
+	BPackageVersion& _version)
+{
+	// major
+	size_t fieldLength = strlen(field);
+	FieldName fieldName(field, ":major");
+	if (!fieldName.IsValid())
+		return B_BAD_VALUE;
+
+	BString major;
+	status_t error = archive->FindString(fieldName, index, &major);
+	if (error != B_OK)
+		return error;
+
+	// minor
+	if (!fieldName.ReplaceSuffix(fieldLength, ":minor"))
+		return B_BAD_VALUE;
+
+	BString minor;
+	error = archive->FindString(fieldName, index, &minor);
+	if (error != B_OK)
+		return error;
+
+	// micro
+	if (!fieldName.ReplaceSuffix(fieldLength, ":micro"))
+		return B_BAD_VALUE;
+
+	BString micro;
+	error = archive->FindString(fieldName, index, µ);
+	if (error != B_OK)
+		return error;
+
+	// pre-release
+	if (!fieldName.ReplaceSuffix(fieldLength, ":pre"))
+		return B_BAD_VALUE;
+
+	BString preRelease;
+	error = archive->FindString(fieldName, index, &preRelease);
+	if (error != B_OK)
+		return error;
+
+	// revision
+	if (!fieldName.ReplaceSuffix(fieldLength, ":revision"))
+		return B_BAD_VALUE;
+
+	uint8 revision;
+	error = archive->FindUInt8(fieldName, index, &revision);
+	if (error != B_OK)
+		return error;
+
+	_version.SetTo(major, minor, micro, preRelease, revision);
+	return B_OK;
+}
+
+
+/*static*/ status_t
+BPackageInfo::_ExtractStringList(BMessage* archive, const char* field,
+	BStringList& _list)
+{
+	// get the number of items
+	type_code type;
+	int32 count;
+	if (archive->GetInfo(field, &type, &count)) {
+		// the field is missing
+		return B_OK;
+	}
+	if (type != B_STRING_TYPE)
+		return B_BAD_DATA;
+
+	for (int32 i = 0; i < count; i++) {
+		BString string;
+		status_t error = archive->FindString(field, i, &string);
+		if (error != B_OK)
+			return error;
+		if (!_list.Add(string))
+			return B_NO_MEMORY;
+	}
+
+	return B_OK;
+}
+
+
+/*static*/ status_t
+BPackageInfo::_ExtractResolvables(BMessage* archive, const char* field,
+	ResolvableList& _resolvables)
+{
+	// construct the field names we need
+	FieldName nameField(field, ":name");
+	FieldName typeField(field, ":type");
+	FieldName versionField(field, ":version");
+	FieldName compatibleVersionField(field, ":compat");
+
+	if (!nameField.IsValid() || !typeField.IsValid() || !versionField.IsValid()
+		|| !compatibleVersionField.IsValid()) {
+		return B_BAD_VALUE;
+	}
+
+	// get the number of items
+	type_code type;
+	int32 count;
+	if (archive->GetInfo(nameField, &type, &count)) {
+		// the field is missing
+		return B_OK;
+	}
+
+	// extract fields
+	for (int32 i = 0; i < count; i++) {
+		BString name;
+		status_t error = archive->FindString(nameField, i, &name);
+		if (error != B_OK)
+			return error;
+
+		int32 type;
+		error = archive->FindInt32(typeField, i, &type);
+		if (error != B_OK)
+			return error;
+		if (type < 0 || type > B_PACKAGE_RESOLVABLE_TYPE_ENUM_COUNT)
+			return B_BAD_DATA;
+
+		BPackageVersion version;
+		error = _ExtractVersion(archive, versionField, i, version);
+		if (error != B_OK)
+			return error;
+
+		BPackageVersion compatibleVersion;
+		error = _ExtractVersion(archive, compatibleVersionField, i,
+			compatibleVersion);
+		if (error != B_OK)
+			return error;
+
+		BPackageResolvable* resolvable = new(std::nothrow) BPackageResolvable(
+			name, (BPackageResolvableType)type, version, compatibleVersion);
+		if (resolvable == NULL || !_resolvables.AddItem(resolvable)) {
+			delete resolvable;
+			return B_NO_MEMORY;
+		}
+	}
+
+	return B_OK;
+}
+
+
+/*static*/ status_t
+BPackageInfo::_ExtractResolvableExpressions(BMessage* archive,
+	const char* field, ResolvableExpressionList& _expressions)
+{
+	// construct the field names we need
+	FieldName nameField(field, ":name");
+	FieldName operatorField(field, ":operator");
+	FieldName versionField(field, ":version");
+
+	if (!nameField.IsValid() || !operatorField.IsValid()
+		|| !versionField.IsValid()) {
+		return B_BAD_VALUE;
+	}
+
+	// get the number of items
+	type_code type;
+	int32 count;
+	if (archive->GetInfo(nameField, &type, &count)) {
+		// the field is missing
+		return B_OK;
+	}
+
+	// extract fields
+	for (int32 i = 0; i < count; i++) {
+		BString name;
+		status_t error = archive->FindString(nameField, i, &name);
+		if (error != B_OK)
+			return error;
+
+		int32 operatorType;
+		error = archive->FindInt32(operatorField, i, &operatorType);
+		if (error != B_OK)
+			return error;
+		if (operatorType < 0 
+			| operatorType > B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT) {
+			return B_BAD_DATA;
+		}
+
+		BPackageVersion version;
+		error = _ExtractVersion(archive, versionField, i, version);
+		if (error != B_OK)
+			return error;
+
+		BPackageResolvableExpression* expression
+			= new(std::nothrow) BPackageResolvableExpression(name,
+				(BPackageResolvableOperator)operatorType, version);
+		if (expression == NULL || !_expressions.AddItem(expression)) {
+			delete expression;
+			return B_NO_MEMORY;
+		}
+	}
+
+	return B_OK;
+}
+
+
 }	// namespace BPackageKit

From b2d96da589896ed9ebb2524f873e9fc0baa650ec Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 14 Apr 2013 16:47:01 +0200
Subject: [PATCH 0410/1170] BPackageInfoSet::Iterator: Fix NULL pointer
 dereference

Since the BPackageInfoSet's map is created lazily, it can be NULL when
an Iterator is constructed.
---
 headers/os/package/PackageInfoSet.h |  3 +--
 src/kits/package/PackageInfoSet.cpp | 10 +---------
 2 files changed, 2 insertions(+), 11 deletions(-)

diff --git a/headers/os/package/PackageInfoSet.h b/headers/os/package/PackageInfoSet.h
index 35fbbdc2be..4a11f553bb 100644
--- a/headers/os/package/PackageInfoSet.h
+++ b/headers/os/package/PackageInfoSet.h
@@ -49,8 +49,7 @@ private:
 
 class BPackageInfoSet::Iterator {
 public:
-								Iterator();
-								Iterator(const PackageMap* map);
+								Iterator(const PackageMap* map = NULL);
 
 			bool				HasNext() const;
 			const BPackageInfo*	Next();
diff --git a/src/kits/package/PackageInfoSet.cpp b/src/kits/package/PackageInfoSet.cpp
index 997e1dced5..f279e67b81 100644
--- a/src/kits/package/PackageInfoSet.cpp
+++ b/src/kits/package/PackageInfoSet.cpp
@@ -173,18 +173,10 @@ private:
 // #pragma mark - Iterator
 
 
-BPackageInfoSet::Iterator::Iterator()
-	:
-	fMap(NULL),
-	fNextInfo(NULL)
-{
-}
-
-
 BPackageInfoSet::Iterator::Iterator(const PackageMap* map)
 	:
 	fMap(map),
-	fNextInfo(map->GetIterator().Next())
+	fNextInfo(map != NULL ? map->GetIterator().Next() : NULL)
 {
 }
 

From d7d9497e31047e9cf1c486865d6cbb7df3441487 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 14 Apr 2013 16:50:30 +0200
Subject: [PATCH 0411/1170] Add BInstallationLocationInfo

---
 .../os/package/InstallationLocationInfo.h     |   1 +
 headers/os/package/InstallationLocationInfo.h |  59 ++++++++
 src/build/libpackage/Jamfile                  |   1 +
 src/kits/package/InstallationLocationInfo.cpp | 131 ++++++++++++++++++
 src/kits/package/Jamfile                      |   1 +
 5 files changed, 193 insertions(+)
 create mode 100644 headers/build/os/package/InstallationLocationInfo.h
 create mode 100644 headers/os/package/InstallationLocationInfo.h
 create mode 100644 src/kits/package/InstallationLocationInfo.cpp

diff --git a/headers/build/os/package/InstallationLocationInfo.h b/headers/build/os/package/InstallationLocationInfo.h
new file mode 100644
index 0000000000..d9e97590f5
--- /dev/null
+++ b/headers/build/os/package/InstallationLocationInfo.h
@@ -0,0 +1 @@
+#include <../os/package/InstallationLocationInfo.h>
diff --git a/headers/os/package/InstallationLocationInfo.h b/headers/os/package/InstallationLocationInfo.h
new file mode 100644
index 0000000000..3bdec66666
--- /dev/null
+++ b/headers/os/package/InstallationLocationInfo.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__INSTALLATION_LOCATION_INFO_H_
+#define _PACKAGE__INSTALLATION_LOCATION_INFO_H_
+
+
+#include 
+
+#include 
+#include 
+
+
+namespace BPackageKit {
+
+
+class BInstallationLocationInfo {
+public:
+								BInstallationLocationInfo();
+								~BInstallationLocationInfo();
+
+			void				Unset();
+
+			BPackageInstallationLocation Location() const;
+			void				SetLocation(
+									BPackageInstallationLocation location);
+
+			const node_ref&		BaseDirectoryRef() const;
+			status_t			SetBaseDirectoryRef(const node_ref& ref);
+
+			const node_ref&		PackagesDirectoryRef() const;
+			status_t			SetPackagesDirectoryRef(const node_ref& ref);
+
+			const BPackageInfoSet& ActivePackageInfos() const;
+			void				SetActivePackageInfos(
+									const BPackageInfoSet& infos);
+
+			const BPackageInfoSet& InactivePackageInfos() const;
+			void				SetInactivePackageInfos(
+									const BPackageInfoSet& infos);
+
+			int64				ChangeCount() const;
+			void				SetChangeCount(int64 changeCount);
+
+private:
+			BPackageInstallationLocation fLocation;
+			node_ref			fBaseDirectoryRef;
+			node_ref			fPackageDirectoryRef;
+			BPackageInfoSet		fActivePackageInfos;
+			BPackageInfoSet		fInactivePackageInfos;
+			int64				fChangeCount;
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif	// _PACKAGE__INSTALLATION_LOCATION_INFO_H_
diff --git a/src/build/libpackage/Jamfile b/src/build/libpackage/Jamfile
index 58ce24b42e..65a24be213 100644
--- a/src/build/libpackage/Jamfile
+++ b/src/build/libpackage/Jamfile
@@ -74,6 +74,7 @@ BuildPlatformSharedLibrary libpackage_build.so
 	Context.cpp
 	DropRepositoryRequest.cpp
 	FetchFileJob.cpp
+	InstallationLocationInfo.cpp
 	Job.cpp
 	JobQueue.cpp
 	PackageInfo.cpp
diff --git a/src/kits/package/InstallationLocationInfo.cpp b/src/kits/package/InstallationLocationInfo.cpp
new file mode 100644
index 0000000000..6d67d07078
--- /dev/null
+++ b/src/kits/package/InstallationLocationInfo.cpp
@@ -0,0 +1,131 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+
+namespace BPackageKit {
+
+
+BInstallationLocationInfo::BInstallationLocationInfo()
+	:
+	fLocation(B_PACKAGE_INSTALLATION_LOCATION_ENUM_COUNT),
+	fBaseDirectoryRef(),
+	fPackageDirectoryRef(),
+	fActivePackageInfos(),
+	fInactivePackageInfos(),
+	fChangeCount(0)
+{
+}
+
+
+BInstallationLocationInfo::~BInstallationLocationInfo()
+{
+}
+
+
+void
+BInstallationLocationInfo::Unset()
+{
+	fLocation = B_PACKAGE_INSTALLATION_LOCATION_ENUM_COUNT;
+	fBaseDirectoryRef = node_ref();
+	fPackageDirectoryRef = node_ref();
+	fActivePackageInfos.MakeEmpty();
+	fInactivePackageInfos.MakeEmpty();
+	fChangeCount = 0;
+}
+
+
+BPackageInstallationLocation
+BInstallationLocationInfo::Location() const
+{
+	return fLocation;
+}
+
+
+void
+BInstallationLocationInfo::SetLocation(BPackageInstallationLocation location)
+{
+	fLocation = location;
+}
+
+
+const node_ref&
+BInstallationLocationInfo::BaseDirectoryRef() const
+{
+	return fBaseDirectoryRef;
+}
+
+
+status_t
+BInstallationLocationInfo::SetBaseDirectoryRef(const node_ref& ref)
+{
+	fBaseDirectoryRef = ref;
+	return fBaseDirectoryRef == ref ? B_OK : B_NO_MEMORY;
+}
+
+
+const node_ref&
+BInstallationLocationInfo::PackagesDirectoryRef() const
+{
+	return fPackageDirectoryRef;
+}
+
+
+status_t
+BInstallationLocationInfo::SetPackagesDirectoryRef(const node_ref& ref)
+{
+	fPackageDirectoryRef = ref;
+	return fPackageDirectoryRef == ref ? B_OK : B_NO_MEMORY;
+}
+
+
+const BPackageInfoSet&
+BInstallationLocationInfo::ActivePackageInfos() const
+{
+	return fActivePackageInfos;
+}
+
+
+void
+BInstallationLocationInfo::SetActivePackageInfos(const BPackageInfoSet& infos)
+{
+	fActivePackageInfos = infos;
+}
+
+
+const BPackageInfoSet&
+BInstallationLocationInfo::InactivePackageInfos() const
+{
+	return fInactivePackageInfos;
+}
+
+
+void
+BInstallationLocationInfo::SetInactivePackageInfos(const BPackageInfoSet& infos)
+{
+	fInactivePackageInfos = infos;
+}
+
+
+int64
+BInstallationLocationInfo::ChangeCount() const
+{
+	return fChangeCount;
+}
+
+
+void
+BInstallationLocationInfo::SetChangeCount(int64 changeCount)
+{
+	fChangeCount = changeCount;
+}
+
+
+}	// namespace BPackageKit
diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile
index 338aceedf7..a3c9bede3d 100644
--- a/src/kits/package/Jamfile
+++ b/src/kits/package/Jamfile
@@ -53,6 +53,7 @@ SharedLibrary libpackage.so
 	Context.cpp
 	DropRepositoryRequest.cpp
 	FetchFileJob.cpp
+	InstallationLocationInfo.cpp
 	Job.cpp
 	JobQueue.cpp
 	PackageInfo.cpp

From e6216e372af01cc90339fe7afb70c113c99974bd Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 14 Apr 2013 17:04:33 +0200
Subject: [PATCH 0412/1170] Implement getting a BInstallationLocationInfo

* Rename PackageDaemonDefs.h to DaemonDefs.h.
* Replace the MESSAGE_GET_PACKAGES by the new
  B_MESSAGE_GET_INSTALLATION_LOCATION_INFO, which not only returns the
  packages, but also other information about the installation location.
* daemon: Volume: Implement a change count which is bumped whenever
  packages are activated/deactivated/added/removed. Cache the reply
  for a location info request, using the change count to check whether
  it is still up-to-date.
* Add private BDaemonClient for communication with the daemon.
* BRoster:
  - Add GetInstallationLocationInfo() using BDaemonClient.
  - Reimplement GetActivePackages(), using
    GetInstallationLocationInfo().
---
 headers/os/package/PackageRoster.h          |   4 +
 headers/private/package/DaemonClient.h      |  49 +++++++
 headers/private/package/DaemonDefs.h        |  46 +++++++
 headers/private/package/PackageDaemonDefs.h |  37 ------
 src/kits/package/DaemonClient.cpp           | 137 ++++++++++++++++++++
 src/kits/package/Jamfile                    |   1 +
 src/kits/package/PackageRoster.cpp          |  79 +++--------
 src/servers/package/PackageDaemon.cpp       |   8 +-
 src/servers/package/Root.cpp                |  18 +--
 src/servers/package/Root.h                  |   9 +-
 src/servers/package/Volume.cpp              |  58 +++++++--
 src/servers/package/Volume.h                |   7 +-
 12 files changed, 329 insertions(+), 124 deletions(-)
 create mode 100644 headers/private/package/DaemonClient.h
 create mode 100644 headers/private/package/DaemonDefs.h
 delete mode 100644 headers/private/package/PackageDaemonDefs.h
 create mode 100644 src/kits/package/DaemonClient.cpp

diff --git a/headers/os/package/PackageRoster.h b/headers/os/package/PackageRoster.h
index d407da7e38..15487c23c1 100644
--- a/headers/os/package/PackageRoster.h
+++ b/headers/os/package/PackageRoster.h
@@ -28,6 +28,7 @@ struct BRepositoryConfigVisitor {
 };
 
 
+class BInstallationLocationInfo;
 class BPackageInfoSet;
 class BRepositoryCache;
 class BRepositoryConfig;
@@ -60,6 +61,9 @@ public:
 			status_t			GetRepositoryConfig(const BString& name,
 									BRepositoryConfig* repositoryConfig);
 
+			status_t			GetInstallationLocationInfo(
+									BPackageInstallationLocation location,
+									BInstallationLocationInfo& _info);
 			status_t			GetActivePackages(
 									BPackageInstallationLocation location,
 									BPackageInfoSet& packageInfos);
diff --git a/headers/private/package/DaemonClient.h b/headers/private/package/DaemonClient.h
new file mode 100644
index 0000000000..e16b3e3499
--- /dev/null
+++ b/headers/private/package/DaemonClient.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef _PACKAGE__PRIVATE__DAEMON_CLIENT_H_
+#define _PACKAGE__PRIVATE__DAEMON_CLIENT_H_
+
+
+#include 
+#include 
+
+
+namespace BPackageKit {
+
+
+class BInstallationLocationInfo;
+class BPackageInfoSet;
+
+
+namespace BPrivate {
+
+
+class BDaemonClient {
+public:
+								BDaemonClient();
+								~BDaemonClient();
+
+			status_t			GetInstallationLocationInfo(
+									BPackageInstallationLocation location,
+									BInstallationLocationInfo& _info);
+
+private:
+			status_t			_InitMessenger();
+			status_t			_ExtractPackageInfoSet(const BMessage& message,
+									const char* field, BPackageInfoSet& _infos);
+
+private:
+			BMessenger			fDaemonMessenger;
+};
+
+
+}	// namespace BPrivate
+}	// namespace BPackageKit
+
+
+#endif	// _PACKAGE__PRIVATE__DAEMON_CLIENT_H_
diff --git a/headers/private/package/DaemonDefs.h b/headers/private/package/DaemonDefs.h
new file mode 100644
index 0000000000..3bde3b742b
--- /dev/null
+++ b/headers/private/package/DaemonDefs.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef _PACKAGE__PRIVATE__DAEMON_DEFS_H_
+#define _PACKAGE__PRIVATE__DAEMON_DEFS_H_
+
+
+namespace BPackageKit {
+namespace BPrivate {
+
+
+#define B_PACKAGE_DAEMON_APP_SIGNATURE "application/x-vnd.haiku-package_daemon"
+
+
+enum BDaemonError {
+	B_DAEMON_OK
+};
+
+
+// message codes for requests to and replies from the daemon
+enum {
+	B_MESSAGE_GET_INSTALLATION_LOCATION_INFO		= 'PKLI',
+		// "location": int32
+		//		the respective installation location constant
+	B_MESSAGE_GET_INSTALLATION_LOCATION_INFO_REPLY	= 'PKLR',
+		// "base directory device": int32
+		// "base directory node": int64
+		// "packages directory device": int32
+		// "packages directory node": int64
+		// "change count": int64
+		// "active packages": message[]
+		//		archived BPackageInfos of the active packages
+		// "inactive packages": message[]
+		//		archived BPackageInfos of the inactive packages
+};
+
+
+#endif	// _PACKAGE__PRIVATE__DAEMON_DEFS_H_
+
+
+}	// namespace BPrivate
+}	// namespace BPackageKit
diff --git a/headers/private/package/PackageDaemonDefs.h b/headers/private/package/PackageDaemonDefs.h
deleted file mode 100644
index ccb74b7df6..0000000000
--- a/headers/private/package/PackageDaemonDefs.h
+++ /dev/null
@@ -1,37 +0,0 @@
-/*
- * Copyright 2013, Haiku, Inc. All Rights Reserved.
- * Distributed under the terms of the MIT License.
- *
- * Authors:
- *		Ingo Weinhold 
- */
-#ifndef _PACKAGE__PRIVATE__PACKAGE_DAEMON_DEFS_H_
-#define _PACKAGE__PRIVATE__PACKAGE_DAEMON_DEFS_H_
-
-
-namespace BPackageKit {
-namespace BPrivate {
-
-
-#define PACKAGE_DAEMON_APP_SIGNATURE "application/x-vnd.haiku-package_daemon"
-
-
-// message codes for requests to and replies from the daemon
-enum {
-	MESSAGE_GET_PACKAGES		= 'PKGG',
-		// "location": int32
-		//		the respective installation location constant
-	MESSAGE_GET_PACKAGES_REPLY	= 'PKGR'
-		// "active packages": string[]
-		//		file names of the active packages (no path)
-		// "inactive packages": string[]
-		//		file names of the inactive packages (no path)
-	
-};
-
-
-#endif	// _PACKAGE__PRIVATE__PACKAGE_DAEMON_DEFS_H_
-
-
-}	// namespace BPrivate
-}	// namespace BPackageKit
diff --git a/src/kits/package/DaemonClient.cpp b/src/kits/package/DaemonClient.cpp
new file mode 100644
index 0000000000..10d35c0de0
--- /dev/null
+++ b/src/kits/package/DaemonClient.cpp
@@ -0,0 +1,137 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+#include 
+#include 
+
+#include 
+
+
+namespace BPackageKit {
+namespace BPrivate {
+
+
+BDaemonClient::BDaemonClient()
+	:
+	fDaemonMessenger()
+{
+}
+
+
+BDaemonClient::~BDaemonClient()
+{
+}
+
+
+status_t
+BDaemonClient::GetInstallationLocationInfo(
+	BPackageInstallationLocation location, BInstallationLocationInfo& _info)
+{
+	status_t error = _InitMessenger();
+	if (error != B_OK)
+		return error;
+
+	// send the request
+	BMessage request(B_MESSAGE_GET_INSTALLATION_LOCATION_INFO);
+	error = request.AddInt32("location", location);
+	if (error != B_OK)
+		return error;
+
+	BMessage reply;
+	fDaemonMessenger.SendMessage(&request, &reply);
+	if (reply.what != B_MESSAGE_GET_INSTALLATION_LOCATION_INFO_REPLY)
+		return B_ERROR;
+
+	// extract the location info
+	int32 baseDirectoryDevice;
+	int64 baseDirectoryNode;
+	int32 packagesDirectoryDevice;
+	int64 packagesDirectoryNode;
+	int64 changeCount;
+	BPackageInfoSet activePackages;
+	BPackageInfoSet inactivePackages;
+	if ((error = reply.FindInt32("base directory device", &baseDirectoryDevice))
+			!= B_OK
+		|| (error = reply.FindInt64("base directory node", &baseDirectoryNode))
+			!= B_OK
+		|| (error = reply.FindInt32("packages directory device",
+			&packagesDirectoryDevice)) != B_OK
+		|| (error = reply.FindInt64("packages directory node",
+			&packagesDirectoryNode)) != B_OK
+		|| (error = _ExtractPackageInfoSet(reply, "active packages",
+			activePackages)) != B_OK
+		|| (error = _ExtractPackageInfoSet(reply, "inactive packages",
+			inactivePackages)) != B_OK
+		|| (error = reply.FindInt64("change count", &changeCount)) != B_OK) {
+		return error;
+	}
+
+	_info.Unset();
+	_info.SetLocation(location);
+	_info.SetBaseDirectoryRef(node_ref(baseDirectoryDevice, baseDirectoryNode));
+	_info.SetPackagesDirectoryRef(
+		node_ref(packagesDirectoryDevice, packagesDirectoryNode));
+	_info.SetActivePackageInfos(activePackages);
+	_info.SetInactivePackageInfos(inactivePackages);
+	_info.SetChangeCount(changeCount);
+
+	return B_OK;
+}
+
+
+status_t
+BDaemonClient::_InitMessenger()
+{
+	if (fDaemonMessenger.IsValid())
+		return B_OK;
+
+		// get the package daemon's address
+	status_t error;
+	fDaemonMessenger = BMessenger(B_PACKAGE_DAEMON_APP_SIGNATURE, -1, &error);
+	return error;
+}
+
+
+status_t
+BDaemonClient::_ExtractPackageInfoSet(const BMessage& message,
+	const char* field, BPackageInfoSet& _infos)
+{
+	// get the number of items
+	type_code type;
+	int32 count;
+	if (message.GetInfo(field, &type, &count)) {
+		// the field is missing
+		return B_OK;
+	}
+	if (type != B_MESSAGE_TYPE)
+		return B_BAD_DATA;
+
+	for (int32 i = 0; i < count; i++) {
+		BMessage archive;
+		status_t error = message.FindMessage(field, i, &archive);
+		if (error != B_OK)
+			return error;
+
+		BPackageInfo info(&archive, &error);
+		if (error != B_OK)
+			return error;
+
+		error = _infos.AddInfo(info);
+		if (error != B_OK)
+			return error;
+	}
+
+	return B_OK;
+}
+
+
+}	// namespace BPrivate
+}	// namespace BPackageKit
diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile
index a3c9bede3d..8ebcc9ce2f 100644
--- a/src/kits/package/Jamfile
+++ b/src/kits/package/Jamfile
@@ -51,6 +51,7 @@ SharedLibrary libpackage.so
 	BlockBufferCacheNoLock.cpp
 	ChecksumAccessors.cpp
 	Context.cpp
+	DaemonClient.cpp
 	DropRepositoryRequest.cpp
 	FetchFileJob.cpp
 	InstallationLocationInfo.cpp
diff --git a/src/kits/package/PackageRoster.cpp b/src/kits/package/PackageRoster.cpp
index 62b4bb90ad..9e5a3a3bcf 100644
--- a/src/kits/package/PackageRoster.cpp
+++ b/src/kits/package/PackageRoster.cpp
@@ -19,6 +19,7 @@
 #include 
 #include 
 
+#include 
 #include 
 #include 
 #include 
@@ -28,7 +29,7 @@
 #include 
 
 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
-#	include 
+#	include 
 #endif
 
 
@@ -188,6 +189,21 @@ BPackageRoster::GetRepositoryConfig(const BString& name,
 }
 
 
+status_t
+BPackageRoster::GetInstallationLocationInfo(
+	BPackageInstallationLocation location, BInstallationLocationInfo& _info)
+{
+// This method makes sense only on an installed Haiku, but not for the build
+// tools.
+#if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
+	return BPackageKit::BPrivate::BDaemonClient().GetInstallationLocationInfo(
+		location, _info);
+#else
+	return B_NOT_SUPPORTED;
+#endif
+}
+
+
 status_t
 BPackageRoster::GetActivePackages(BPackageInstallationLocation location,
 	BPackageInfoSet& packageInfos)
@@ -195,67 +211,12 @@ BPackageRoster::GetActivePackages(BPackageInstallationLocation location,
 // This method makes sense only on an installed Haiku, but not for the build
 // tools.
 #if defined(__HAIKU__) && !defined(HAIKU_HOST_PLATFORM_HAIKU)
-	// check the given location
-	directory_which packagesDirectory;
-	switch (location) {
-		case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM:
-			packagesDirectory = B_SYSTEM_PACKAGES_DIRECTORY;
-			break;
-		case B_PACKAGE_INSTALLATION_LOCATION_COMMON:
-			packagesDirectory = B_COMMON_PACKAGES_DIRECTORY;
-			break;
-		case B_PACKAGE_INSTALLATION_LOCATION_HOME:
-			packagesDirectory = B_USER_PACKAGES_DIRECTORY;
-			break;
-		default:
-			return B_BAD_VALUE;
-	}
-
-	// get the package daemon's address
-	status_t error;
-	BMessenger messenger(PACKAGE_DAEMON_APP_SIGNATURE, -1, &error);
+	BInstallationLocationInfo info;
+	status_t error = GetInstallationLocationInfo(location, info);
 	if (error != B_OK)
 		return error;
 
-	// request a list of packages
-	BMessage request(BPackageKit::BPrivate::MESSAGE_GET_PACKAGES);
-	error = request.AddInt32("location", location);
-	if (error != B_OK)
-		return error;
-
-	BMessage reply;
-	messenger.SendMessage(&request, &reply);
-	if (reply.what != BPackageKit::BPrivate::MESSAGE_GET_PACKAGES_REPLY)
-		return B_ERROR;
-
-	// find and open the packages directory
-	BPath packagesDirPath;
-	error = find_directory(packagesDirectory, &packagesDirPath);
-	if (error != B_OK)
-		return error;
-
-	// iterate through the packages
-	const char* packageFileName;
-	for (int32 i = 0;
-		reply.FindString("active packages", i, &packageFileName) == B_OK; i++) {
-		// get the full package file path
-		BPath packagePath;
-		error = packagePath.SetTo(packagesDirPath.Path(), packageFileName);
-		if (error != B_OK)
-			continue;
-
-		// read the package info from the file
-		BPackageInfo info;
-		error = info.ReadFromPackageFile(packagePath.Path());
-		if (error != B_OK || info.InitCheck() != B_OK)
-			continue;
-
-		// add the info
-		error = packageInfos.AddInfo(info);
-		if (error != B_OK)
-			return error;
-	}
-
+	packageInfos = info.ActivePackageInfos();
 	return B_OK;
 #else
 	return B_NOT_SUPPORTED;
diff --git a/src/servers/package/PackageDaemon.cpp b/src/servers/package/PackageDaemon.cpp
index e5ebee0515..58d76c045f 100644
--- a/src/servers/package/PackageDaemon.cpp
+++ b/src/servers/package/PackageDaemon.cpp
@@ -16,7 +16,7 @@
 #include 
 
 #include 
-#include 
+#include 
 
 #include "DebugSupport.h"
 #include "Root.h"
@@ -28,7 +28,7 @@ using namespace BPackageKit::BPrivate;
 
 PackageDaemon::PackageDaemon(status_t* _error)
 	:
-	BServer(PACKAGE_DAEMON_APP_SIGNATURE, false, _error),
+	BServer(B_PACKAGE_DAEMON_APP_SIGNATURE, false, _error),
 	fSystemRoot(NULL),
 	fRoots(10, true),
 	fVolumeWatcher()
@@ -85,12 +85,12 @@ PackageDaemon::MessageReceived(BMessage* message)
 			break;
 		}
 
-		case MESSAGE_GET_PACKAGES:
+		case B_MESSAGE_GET_INSTALLATION_LOCATION_INFO:
 		{
 			if (fSystemRoot == NULL)
 				break;
 
-			fSystemRoot->HandleGetPackagesRequest(DetachCurrentMessage());
+			fSystemRoot->HandleGetLocationInfoRequest(DetachCurrentMessage());
 			break;
 		}
 
diff --git a/src/servers/package/Root.cpp b/src/servers/package/Root.cpp
index b2d63b4bf5..fd0c4565c0 100644
--- a/src/servers/package/Root.cpp
+++ b/src/servers/package/Root.cpp
@@ -42,11 +42,11 @@ private:
 };
 
 
-// #pragma mark - VolumeJob
+// #pragma mark - HandleGetLocationInfoRequestJob
 
 
-struct Root::HandleGetPackagesJob : public Job {
-	HandleGetPackagesJob(Root* root, BMessage* message)
+struct Root::HandleGetLocationInfoRequestJob : public Job {
+	HandleGetLocationInfoRequestJob(Root* root, BMessage* message)
 		:
 		fRoot(root),
 		fMessage(message)
@@ -55,7 +55,7 @@ struct Root::HandleGetPackagesJob : public Job {
 
 	virtual void Do()
 	{
-		fRoot->_HandleGetPackagesRequest(fMessage.Get());
+		fRoot->_HandleGetLocationInfoRequest(fMessage.Get());
 	}
 
 private:
@@ -209,10 +209,10 @@ Root::FindVolume(dev_t deviceID) const
 
 
 void
-Root::HandleGetPackagesRequest(BMessage* message)
+Root::HandleGetLocationInfoRequest(BMessage* message)
 {
-	HandleGetPackagesJob* job
-		= new(std::nothrow) HandleGetPackagesJob(this, message);
+	HandleGetLocationInfoRequestJob* job
+		= new(std::nothrow) HandleGetLocationInfoRequestJob(this, message);
 	if (job == NULL) {
 		delete message;
 		return;
@@ -314,7 +314,7 @@ Root::_ProcessNodeMonitorEvents(Volume* volume)
 
 
 void
-Root::_HandleGetPackagesRequest(BMessage* message)
+Root::_HandleGetLocationInfoRequest(BMessage* message)
 {
 	int32 location;
 	if (message->FindInt32("location", &location) != B_OK
@@ -341,7 +341,7 @@ Root::_HandleGetPackagesRequest(BMessage* message)
 	}
 
 	if (volume != NULL)
-		volume->HandleGetPackagesRequest(message);
+		volume->HandleGetLocationInfoRequest(message);
 }
 
 
diff --git a/src/servers/package/Root.h b/src/servers/package/Root.h
index ad84421aa9..62aba1b8d3 100644
--- a/src/servers/package/Root.h
+++ b/src/servers/package/Root.h
@@ -41,7 +41,7 @@ public:
 
 			Volume*				FindVolume(dev_t deviceID) const;
 
-			void				HandleGetPackagesRequest(BMessage* message);
+			void				HandleGetLocationInfoRequest(BMessage* message);
 
 private:
 	// Volume::Listener
@@ -52,9 +52,9 @@ protected:
 
 private:
 			struct VolumeJob;
-			struct HandleGetPackagesJob;
+			struct HandleGetLocationInfoRequestJob;
 
-			friend struct HandleGetPackagesJob;
+			friend struct HandleGetLocationInfoRequestJob;
 
 private:
 			Volume**			_GetVolume(PackageFSMountType mountType);
@@ -63,7 +63,8 @@ private:
 			void				_InitPackages(Volume* volume);
 			void				_DeleteVolume(Volume* volume);
 			void				_ProcessNodeMonitorEvents(Volume* volume);
-			void				_HandleGetPackagesRequest(BMessage* message);
+			void				_HandleGetLocationInfoRequest(
+									BMessage* message);
 
 			status_t			_QueueJob(Job* job);
 
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index abc5732f7b..401d760430 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -30,7 +30,7 @@
 
 #include 
 #include 
-#include 
+#include 
 #include 
 
 #include "DebugSupport.h"
@@ -104,7 +104,9 @@ Volume::Volume(BLooper* looper)
 	fPendingNodeMonitorEventsLock("pending node monitor events"),
 	fPendingNodeMonitorEvents(),
 	fPackagesToBeActivated(),
-	fPackagesToBeDeactivated()
+	fPackagesToBeDeactivated(),
+	fChangeCount(0),
+	fLocationInfoReply(B_MESSAGE_GET_INSTALLATION_LOCATION_INFO_REPLY)
 {
 	looper->AddHandler(this);
 }
@@ -335,20 +337,49 @@ INFORM("Volume::InitialVerify(%p, %p)\n", nextVolume, nextNextVolume);
 
 
 void
-Volume::HandleGetPackagesRequest(BMessage* message)
+Volume::HandleGetLocationInfoRequest(BMessage* message)
 {
-	BMessage reply(MESSAGE_GET_PACKAGES_REPLY);
+	// If the cached reply message is up-to-date, just send it.
+	int64 changeCount;
+	if (fLocationInfoReply.FindInt64("change count", &changeCount) == B_OK
+		&& changeCount == fChangeCount) {
+		message->SendReply(&fLocationInfoReply, (BHandler*)NULL,
+			kCommunicationTimeout);
+		return;
+	}
+
+	// rebuild the reply message
+	fLocationInfoReply.MakeEmpty();
+
+	if (fLocationInfoReply.AddInt32("base directory device",
+			fRootDirectoryRef.device) != B_OK
+		|| fLocationInfoReply.AddInt64("base directory node",
+			fRootDirectoryRef.node) != B_OK
+		|| fLocationInfoReply.AddInt32("packages directory device",
+			fPackagesDirectoryRef.device) != B_OK
+		|| fLocationInfoReply.AddInt64("packages directory node",
+			fPackagesDirectoryRef.node) != B_OK) {
+		return;
+	}
 
 	for (PackageFileNameHashTable::Iterator it
 			= fPackagesByFileName.GetIterator(); it.HasNext();) {
 		Package* package = it.Next();
 		const char* fieldName = package->IsActive()
 			? "active packages" : "inactive packages";
-		if (reply.AddString(fieldName, package->FileName()) != B_OK)
+		BMessage packageArchive;
+		if (package->Info().Archive(&packageArchive) != B_OK
+			|| fLocationInfoReply.AddMessage(fieldName, &packageArchive)
+				!= B_OK) {
 			return;
+		}
 	}
 
-	message->SendReply(&reply, (BHandler*)NULL, kCommunicationTimeout);
+	if (fLocationInfoReply.AddInt64("change count", fChangeCount) != B_OK)
+		return;
+
+	message->SendReply(&fLocationInfoReply, (BHandler*)NULL,
+		kCommunicationTimeout);
 }
 
 
@@ -514,6 +545,7 @@ fPackagesToBeActivated.size(), fPackagesToBeDeactivated.size());
 	for (PackageSet::iterator it = fPackagesToBeActivated.begin();
 		it != fPackagesToBeActivated.end(); ++it) {
 		(*it)->SetActive(true);
+		fChangeCount++;
 	}
 
 	for (PackageSet::iterator it = fPackagesToBeDeactivated.begin();
@@ -671,8 +703,7 @@ INFORM("Volume::_PackagesEntryCreated(\"%s\")\n", name);
 		return;
 	}
 
-	fPackagesByFileName.Insert(package);
-	fPackagesByNodeRef.Insert(package);
+	_AddPackage(package);
 	packageDeleter.Detach();
 
 	try {
@@ -731,11 +762,19 @@ Volume::_FillInActivationChangeItem(PackageFSActivationChangeItem* item,
 }
 
 
+void
+Volume::_AddPackage(Package* package)
+{
+	fPackagesByFileName.Insert(package);
+	fPackagesByNodeRef.Insert(package);
+}
+
 void
 Volume::_RemovePackage(Package* package)
 {
 	fPackagesByFileName.Remove(package);
 	fPackagesByNodeRef.Remove(package);
+	fChangeCount++;
 }
 
 
@@ -762,8 +801,7 @@ Volume::_ReadPackagesDirectory()
 
 		status_t error = package->Init(entry);
 		if (error == B_OK) {
-			fPackagesByFileName.Insert(package);
-			fPackagesByNodeRef.Insert(package);
+			_AddPackage(package);
 			packageDeleter.Detach();
 		}
 	}
diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h
index 404f6c4a57..8e65ff3fe1 100644
--- a/src/servers/package/Volume.h
+++ b/src/servers/package/Volume.h
@@ -13,6 +13,7 @@
 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -48,7 +49,7 @@ public:
 									bool activeOnly);
 			void				InitialVerify(Volume* nextVolume,
 									Volume* nextNextVolume);
-			void				HandleGetPackagesRequest(BMessage* message);
+			void				HandleGetLocationInfoRequest(BMessage* message);
 
 			void				Unmounted();
 
@@ -105,6 +106,8 @@ private:
 									PackageFSActivationChangeItem* item,
 									PackageFSActivationChangeType type,
 									Package* package, char*& nameBuffer);
+
+			void				_AddPackage(Package* package);
 			void				_RemovePackage(Package* package);
 
 			status_t			_ReadPackagesDirectory();
@@ -133,6 +136,8 @@ private:
 			NodeMonitorEventList fPendingNodeMonitorEvents;
 			PackageSet			fPackagesToBeActivated;
 			PackageSet			fPackagesToBeDeactivated;
+			int64				fChangeCount;
+			BMessage			fLocationInfoReply;
 };
 
 

From bd59e0d00d58dadd5b5e0749b7edda0aefe61efe Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 16 Apr 2013 00:01:02 +0200
Subject: [PATCH 0413/1170] BPackageInfo: Fix Linux build

... including an actual bug (operator "|" instead of "||").
---
 src/kits/package/PackageInfo.cpp | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 6ff7cf9f79..a3e24332ec 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -14,6 +14,7 @@
 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -2145,8 +2146,8 @@ BPackageInfo::_ExtractResolvableExpressions(BMessage* archive,
 		error = archive->FindInt32(operatorField, i, &operatorType);
 		if (error != B_OK)
 			return error;
-		if (operatorType < 0 
-			| operatorType > B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT) {
+		if (operatorType < 0
+			|| operatorType > B_PACKAGE_RESOLVABLE_OP_ENUM_COUNT) {
 			return B_BAD_DATA;
 		}
 

From 202c1daaed2556eaccea80643e58d498594f2506 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 16 Apr 2013 00:05:19 +0200
Subject: [PATCH 0414/1170] BPackageVersion: Rename property release to
 revision

* ... to avoid confusion with the preRelease property. It's also called
  "revision" in the HaikuPorts recipes.
* Update libsolv package. Was necessary due to the BPackageVersion
  change, but also includes a few more changes.
---
 build/jam/OptionalBuildFeatures               |  2 +-
 headers/os/package/PackageInfo.h              |  2 +-
 headers/os/package/PackageInfoAttributes.h    |  3 +-
 headers/os/package/PackageVersion.h           | 14 +++---
 headers/os/package/hpkg/HPKGDefs.h            |  2 +-
 .../package/hpkg/PackageInfoAttributeValue.h  |  2 +-
 .../kernel/file_systems/packagefs/Package.cpp |  8 ++--
 .../kernel/file_systems/packagefs/Version.cpp | 18 ++++----
 .../kernel/file_systems/packagefs/Version.h   |  6 +--
 src/bin/package/command_list.cpp              |  4 +-
 src/bin/package_repo/command_list.cpp         |  4 +-
 src/kits/package/PackageInfo.cpp              | 44 +++++++++----------
 src/kits/package/PackageVersion.cpp           | 34 +++++++-------
 .../package/hpkg/PackageContentHandler.cpp    |  2 +-
 src/kits/package/hpkg/ReaderImplBase.cpp      |  4 +-
 src/kits/package/hpkg/WriterImplBase.cpp      | 12 ++---
 16 files changed, 82 insertions(+), 79 deletions(-)

diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures
index 50ac91e77e..d1227d9839 100644
--- a/build/jam/OptionalBuildFeatures
+++ b/build/jam/OptionalBuildFeatures
@@ -221,7 +221,7 @@ if $(TARGET_ARCH) != x86 {
 	Echo "Libsolv not available for $(TARGET_ARCH)." ;
 } else if $(HAIKU_GCC_VERSION[1]) = 2 {
 	HAIKU_LIBSOLV_PACKAGE
-		= libsolv-0.3.0_haiku_2013_04_01-1-x86_gcc2.hpkg ;
+		= libsolv-0.3.0_haiku_2013_04_15-1-x86_gcc2.hpkg ;
 } else {
 	Echo "Libsolv not available for gcc4." ;
 }
diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h
index 1a34a388f5..bdab0a868a 100644
--- a/headers/os/package/PackageInfo.h
+++ b/headers/os/package/PackageInfo.h
@@ -152,7 +152,7 @@ public:
 									BPackageArchitecture& _architecture);
 
 	static	status_t			ParseVersionString(const BString& string,
-									bool releaseIsOptional,
+									bool revisionIsOptional,
 									BPackageVersion& _version,
 									ParseErrorListener* listener = NULL);
 
diff --git a/headers/os/package/PackageInfoAttributes.h b/headers/os/package/PackageInfoAttributes.h
index f1b86018ae..56fa2ef7aa 100644
--- a/headers/os/package/PackageInfoAttributes.h
+++ b/headers/os/package/PackageInfoAttributes.h
@@ -16,7 +16,8 @@ enum BPackageInfoAttributeID {
 	B_PACKAGE_INFO_VENDOR,		// e.g. "Haiku Project"
 	B_PACKAGE_INFO_PACKAGER,	// e-mail address preferred
 	B_PACKAGE_INFO_ARCHITECTURE,
-	B_PACKAGE_INFO_VERSION,		// [.[.]][-
]-
+	B_PACKAGE_INFO_VERSION,		// [.[.]][-
]
+								//		-
 	B_PACKAGE_INFO_COPYRIGHTS,	// list
 	B_PACKAGE_INFO_LICENSES,	// list
 	B_PACKAGE_INFO_PROVIDES,	// list of resolvables this package provides,
diff --git a/headers/os/package/PackageVersion.h b/headers/os/package/PackageVersion.h
index 63a53f4d1d..f8b78b1b28 100644
--- a/headers/os/package/PackageVersion.h
+++ b/headers/os/package/PackageVersion.h
@@ -24,10 +24,10 @@ public:
 								BPackageVersion(
 									const BPackageVersionData& data);
 	explicit					BPackageVersion(const BString& versionString,
-									bool releaseIsOptional = true);
+									bool revisionIsOptional = true);
 								BPackageVersion(const BString& major,
 									const BString& minor, const BString& micro,
-									const BString& preRelease, uint8 release);
+									const BString& preRelease, uint32 revision);
 
 			status_t			InitCheck() const;
 
@@ -36,27 +36,27 @@ public:
 			const BString&		Micro() const;
 			const BString&		PreRelease() const;
 									// "alpha3", "beta2", "rc1" or "" if final
-			uint8				Release() const;
+			uint32				Revision() const;
 
 			BString				ToString() const;
 
 			void				SetTo(const BString& major,
 									const BString& minor, const BString& micro,
-									const BString& preRelease, uint8 release);
+									const BString& preRelease, uint32 revision);
 			status_t			SetTo(const BString& versionString,
-									bool releaseIsOptional = true);
+									bool revisionIsOptional = true);
 			void				Clear();
 
 			int					Compare(const BPackageVersion& other) const;
 									// does a natural compare over major, minor
-									// and micro, finally comparing release
+									// and micro, finally comparing revision
 
 private:
 			BString				fMajor;
 			BString				fMinor;
 			BString				fMicro;
 			BString				fPreRelease;
-			uint8				fRelease;
+			uint32				fRevision;
 };
 
 
diff --git a/headers/os/package/hpkg/HPKGDefs.h b/headers/os/package/hpkg/HPKGDefs.h
index f4e812ef74..5f45be9e34 100644
--- a/headers/os/package/hpkg/HPKGDefs.h
+++ b/headers/os/package/hpkg/HPKGDefs.h
@@ -110,7 +110,7 @@ enum BHPKGAttributeID {
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MAJOR		= 25,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MINOR		= 26,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_MICRO		= 27,
-	B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_RELEASE		= 28,
+	B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_REVISION	= 28,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_COPYRIGHT			= 29,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_LICENSE				= 30,
 	B_HPKG_ATTRIBUTE_ID_PACKAGE_PROVIDES			= 31,
diff --git a/headers/os/package/hpkg/PackageInfoAttributeValue.h b/headers/os/package/hpkg/PackageInfoAttributeValue.h
index 40055e08b3..b888a016a5 100644
--- a/headers/os/package/hpkg/PackageInfoAttributeValue.h
+++ b/headers/os/package/hpkg/PackageInfoAttributeValue.h
@@ -24,7 +24,7 @@ struct BPackageVersionData {
 			const char*			minor;
 			const char*			micro;
 			const char*			preRelease;
-			uint8				release;
+			uint32				revision;
 };
 
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Package.cpp b/src/add-ons/kernel/file_systems/packagefs/Package.cpp
index 721d3219f6..ee04cc662e 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Package.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Package.cpp
@@ -183,7 +183,7 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
 				::Version* version;
 				status_t error = Version::Create(value.version.major,
 					value.version.minor, value.version.micro,
-					value.version.preRelease, value.version.release, version);
+					value.version.preRelease, value.version.revision, version);
 				if (error != B_OK)
 					RETURN_ERROR(error);
 
@@ -209,7 +209,7 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
 						= value.resolvable.version;
 					status_t error = Version::Create(versionInfo.major,
 						versionInfo.minor, versionInfo.micro,
-						versionInfo.preRelease, versionInfo.release, version);
+						versionInfo.preRelease, versionInfo.revision, version);
 					if (error != B_OK)
 						RETURN_ERROR(error);
 				}
@@ -222,7 +222,7 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
 						= value.resolvable.compatibleVersion;
 					status_t error = Version::Create(versionInfo.major,
 						versionInfo.minor, versionInfo.micro,
-						versionInfo.preRelease, versionInfo.release,
+						versionInfo.preRelease, versionInfo.revision,
 						compatibleVersion);
 					if (error != B_OK)
 						RETURN_ERROR(error);
@@ -266,7 +266,7 @@ struct Package::LoaderContentHandler : BPackageContentHandler {
 						= value.resolvableExpression.version;
 					status_t error = Version::Create(versionInfo.major,
 						versionInfo.minor, versionInfo.micro,
-						versionInfo.preRelease, versionInfo.release, version);
+						versionInfo.preRelease, versionInfo.revision, version);
 					if (error != B_OK)
 						RETURN_ERROR(error);
 
diff --git a/src/add-ons/kernel/file_systems/packagefs/Version.cpp b/src/add-ons/kernel/file_systems/packagefs/Version.cpp
index a9b212959c..b5206bb5e2 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Version.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Version.cpp
@@ -39,7 +39,7 @@ Version::Version()
 	fMinor(NULL),
 	fMicro(NULL),
 	fPreRelease(NULL),
-	fRelease(0)
+	fRevision(0)
 {
 }
 
@@ -55,7 +55,7 @@ Version::~Version()
 
 status_t
 Version::Init(const char* major, const char* minor, const char* micro,
-	const char* preRelease, uint8 release)
+	const char* preRelease, uint32 revision)
 {
 	if (major != NULL) {
 		fMajor = strdup(major);
@@ -81,7 +81,7 @@ Version::Init(const char* major, const char* minor, const char* micro,
 			return B_NO_MEMORY;
 	}
 
-	fRelease = release;
+	fRevision = revision;
 
 	return B_OK;
 }
@@ -89,13 +89,13 @@ Version::Init(const char* major, const char* minor, const char* micro,
 
 /*static*/ status_t
 Version::Create(const char* major, const char* minor, const char* micro,
-	const char* preRelease, uint8 release, Version*& _version)
+	const char* preRelease, uint32 revision, Version*& _version)
 {
 	Version* version = new(std::nothrow) Version;
 	if (version == NULL)
 		return B_NO_MEMORY;
 
-	status_t error = version->Init(major, minor, micro, preRelease, release);
+	status_t error = version->Init(major, minor, micro, preRelease, revision);
 	if (error != B_OK) {
 		delete version;
 		return error;
@@ -136,7 +136,8 @@ Version::Compare(const Version& other) const
 			return cmp;
 	}
 
-	return (int)fRelease - other.fRelease;
+	return fRevision == other.fRevision
+		? 0 : (fRevision < other.fRevision ? -1 : 1);
 }
 
 
@@ -200,9 +201,10 @@ Version::ToString(char* buffer, size_t bufferSize) const
 			fPreRelease);
 	}
 
-	if (fRelease != 0) {
+	if (fRevision != 0) {
 		size_t offset = std::min(bufferSize, size);
-		size += snprintf(buffer + offset, bufferSize - offset, "-%u", fRelease);
+		size += snprintf(buffer + offset, bufferSize - offset, "-%" B_PRIu32,
+			fRevision);
 	}
 
 	return size;
diff --git a/src/add-ons/kernel/file_systems/packagefs/Version.h b/src/add-ons/kernel/file_systems/packagefs/Version.h
index a78beb0a03..8ce58af21f 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Version.h
+++ b/src/add-ons/kernel/file_systems/packagefs/Version.h
@@ -20,11 +20,11 @@ public:
 
 			status_t			Init(const char* major, const char* minor,
 									const char* micro, const char* preRelease,
-									uint8 release);
+									uint32 revision);
 
 	static	status_t			Create(const char* major, const char* minor,
 									const char* micro, const char* preRelease,
-									uint8 release, Version*& _version);
+									uint32 revision, Version*& _version);
 
 			int					Compare(const Version& other) const;
 			bool				Compare(BPackageResolvableOperator op,
@@ -39,7 +39,7 @@ private:
 			char*				fMinor;
 			char*				fMicro;
 			char*				fPreRelease;
-			uint8				fRelease;
+			uint32				fRevision;
 };
 
 
diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp
index 1cadda7c82..63569b16a0 100644
--- a/src/bin/package/command_list.cpp
+++ b/src/bin/package/command_list.cpp
@@ -272,8 +272,8 @@ private:
 			printf(".%s", version.micro);
 		if (version.preRelease != NULL && version.preRelease[0] != '\0')
 			printf("-%s", version.preRelease);
-		if (version.release > 0)
-			printf("-%d", version.release);
+		if (version.revision > 0)
+			printf("-%" B_PRIu32, version.revision);
 	}
 
 private:
diff --git a/src/bin/package_repo/command_list.cpp b/src/bin/package_repo/command_list.cpp
index ba2fe35af9..38d2842722 100644
--- a/src/bin/package_repo/command_list.cpp
+++ b/src/bin/package_repo/command_list.cpp
@@ -238,8 +238,8 @@ private:
 			printf(".%s", version.micro);
 		if (version.preRelease != NULL && version.preRelease[0] != '\0')
 			printf("-%s", version.preRelease);
-		if (version.release > 0)
-			printf("-%d", version.release);
+		if (version.revision > 0)
+			printf("-%" B_PRIu32, version.revision);
 	}
 
 private:
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index a3e24332ec..ed9d27f318 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -73,7 +73,7 @@ public:
 									BPackageInfo* packageInfo);
 
 			status_t			ParseVersion(const BString& versionString,
-									bool releaseIsOptional,
+									bool revisionIsOptional,
 									BPackageVersion& _version);
 
 private:
@@ -89,10 +89,10 @@ private:
 			void				_ParseArchitectureValue(
 									BPackageArchitecture* value);
 			void				_ParseVersionValue(BPackageVersion* value,
-									bool releaseIsOptional);
+									bool revisionIsOptional);
 	static	void				_ParseVersionValue(Token& word,
 									BPackageVersion* value,
-									bool releaseIsOptional);
+									bool revisionIsOptional);
 			void				_ParseList(ListElementParser& elementParser,
 									bool allowSingleNonListElement);
 			void				_ParseStringList(BStringList* value,
@@ -219,13 +219,13 @@ BPackageInfo::Parser::Parse(const BString& packageInfoString,
 
 status_t
 BPackageInfo::Parser::ParseVersion(const BString& versionString,
-	bool releaseIsOptional, BPackageVersion& _version)
+	bool revisionIsOptional, BPackageVersion& _version)
 {
 	fPos = versionString.String();
 
 	try {
 		Token token(TOKEN_WORD, fPos, versionString.Length());
-		_ParseVersionValue(token, &_version, releaseIsOptional);
+		_ParseVersionValue(token, &_version, revisionIsOptional);
 	} catch (const ParseError& error) {
 		if (fListener != NULL) {
 			int32 offset = error.pos - versionString.String();
@@ -393,41 +393,41 @@ BPackageInfo::Parser::_ParseArchitectureValue(BPackageArchitecture* value)
 
 void
 BPackageInfo::Parser::_ParseVersionValue(BPackageVersion* value,
-	bool releaseIsOptional)
+	bool revisionIsOptional)
 {
 	Token word = _NextToken();
-	_ParseVersionValue(word, value, releaseIsOptional);
+	_ParseVersionValue(word, value, revisionIsOptional);
 }
 
 
 /*static*/ void
 BPackageInfo::Parser::_ParseVersionValue(Token& word, BPackageVersion* value,
-	bool releaseIsOptional)
+	bool revisionIsOptional)
 {
 	if (word.type != TOKEN_WORD)
 		throw ParseError("expected word (a version)", word.pos);
 
-	// get the release number
-	uint8 release = 0;
+	// get the revision number
+	uint32 revision = 0;
 	int32 lastDashPos = word.text.FindLast('-');
 	if (lastDashPos >= 0) {
-		// Might be either the release number or, if that is optional, a
+		// Might be either the revision number or, if that is optional, a
 		// pre-release. The former always is a number, the latter starts with a
 		// non-digit.
 		if (isdigit(word.text[lastDashPos + 1])) {
 			int number = atoi(word.text.String() + lastDashPos + 1);
-			if (number <= 0 || number > 99) {
-				throw ParseError("release number must be from 1-99",
+			if (number <= 0) {
+				throw ParseError("revision number must be > 0",
 					word.pos + word.text.Length());
 			}
-			release = number;
+			revision = number;
 			word.text.Truncate(lastDashPos);
 			lastDashPos = word.text.FindLast('-');
 		}
 	}
 
-	if (release == 0 && !releaseIsOptional) {
-		throw ParseError("expected release number (- suffix)",
+	if (revision == 0 && !revisionIsOptional) {
+		throw ParseError("expected revision number (- suffix)",
 			word.pos + word.text.Length());
 	}
 
@@ -465,7 +465,7 @@ BPackageInfo::Parser::_ParseVersionValue(Token& word, BPackageVersion* value,
 		}
 	}
 
-	value->SetTo(major, minor, micro, preRelease, release);
+	value->SetTo(major, minor, micro, preRelease, revision);
 }
 
 
@@ -1831,10 +1831,10 @@ BPackageInfo::GetArchitectureByName(const BString& name,
 
 
 /*static*/ status_t
-BPackageInfo::ParseVersionString(const BString& string, bool releaseIsOptional,
+BPackageInfo::ParseVersionString(const BString& string, bool revisionIsOptional,
 	BPackageVersion& _version, ParseErrorListener* listener)
 {
-	return Parser(listener).ParseVersion(string, releaseIsOptional, _version);
+	return Parser(listener).ParseVersion(string, revisionIsOptional, _version);
 }
 
 
@@ -1884,7 +1884,7 @@ BPackageInfo::_AddVersion(BMessage* archive, const char* field,
 	if (!fieldName.ReplaceSuffix(fieldLength, ":revision"))
 		return B_BAD_VALUE;
 
-	return archive->AddUInt8(fieldName, version.Release());
+	return archive->AddUInt32(fieldName, version.Revision());
 }
 
 
@@ -2016,8 +2016,8 @@ BPackageInfo::_ExtractVersion(BMessage* archive, const char* field, int32 index,
 	if (!fieldName.ReplaceSuffix(fieldLength, ":revision"))
 		return B_BAD_VALUE;
 
-	uint8 revision;
-	error = archive->FindUInt8(fieldName, index, &revision);
+	uint32 revision;
+	error = archive->FindUInt32(fieldName, index, &revision);
 	if (error != B_OK)
 		return error;
 
diff --git a/src/kits/package/PackageVersion.cpp b/src/kits/package/PackageVersion.cpp
index 6b0de38a41..6aedbad07e 100644
--- a/src/kits/package/PackageVersion.cpp
+++ b/src/kits/package/PackageVersion.cpp
@@ -20,28 +20,28 @@ namespace BPackageKit {
 
 BPackageVersion::BPackageVersion()
 	:
-	fRelease(0)
+	fRevision(0)
 {
 }
 
 
 BPackageVersion::BPackageVersion(const BPackageVersionData& data)
 {
-	SetTo(data.major, data.minor, data.micro, data.preRelease, data.release);
+	SetTo(data.major, data.minor, data.micro, data.preRelease, data.revision);
 }
 
 
 BPackageVersion::BPackageVersion(const BString& versionString,
-	bool releaseIsOptional)
+	bool revisionIsOptional)
 {
-	SetTo(versionString, releaseIsOptional);
+	SetTo(versionString, revisionIsOptional);
 }
 
 
 BPackageVersion::BPackageVersion(const BString& major, const BString& minor,
-	const BString& micro, const BString& preRelease, uint8 release)
+	const BString& micro, const BString& preRelease, uint32 revision)
 {
-	SetTo(major, minor, micro, preRelease, release);
+	SetTo(major, minor, micro, preRelease, revision);
 }
 
 
@@ -80,10 +80,10 @@ BPackageVersion::PreRelease() const
 }
 
 
-uint8
-BPackageVersion::Release() const
+uint32
+BPackageVersion::Revision() const
 {
-	return fRelease;
+	return fRevision;
 }
 
 
@@ -117,7 +117,7 @@ BPackageVersion::Compare(const BPackageVersion& other) const
 			return diff;
 	}
 
-	return (int)fRelease - (int)other.fRelease;
+	return (int)fRevision - (int)other.fRevision;
 }
 
 
@@ -135,8 +135,8 @@ BPackageVersion::ToString() const
 	if (!fPreRelease.IsEmpty())
 		string << '-' << fPreRelease;
 
-	if (fRelease > 0)
-		string << '-' << fRelease;
+	if (fRevision > 0)
+		string << '-' << fRevision;
 
 	return string;
 }
@@ -144,13 +144,13 @@ BPackageVersion::ToString() const
 
 void
 BPackageVersion::SetTo(const BString& major, const BString& minor,
-	const BString& micro, const BString& preRelease, uint8 release)
+	const BString& micro, const BString& preRelease, uint32 revision)
 {
 	fMajor = major;
 	fMinor = minor;
 	fMicro = micro;
 	fPreRelease = preRelease;
-	fRelease = release;
+	fRevision = revision;
 
 	fMajor.ToLower();
 	fMinor.ToLower();
@@ -160,10 +160,10 @@ BPackageVersion::SetTo(const BString& major, const BString& minor,
 
 
 status_t
-BPackageVersion::SetTo(const BString& versionString, bool releaseIsOptional)
+BPackageVersion::SetTo(const BString& versionString, bool revisionIsOptional)
 {
 	Clear();
-	return BPackageInfo::ParseVersionString(versionString, releaseIsOptional,
+	return BPackageInfo::ParseVersionString(versionString, revisionIsOptional,
 		*this);
 }
 
@@ -175,7 +175,7 @@ BPackageVersion::Clear()
 	fMinor.Truncate(0);
 	fMicro.Truncate(0);
 	fPreRelease.Truncate(0);
-	fRelease = 0;
+	fRevision = 0;
 }
 
 
diff --git a/src/kits/package/hpkg/PackageContentHandler.cpp b/src/kits/package/hpkg/PackageContentHandler.cpp
index 418e84bf5d..c44f0b5e46 100644
--- a/src/kits/package/hpkg/PackageContentHandler.cpp
+++ b/src/kits/package/hpkg/PackageContentHandler.cpp
@@ -44,7 +44,7 @@ static const char* kAttributeNames[B_HPKG_ATTRIBUTE_ID_ENUM_COUNT + 1] = {
 	"package:version.major",
 	"package:version.minor",
 	"package:version.micro",
-	"package:version.release",
+	"package:version.revision",
 	"package:copyright",
 	"package:license",
 	"package:provides",
diff --git a/src/kits/package/hpkg/ReaderImplBase.cpp b/src/kits/package/hpkg/ReaderImplBase.cpp
index 150c3d12bf..2f8c733679 100644
--- a/src/kits/package/hpkg/ReaderImplBase.cpp
+++ b/src/kits/package/hpkg/ReaderImplBase.cpp
@@ -135,8 +135,8 @@ ReaderImplBase::PackageVersionAttributeHandler::HandleAttribute(
 			fPackageVersionData.preRelease = value.string;
 			break;
 
-		case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_RELEASE:
-			fPackageVersionData.release = value.unsignedInt;
+		case B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_REVISION:
+			fPackageVersionData.revision = value.unsignedInt;
 			break;
 
 		default:
diff --git a/src/kits/package/hpkg/WriterImplBase.cpp b/src/kits/package/hpkg/WriterImplBase.cpp
index b5b01840a7..9b85cd16f8 100644
--- a/src/kits/package/hpkg/WriterImplBase.cpp
+++ b/src/kits/package/hpkg/WriterImplBase.cpp
@@ -577,12 +577,12 @@ WriterImplBase::RegisterPackageVersion(PackageAttributeList& attributeList,
 		versionMajor->children.Add(preRelease);
 	}
 
-	if (version.Release() != 0) {
-		PackageAttribute* versionRelease = new PackageAttribute(
-			B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_RELEASE,
-			B_HPKG_ATTRIBUTE_TYPE_UINT, B_HPKG_ATTRIBUTE_ENCODING_INT_8_BIT);
-		versionRelease->unsignedInt = version.Release();
-		versionMajor->children.Add(versionRelease);
+	if (version.Revision() != 0) {
+		PackageAttribute* versionRevision = new PackageAttribute(
+			B_HPKG_ATTRIBUTE_ID_PACKAGE_VERSION_REVISION,
+			B_HPKG_ATTRIBUTE_TYPE_UINT, B_HPKG_ATTRIBUTE_ENCODING_INT_32_BIT);
+		versionRevision->unsignedInt = version.Revision();
+		versionMajor->children.Add(versionRevision);
 	}
 }
 

From e7563b87c715320be9d10225ceff110844e84a90 Mon Sep 17 00:00:00 2001
From: Oliver Tappe 
Date: Tue, 16 Apr 2013 11:18:44 +0200
Subject: [PATCH 0415/1170] Updated several base packages

---
 build/jam/OptionalBuildFeatures |  2 +-
 build/jam/OptionalPackages      | 62 ++++++++++++++++-----------------
 2 files changed, 32 insertions(+), 32 deletions(-)

diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures
index d1227d9839..a3e087d068 100644
--- a/build/jam/OptionalBuildFeatures
+++ b/build/jam/OptionalBuildFeatures
@@ -14,7 +14,7 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSL ] {
 if $(HAIKU_GCC_VERSION[1]) >= 4 {
 	HAIKU_OPENSSL_PACKAGE = openssl-1.0.0e-x86-gcc4-2011-09-08.zip ;
 } else {
-	HAIKU_OPENSSL_PACKAGE = openssl-1.0.0d-2-x86_gcc2.hpkg ;
+	HAIKU_OPENSSL_PACKAGE = openssl-1.0.0d-3-x86_gcc2.hpkg ;
 }
 
 local baseURL = http://haiku-files.org/files/optional-packages ;
diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index e820993970..82fc494b77 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -114,8 +114,8 @@ if [ IsOptionalHaikuImagePackageAdded APR ] {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			apr-1.4.2-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/apr-1.4.2-2-x86_gcc2.hpkg
+			apr-1.4.2-3-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/apr-1.4.2-3-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -132,8 +132,8 @@ if [ IsOptionalHaikuImagePackageAdded APR-util ] {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			apr-util-1.3.10-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/apr-util-1.3.10-2-x86_gcc2.hpkg
+			apr-util-1.3.10-3-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/apr-util-1.3.10-3-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -497,16 +497,16 @@ if [ IsOptionalHaikuImagePackageAdded Development ] && $(TARGET_ARCH) = x86 {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			autoconf-2.68-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/autoconf-2.68-2-x86_gcc2.hpkg
+			autoconf-2.68-3-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/autoconf-2.68-3-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			automake-1.11.1-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/automake-1.11.1-2-x86_gcc2.hpkg
+			automake-1.11.1-3-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/automake-1.11.1-3-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
 			libtool-2.4-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/libtool-2.4-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/libtool-2.4-3-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
 			texinfo-4.13a-2-x86_gcc2.hpkg
@@ -521,8 +521,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 		&& $(TARGET_ARCH) = x86 {
 	# gcc and binutils
 	if $(HAIKU_GCC_VERSION[1]) = 2 {
-		InstallOptionalHaikuImagePackage gcc-2.95.3_110711-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/gcc-2.95.3_110711-2-x86_gcc2.hpkg
+		InstallOptionalHaikuImagePackage gcc-2.95.3_110711-4-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/gcc-2.95.3_110711-4-x86_gcc2.hpkg
 			: common packages ;
 
 		# TODO: remove this when we have a mechanism to switch gcc via PATH
@@ -563,8 +563,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 			: $(hpkgBaseURL)/bison-2.4.3-2-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			m4-1.4.16-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/m4-1.4.16-2-x86_gcc2.hpkg
+			m4-1.4.16-3-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/m4-1.4.16-3-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
 			flex-2.5.35-2-x86_gcc2.hpkg
@@ -579,8 +579,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 			: $(hpkgBaseURL)/mkdepend-1.7-1-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			make-3.82-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/make-3.82-2-x86_gcc2.hpkg
+			make-3.82-3-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/make-3.82-3-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -668,8 +668,8 @@ if [ IsOptionalHaikuImagePackageAdded Expat ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				expat-2.0.1-2-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/expat-2.0.1-2-x86_gcc2.hpkg
+				expat-2.0.1-3-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/expat-2.0.1-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -942,8 +942,8 @@ if [ IsOptionalHaikuImagePackageAdded LibXML2 ] {
 				: $(baseURL)/libxml2-2.7.8-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				libxml2-2.7.8-2-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/libxml2-2.7.8-2-x86_gcc2.hpkg
+				libxml2-2.7.8-3-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/libxml2-2.7.8-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1074,8 +1074,8 @@ if [ IsOptionalHaikuImagePackageAdded Neon ] {
 				: $(baseURL)/neon-0.29.6-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				neon-0.29.6-2-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/neon-0.29.6-2-x86_gcc2.hpkg
+				neon-0.29.6-3-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/neon-0.29.6-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1301,8 +1301,8 @@ if [ IsOptionalHaikuImagePackageAdded Perl ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				perl-5.10.1-2-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/perl-5.10.1-2-x86_gcc2.hpkg
+				perl-5.10.1-3-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/perl-5.10.1-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1375,8 +1375,8 @@ if [ IsOptionalHaikuImagePackageAdded Sed ] {
 			: $(baseURL)/sed-4.2.1-r1a3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			sed-4.2.1-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/sed-4.2.1-1-x86_gcc2.hpkg
+			sed-4.2.1-2-x86_gcc2.hpkg
+			: $(hpkgBaseURL)/sed-4.2.1-2-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -1393,8 +1393,8 @@ if [ IsOptionalHaikuImagePackageAdded SQLite ] {
 				: $(baseURL)/sqlite-3.7.5-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				sqlite-3.7.5-3-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/sqlite-3.7.5-3-x86_gcc2.hpkg
+				sqlite-3.7.5-4-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/sqlite-3.7.5-4-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1413,8 +1413,8 @@ if [ IsOptionalHaikuImagePackageAdded Subversion ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				subversion-1.6.15-2-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/subversion-1.6.15-2-x86_gcc2.hpkg
+				subversion-1.6.15-3-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/subversion-1.6.15-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1448,8 +1448,8 @@ if [ IsOptionalHaikuImagePackageAdded Tar ] {
 				: $(baseURL)/tar-1.25-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				tar-1.25-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/tar-1.25-1-x86_gcc2.hpkg
+				tar-1.26-2-x86_gcc2.hpkg
+				: $(hpkgBaseURL)/tar-1.26-2-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}

From 6185f6e7cc2c1df89a32b9fc82a315b69ae98629 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 16 Apr 2013 13:45:33 +0200
Subject: [PATCH 0416/1170] Fix libtool file name

---
 build/jam/OptionalPackages | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 82fc494b77..3f84fc3490 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -505,7 +505,7 @@ if [ IsOptionalHaikuImagePackageAdded Development ] && $(TARGET_ARCH) = x86 {
 			: $(hpkgBaseURL)/automake-1.11.1-3-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			libtool-2.4-2-x86_gcc2.hpkg
+			libtool-2.4-3-x86_gcc2.hpkg
 			: $(hpkgBaseURL)/libtool-2.4-3-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage

From 88f22c9768e3a7d5bd439800b2f6d479a369d745 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 16 Apr 2013 14:39:31 +0200
Subject: [PATCH 0417/1170] InstallOptionalHaikuImagePackage: Remove first
 parameter

Instead deduce the file name from the URL. A long overdue change. Avoids
unnecessary name duplication, which only led to errors.
---
 build/jam/ImageRules          |   4 +-
 build/jam/OptionalLibPackages | 183 +++++--------
 build/jam/OptionalPackages    | 480 ++++++++++++----------------------
 3 files changed, 237 insertions(+), 430 deletions(-)

diff --git a/build/jam/ImageRules b/build/jam/ImageRules
index 0b0a34746e..2420a1e934 100644
--- a/build/jam/ImageRules
+++ b/build/jam/ImageRules
@@ -920,8 +920,10 @@ rule InstallSourceArchive file : url
 	}
 }
 
-rule InstallOptionalHaikuImagePackage package : url : dirTokens : isCDPackage
+rule InstallOptionalHaikuImagePackage url : dirTokens : isCDPackage
 {
+	local package = $(url:BS) ;
+
 	# download archive file
 	local archiveFile = [ DownloadFile $(package) : $(url) ] ;
 
diff --git a/build/jam/OptionalLibPackages b/build/jam/OptionalLibPackages
index 1a568121aa..56d45a0fe7 100644
--- a/build/jam/OptionalLibPackages
+++ b/build/jam/OptionalLibPackages
@@ -29,24 +29,18 @@ if [ IsOptionalHaikuImagePackageAdded AllegroLibs ] {
 		Echo "No optional package AllegroLibs available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			allegro-4.4.1.1-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/allegro-4.4.1.1-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/allegro-4.4.1.1-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			dumb-0.9.3-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/dumb-0.9.3-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/dumb-0.9.3-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			jgmod-0.99-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/jgmod-0.99-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/jgmod-0.99-r1a3-x86-gcc4-2011-05-26.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			allegro-4.4.1.1-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/allegro-4.4.1.1-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/allegro-4.4.1.1-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			dumb-0.9.3-x86-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/dumb-0.9.3-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/dumb-0.9.3-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			jgmod-0.99-x86-gcc2-2011-08-02.zip
-			: $(baseURL)/lib/jgmod-0.99-x86-gcc2-2011-08-02.zip ;
+			$(baseURL)/lib/jgmod-0.99-x86-gcc2-2011-08-02.zip ;
 	}
 }
 
@@ -58,8 +52,7 @@ if [ IsOptionalHaikuImagePackageAdded box2d ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				box2d-2.1.2-r1a3-r1a3-x86-gcc4-2011-05-26.zip
-				: $(baseURL)/lib/box2d-2.1.2-r1a3-x86-gcc4-2011-05-26.zip
+				$(baseURL)/lib/box2d-2.1.2-r1a3-x86-gcc4-2011-05-26.zip
 				: : true ;
 		} else {
 			Echo "No optional package box2d available for $(TARGET_ARCH)-gcc2" ;
@@ -74,13 +67,11 @@ if [ IsOptionalHaikuImagePackageAdded fribidi ] {
 		Echo "No optional package fribidi available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			fribidi-0.19.2-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/fribidi-0.19.2-r1a3-x86-gcc4-2011-05-26.zip
+			$(baseURL)/lib/fribidi-0.19.2-r1a3-x86-gcc4-2011-05-26.zip
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			fribidi-0.19.2-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/fribidi-0.19.2-r1a3-x86-gcc2-2011-05-19.zip
+			$(baseURL)/lib/fribidi-0.19.2-r1a3-x86-gcc2-2011-05-19.zip
 			: : true ;
 	}
 }
@@ -92,13 +83,11 @@ if [ IsOptionalHaikuImagePackageAdded lcms ] {
 		Echo "No optional package lcms available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			lcms-2.1-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/lcms-2.1-r1a3-x86-gcc4-2011-05-26.zip
+			$(baseURL)/lib/lcms-2.1-r1a3-x86-gcc4-2011-05-26.zip
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			lcms-2.1-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/lcms-2.1-r1a3-x86-gcc2-2011-05-19.zip
+			$(baseURL)/lib/lcms-2.1-r1a3-x86-gcc2-2011-05-19.zip
 			: : true ;
 	}
 }
@@ -110,13 +99,11 @@ if [ IsOptionalHaikuImagePackageAdded libart_lgpl ] {
 		Echo "No optional package libart_lgpl available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			libart_lgpl-2.3.21-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/libart_lgpl-2.3.21-r1a3-x86-gcc4-2011-05-26.zip
+			$(baseURL)/lib/libart_lgpl-2.3.21-r1a3-x86-gcc4-2011-05-26.zip
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			libart_lgpl-2.3.21-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/libart_lgpl-2.3.21-r1a3-x86-gcc2-2011-05-19.zip
+			$(baseURL)/lib/libart_lgpl-2.3.21-r1a3-x86-gcc2-2011-05-19.zip
 			: : true ;
 	}
 }
@@ -128,13 +115,11 @@ if [ IsOptionalHaikuImagePackageAdded libmad ] {
 		Echo "No optional package libmad available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			libmad-0.15.1b-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/libmad-0.15.1b-r1a3-x86-gcc4-2011-05-26.zip
+			$(baseURL)/lib/libmad-0.15.1b-r1a3-x86-gcc4-2011-05-26.zip
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			libmad-0.15.1b-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/libmad-0.15.1b-r1a3-x86-gcc2-2011-05-19.zip
+			$(baseURL)/lib/libmad-0.15.1b-r1a3-x86-gcc2-2011-05-19.zip
 			: : true ;
 	}
 }
@@ -146,13 +131,11 @@ if [ IsOptionalHaikuImagePackageAdded libmikmod ] {
 		Echo "No optional package libmikmod available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			libmikmod-3.1.11-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/libmikmod-3.1.11-r1a3-x86-gcc4-2011-05-26.zip
+			$(baseURL)/lib/libmikmod-3.1.11-r1a3-x86-gcc4-2011-05-26.zip
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			libmikmod-3.1.11-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/libmikmod-3.1.11-r1a3-x86-gcc2-2011-05-19.zip
+			$(baseURL)/lib/libmikmod-3.1.11-r1a3-x86-gcc2-2011-05-19.zip
 			: : true ;
 	}
 }
@@ -164,13 +147,11 @@ if [ IsOptionalHaikuImagePackageAdded libmodplug ] {
 		Echo "No optional package libmodplug available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			libmodplug-0.8.8.1-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/libmodplug-0.8.8.1-r1a3-x86-gcc4-2011-05-26.zip
+			$(baseURL)/lib/libmodplug-0.8.8.1-r1a3-x86-gcc4-2011-05-26.zip
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			libmodplug-0.8.8.1-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/libmodplug-0.8.8.1-r1a3-x86-gcc2-2011-05-19.zip
+			$(baseURL)/lib/libmodplug-0.8.8.1-r1a3-x86-gcc2-2011-05-19.zip
 			: : true ;
 	}
 }
@@ -182,13 +163,11 @@ if [ IsOptionalHaikuImagePackageAdded libpaper ] {
 		Echo "No optional package libpaper available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			libpaper-1.1.24-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/libpaper-1.1.24-r1a3-x86-gcc4-2011-05-26.zip
+			$(baseURL)/lib/libpaper-1.1.24-r1a3-x86-gcc4-2011-05-26.zip
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			libpaper-1.1.24-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/libpaper-1.1.24-r1a3-x86-gcc2-2011-05-19.zip
+			$(baseURL)/lib/libpaper-1.1.24-r1a3-x86-gcc2-2011-05-19.zip
 			: : true ;
 	}
 }
@@ -200,13 +179,11 @@ if [ IsOptionalHaikuImagePackageAdded physfs ] {
 		Echo "No optional package physfs available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			physfs-2.0.1-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/physfs-2.0.1-r1a3-x86-gcc4-2011-05-26.zip
+			$(baseURL)/lib/physfs-2.0.1-r1a3-x86-gcc4-2011-05-26.zip
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			physfs-2.0.1-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/physfs-2.0.1-r1a3-x86-gcc2-2011-05-19.zip
+			$(baseURL)/lib/physfs-2.0.1-r1a3-x86-gcc2-2011-05-19.zip
 			: : true ;
 	}
 }
@@ -218,78 +195,54 @@ if [ IsOptionalHaikuImagePackageAdded SDLLibs ] {
 		Echo "No optional package SDLLibs available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			libsdl-1.2-hg-r1a3-x86-gcc4-2011-05-29.zip
-			: $(baseURL)/lib/libsdl-1.2-hg-r1a3-x86-gcc4-2011-05-29.zip ;
+			$(baseURL)/lib/libsdl-1.2-hg-r1a3-x86-gcc4-2011-05-29.zip ;
 		InstallOptionalHaikuImagePackage
-			guilib-1.2.1-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/guilib-1.2.1-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/guilib-1.2.1-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-gfx-2.0.22-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/sdl-gfx-2.0.22-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/sdl-gfx-2.0.22-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-image-1.2.10-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/sdl-image-1.2.10-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/sdl-image-1.2.10-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-mixer-1.2.11-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/sdl-mixer-1.2.11-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/sdl-mixer-1.2.11-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-net-1.2.7-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/sdl-net-1.2.7-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/sdl-net-1.2.7-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-sound-1.0.3-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/sdl-sound-1.0.3-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/sdl-sound-1.0.3-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-rtf-0.1.0-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/sdl-rtf-0.1.0-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/sdl-rtf-0.1.0-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-ttf-2.0.10-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/sdl-ttf-2.0.10-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/sdl-ttf-2.0.10-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			sge-030809-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/sge-030809-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/sge-030809-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			smjpeg-0.2.1-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/smjpeg-0.2.1-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/smjpeg-0.2.1-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			smpeg-0.4.5-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/smpeg-0.4.5-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/smpeg-0.4.5-r1a3-x86-gcc4-2011-05-26.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			libsdl-1.2-hg-r1a3-x86-gcc2-2011-05-29.zip
-			: $(baseURL)/lib/libsdl-1.2-hg-r1a3-x86-gcc2-2011-05-29.zip ;
+			$(baseURL)/lib/libsdl-1.2-hg-r1a3-x86-gcc2-2011-05-29.zip ;
 		InstallOptionalHaikuImagePackage
-			guilib-1.2.1-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/guilib-1.2.1-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/guilib-1.2.1-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-gfx-2.0.22-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/sdl-gfx-2.0.22-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/sdl-gfx-2.0.22-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-image-1.2.10-x86-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/sdl-image-1.2.10-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/sdl-image-1.2.10-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-mixer-1.2.11-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/sdl-mixer-1.2.11-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/sdl-mixer-1.2.11-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-net-1.2.7-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/sdl-net-1.2.7-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/sdl-net-1.2.7-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-sound-1.0.3-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/sdl-sound-1.0.3-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/sdl-sound-1.0.3-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-rtf-0.1.0-r1a3-x86-gcc2-2011-05-20.zip
-			: $(baseURL)/lib/sdl-rtf-0.1.0-r1a3-x86-gcc2-2011-05-20.zip ;
+			$(baseURL)/lib/sdl-rtf-0.1.0-r1a3-x86-gcc2-2011-05-20.zip ;
 		InstallOptionalHaikuImagePackage
-			sdl-ttf-2.0.10-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/sdl-ttf-2.0.10-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/sdl-ttf-2.0.10-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			sge-030809-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/sge-030809-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/sge-030809-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			smjpeg-0.2.1-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/smjpeg-0.2.1-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/smjpeg-0.2.1-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			smpeg-0.4.5-r1a3-x86-gcc2-2011-05-20.zip
-			: $(baseURL)/lib/smpeg-0.4.5-r1a3-x86-gcc2-2011-05-20.zip ;
+			$(baseURL)/lib/smpeg-0.4.5-r1a3-x86-gcc2-2011-05-20.zip ;
 	}
 }
 
@@ -300,48 +253,34 @@ if [ IsOptionalHaikuImagePackageAdded XiphLibs ] {
 		Echo "No optional package XiphLibs available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			flac-1.2.1-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/flac-1.2.1-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/flac-1.2.1-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			libao-1.0.0-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/libao-1.0.0-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/libao-1.0.0-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			libogg-1.2.2-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/libogg-1.2.2-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/libogg-1.2.2-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			libtheora-1.1.1-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/libtheora-1.1.1-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/libtheora-1.1.1-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			libvorbis-1.3.2-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/libvorbis-1.3.2-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/libvorbis-1.3.2-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			speex-1.2-git-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/speex-1.2-git-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/speex-1.2-git-r1a3-x86-gcc4-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			vorbis-tools-1.4.0-r1a3-x86-gcc4-2011-05-26.zip
-			: $(baseURL)/lib/vorbis-tools-1.4.0-r1a3-x86-gcc4-2011-05-26.zip ;
+			$(baseURL)/lib/vorbis-tools-1.4.0-r1a3-x86-gcc4-2011-05-26.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			flac-1.2.1-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/flac-1.2.1-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/flac-1.2.1-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			libao-1.0.0-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/libao-1.0.0-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/libao-1.0.0-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			libogg-1.2.2-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/libogg-1.2.2-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/libogg-1.2.2-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			libtheora-1.1.1-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/libtheora-1.1.1-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/libtheora-1.1.1-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			libvorbis-1.3.2-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/libvorbis-1.3.2-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/libvorbis-1.3.2-r1a3-x86-gcc2-2011-05-19.zip ;
 		InstallOptionalHaikuImagePackage
-			speex-1.2-git-r1a3-x86-gcc2-2011-05-26.zip
-			: $(baseURL)/lib/speex-1.2-git-r1a3-x86-gcc2-2011-05-26.zip ;
+			$(baseURL)/lib/speex-1.2-git-r1a3-x86-gcc2-2011-05-26.zip ;
 		InstallOptionalHaikuImagePackage
-			vorbis-tools-1.4.0-r1a3-x86-gcc2-2011-05-19.zip
-			: $(baseURL)/lib/vorbis-tools-1.4.0-r1a3-x86-gcc2-2011-05-19.zip ;
+			$(baseURL)/lib/vorbis-tools-1.4.0-r1a3-x86-gcc2-2011-05-19.zip ;
 	}
 }
 
diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 3f84fc3490..d31636966c 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -97,8 +97,7 @@ if [ IsOptionalHaikuImagePackageAdded ABI-compliance-checker ] {
 		Echo "No optional package ABI-compliance-checker for gcc2" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			ABI-compliance-checker-1.12-noarch-gcc4-2010-02-01.zip
-			: $(baseURL)/ABI-compliance-checker-1.12-noarch-gcc4-2010-02-01.zip ;
+			$(baseURL)/ABI-compliance-checker-1.12-noarch-gcc4-2010-02-01.zip ;
 	}
 }
 
@@ -109,13 +108,11 @@ if [ IsOptionalHaikuImagePackageAdded APR ] {
 		Echo "No optional package APR available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			apr-1.4.2-r1a3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/apr-1.4.2-r1a3-x86-gcc4-2011-05-24.zip
+			$(baseURL)/apr-1.4.2-r1a3-x86-gcc4-2011-05-24.zip
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			apr-1.4.2-3-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/apr-1.4.2-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/apr-1.4.2-3-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -127,13 +124,11 @@ if [ IsOptionalHaikuImagePackageAdded APR-util ] {
 		Echo "No optional package APR-util available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			apr-util-1.3.10-r1a3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/apr-util-1.3.10-r1a3-x86-gcc4-2011-05-24.zip
+			$(baseURL)/apr-util-1.3.10-r1a3-x86-gcc4-2011-05-24.zip
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			apr-util-1.3.10-3-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/apr-util-1.3.10-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/apr-util-1.3.10-3-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -147,8 +142,7 @@ if [ IsOptionalHaikuImagePackageAdded ArmyKnife ] {
 		Echo "No optional package ArmyKnife for gcc4" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			armyknife-63-r1a3-x86-gcc2-2011-06-04.zip
-			: $(baseURL)/armyknife-63-r1a3-x86-gcc2-2011-06-04.zip ;
+			$(baseURL)/armyknife-63-r1a3-x86-gcc2-2011-06-04.zip ;
 		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/ArmyKnife/ArmyKnife ;
 	}
@@ -160,11 +154,11 @@ if [ IsOptionalHaikuImagePackageAdded Bazaar ] {
 	if $(TARGET_ARCH) != x86 {
 		Echo "No optional package Bazaar available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
-		InstallOptionalHaikuImagePackage bzr-2.2.2-r1a3-x86-gcc4-2011-05-23.zip
-			: $(baseURL)/bzr-2.2.2-r1a3-x86-gcc4-2011-05-23.zip ;
+		InstallOptionalHaikuImagePackage
+			$(baseURL)/bzr-2.2.2-r1a3-x86-gcc4-2011-05-23.zip ;
 	} else {
-		InstallOptionalHaikuImagePackage bzr-2.2.2-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/bzr-2.2.2-r1a3-x86-gcc2-2011-05-17.zip ;
+		InstallOptionalHaikuImagePackage
+			$(baseURL)/bzr-2.2.2-r1a3-x86-gcc2-2011-05-17.zip ;
 	}
 }
 
@@ -176,12 +170,10 @@ if [ IsOptionalHaikuImagePackageAdded BeAE ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				beae-22-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/beae-22-r1a3-x86-gcc4-2011-05-24.zip ;
+				$(baseURL)/beae-22-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				beae-22-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/beae-22-r1a3-x86-gcc2-2011-05-18.zip ;
+				$(baseURL)/beae-22-r1a3-x86-gcc2-2011-05-18.zip ;
 		}
 		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/BeAE/BeAE ;
@@ -196,8 +188,8 @@ if [ IsOptionalHaikuImagePackageAdded Beam ] {
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		Echo "No optional package Beam available for gcc4" ;
 	} else {
-		InstallOptionalHaikuImagePackage Beam-1.2alpha-x86-gcc2-2010-04-29.zip
-			: $(baseURL)/Beam-1.2alpha-x86-gcc2-2010-04-29.zip ;
+		InstallOptionalHaikuImagePackage
+			$(baseURL)/Beam-1.2alpha-x86-gcc2-2010-04-29.zip ;
 		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/Beam/Beam ;
 	}
@@ -206,8 +198,8 @@ if [ IsOptionalHaikuImagePackageAdded Beam ] {
 
 # BeBook
 if [ IsOptionalHaikuImagePackageAdded BeBook ] {
-	InstallOptionalHaikuImagePackage bebook-2008-10-26-1.hpkg
-		: $(hpkgBaseURL)/bebook-2008-10-26-1.hpkg
+	InstallOptionalHaikuImagePackage
+		$(hpkgBaseURL)/bebook-2008-10-26-1.hpkg
 		: system packages ;
 	AddSymlinkToHaikuImage home Desktop
 		: /boot/system/documentation/bebook/index.html
@@ -257,8 +249,7 @@ if [ IsOptionalHaikuImagePackageAdded BePDF ] {
 		Echo "No optional package BePDF available for gcc4" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			bepdf-1.1.1b4-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/bepdf-1.1.1b4-1-x86_gcc2.hpkg
+			$(hpkgBaseURL)/bepdf-1.1.1b4-1-x86_gcc2.hpkg
 			: common packages ;
 		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/BePDF/BePDF ;
@@ -273,12 +264,10 @@ if [ IsOptionalHaikuImagePackageAdded BeZillaBrowser ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				BeZillaBrowser-2.0.0.22pre-r1a2-x86-gcc4-2010-05-04.zip
-				: $(baseURL)/BeZillaBrowser-2.0.0.22pre-r1a2-x86-gcc4-2010-05-04.zip ;
+				$(baseURL)/BeZillaBrowser-2.0.0.22pre-r1a2-x86-gcc4-2010-05-04.zip ;
  		} else {
 			InstallOptionalHaikuImagePackage
-				bezillabrowser-2.0.0.22pre_2010_05_02-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/bezillabrowser-2.0.0.22pre_2010_05_02-1-x86_gcc2.hpkg
+				$(hpkgBaseURL)/bezillabrowser-2.0.0.22pre_2010_05_02-1-x86_gcc2.hpkg
 				: common packages ;
  		}
  		AddSymlinkToHaikuImage home config settings deskbar Applications
@@ -321,12 +310,10 @@ if [ IsOptionalHaikuImagePackageAdded BurnItNow ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-			burnitnow-39-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/burnitnow-39-r1a3-x86-gcc4-2011-05-24.zip ;
+				$(baseURL)/burnitnow-39-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
-		InstallOptionalHaikuImagePackage
-			burnitnow-39-r1a3-x86-gcc2-2011-05-18.zip
-			: $(baseURL)/burnitnow-39-r1a3-x86-gcc2-2011-05-18.zip ;
+			InstallOptionalHaikuImagePackage
+				$(baseURL)/burnitnow-39-r1a3-x86-gcc2-2011-05-18.zip ;
 		}
 		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/BurnItNow/BurnItNow ;
@@ -340,13 +327,11 @@ if [ IsOptionalHaikuImagePackageAdded Bzip ] {
 		Echo "No optional package Bzip available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			bzip2-1.0.6-r1a3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/bzip2-1.0.6-r1a3-x86-gcc4-2011-05-24.zip
+			$(baseURL)/bzip2-1.0.6-r1a3-x86-gcc4-2011-05-24.zip
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			bzip2-1.0.6-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/bzip2-1.0.6-1-x86_gcc2.hpkg
+			$(hpkgBaseURL)/bzip2-1.0.6-1-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -358,12 +343,10 @@ if [ IsOptionalHaikuImagePackageAdded CCache ] {
 		Echo "No optional package CCache available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			ccache-3.0.1-r1a3-x86-gcc4-2011-05-23.zip
-			: $(baseURL)/ccache-3.0.1-r1a3-x86-gcc4-2011-05-23.zip ;
+			$(baseURL)/ccache-3.0.1-r1a3-x86-gcc4-2011-05-23.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			ccache-3.0.1-r1a3-x86-gcc2-2011-05-17.zip
-			: $(baseURL)/ccache-3.0.1-r1a3-x86-gcc2-2011-05-17.zip ;
+			$(baseURL)/ccache-3.0.1-r1a3-x86-gcc2-2011-05-17.zip ;
 	}
 }
 
@@ -374,12 +357,10 @@ if [ IsOptionalHaikuImagePackageAdded CDRecord ] {
 		Echo "No optional package CDRecord available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			cdrtools-3.01a01-r1a3-x86-gcc4-2011-05-23.zip
-			: $(baseURL)/cdrtools-3.01a01-r1a3-x86-gcc4-2011-05-23.zip ;
+			$(baseURL)/cdrtools-3.01a01-r1a3-x86-gcc4-2011-05-23.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			cdrtools-3.00-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/cdrtools-3.00-1-x86_gcc2.hpkg
+			$(hpkgBaseURL)/cdrtools-3.00-1-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -392,12 +373,10 @@ if [ IsOptionalHaikuImagePackageAdded Clockwerk ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				Clockwerk-0.0.2-x86-gcc4-2010-10-13-1.zip
-				: $(baseURL)/Clockwerk-0.0.2-x86-gcc4-2010-10-13-1.zip ;
+				$(baseURL)/Clockwerk-0.0.2-x86-gcc4-2010-10-13-1.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				Clockwerk-0.0.2-x86-gcc2-2010-10-13-1.zip
-				: $(baseURL)/Clockwerk-0.0.2-x86-gcc2-2010-10-13-1.zip ;
+				$(baseURL)/Clockwerk-0.0.2-x86-gcc2-2010-10-13-1.zip ;
 		}
 		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/Clockwerk/Clockwerk ;
@@ -413,8 +392,7 @@ if [ IsOptionalHaikuImagePackageAdded CLucene ] {
 		Echo "No optional package CLucene available for GCC2" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			clucene-0.9.21-x86-gcc4-haiku-2009-08-11.zip
-			: $(baseURL)/clucene-0.9.21-x86-gcc4-haiku-2009-08-11.zip
+			$(baseURL)/clucene-0.9.21-x86-gcc4-haiku-2009-08-11.zip
 			: : true ;
 	}
 }
@@ -427,13 +405,11 @@ if [ IsOptionalHaikuImagePackageAdded CMake ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				cmake-2.8.4-r1a3-x86-gcc4-2011-05-23.zip
-				: $(baseURL)/cmake-2.8.4-r1a3-x86-gcc4-2011-05-23.zip
+				$(baseURL)/cmake-2.8.4-r1a3-x86-gcc4-2011-05-23.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				cmake-2.8.5-2-gcc2_x86.hpkg
-				: $(hpkgBaseURL)/cmake-2.8.5-2-gcc2_x86.hpkg
+				$(hpkgBaseURL)/cmake-2.8.5-2-gcc2_x86.hpkg
 				: common packages ;
 		}
 	}
@@ -445,11 +421,11 @@ if [ IsOptionalHaikuImagePackageAdded Curl ] {
 	if $(TARGET_ARCH) != x86 {
 		Echo "No optional package Curl available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
-		InstallOptionalHaikuImagePackage curl-7.21.7-x86-gcc4-2011-06-23.zip
-			: $(baseURL)/curl-7.21.7-x86-gcc4-2011-06-23.zip ;
+		InstallOptionalHaikuImagePackage
+			$(baseURL)/curl-7.21.7-x86-gcc4-2011-06-23.zip ;
 	} else {
-		InstallOptionalHaikuImagePackage curl-7.21.6-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/curl-7.21.6-1-x86_gcc2.hpkg
+		InstallOptionalHaikuImagePackage
+			$(hpkgBaseURL)/curl-7.21.6-1-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -462,13 +438,11 @@ if [ IsOptionalHaikuImagePackageAdded CVS ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				cvs-1.12.13.1-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/cvs-1.12.13.1-r1a3-x86-gcc4-2011-05-24.zip
+				$(baseURL)/cvs-1.12.13.1-r1a3-x86-gcc4-2011-05-24.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				cvs-1.12.13.1-2-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/cvs-1.12.13.1-2-x86_gcc2.hpkg
+				$(hpkgBaseURL)/cvs-1.12.13.1-2-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -480,37 +454,29 @@ if [ IsOptionalHaikuImagePackageAdded Development ] && $(TARGET_ARCH) = x86 {
 	# autotools
 	if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			autoconf-2.68-r1a3-x86-gcc4-2011-05-23.zip
-			: $(baseURL)/autoconf-2.68-r1a3-x86-gcc4-2011-05-23.zip
+			$(baseURL)/autoconf-2.68-r1a3-x86-gcc4-2011-05-23.zip
 			: : true ;
 		InstallOptionalHaikuImagePackage
-			automake-1.11.1-r1a3-x86-gcc4-2011-05-23.zip
-			: $(baseURL)/automake-1.11.1-r1a3-x86-gcc4-2011-05-23.zip
+			$(baseURL)/automake-1.11.1-r1a3-x86-gcc4-2011-05-23.zip
 			: : true ;
 		InstallOptionalHaikuImagePackage
-			libtool-2.4-r1a3-x86-gcc4-2011-05-23.zip
-			: $(baseURL)/libtool-2.4-r1a3-x86-gcc4-2011-05-23.zip
+			$(baseURL)/libtool-2.4-r1a3-x86-gcc4-2011-05-23.zip
 			: : true ;
 		InstallOptionalHaikuImagePackage
-			texinfo-4.13a-r1a3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/texinfo-4.13a-r1a3-x86-gcc4-2011-05-24.zip
+			$(baseURL)/texinfo-4.13a-r1a3-x86-gcc4-2011-05-24.zip
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			autoconf-2.68-3-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/autoconf-2.68-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/autoconf-2.68-3-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			automake-1.11.1-3-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/automake-1.11.1-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/automake-1.11.1-3-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			libtool-2.4-3-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/libtool-2.4-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/libtool-2.4-3-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			texinfo-4.13a-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/texinfo-4.13a-2-x86_gcc2.hpkg
+			$(hpkgBaseURL)/texinfo-4.13a-2-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -521,8 +487,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 		&& $(TARGET_ARCH) = x86 {
 	# gcc and binutils
 	if $(HAIKU_GCC_VERSION[1]) = 2 {
-		InstallOptionalHaikuImagePackage gcc-2.95.3_110711-4-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/gcc-2.95.3_110711-4-x86_gcc2.hpkg
+		InstallOptionalHaikuImagePackage
+			$(hpkgBaseURL)/gcc-2.95.3_110711-4-x86_gcc2.hpkg
 			: common packages ;
 
 		# TODO: remove this when we have a mechanism to switch gcc via PATH
@@ -533,54 +499,41 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 
 	if $(HAIKU_GCC_VERSION[1]) = 4 {
 		InstallOptionalHaikuImagePackage
-			gcc-4.5.3-r1a3-x86-gcc4-2011-06-20.zip
-			: $(baseURL)/gcc-4.5.3-r1a3-x86-gcc4-2011-06-20.zip ;
+			$(baseURL)/gcc-4.5.3-r1a3-x86-gcc4-2011-06-20.zip ;
 	}
 
 	# other commonly used tools
 	if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			bison-2.4.3-r1a3-x86-gcc4-2011-05-23.zip
-			: $(baseURL)/bison-2.4.3-r1a3-x86-gcc4-2011-05-23.zip ;
+			$(baseURL)/bison-2.4.3-r1a3-x86-gcc4-2011-05-23.zip ;
 		InstallOptionalHaikuImagePackage
-			m4-1.4.16-r1a3-x86-gcc4-2011-05-23.zip
-			: $(baseURL)/m4-1.4.16-r1a3-x86-gcc4-2011-05-23.zip ;
+			$(baseURL)/m4-1.4.16-r1a3-x86-gcc4-2011-05-23.zip ;
 		InstallOptionalHaikuImagePackage
-			flex-2.5.35-r1a3-x86-gcc4-2011-05-23.zip
-			: $(baseURL)/flex-2.5.35-r1a3-x86-gcc4-2011-05-23.zip ;
+			$(baseURL)/flex-2.5.35-r1a3-x86-gcc4-2011-05-23.zip ;
 		InstallOptionalHaikuImagePackage
-			jam-2.5-r1a3-x86-gcc4-2011-05-23.zip
-			: $(baseURL)/jam-2.5-r1a3-x86-gcc4-2011-05-23.zip ;
+			$(baseURL)/jam-2.5-r1a3-x86-gcc4-2011-05-23.zip ;
 		InstallOptionalHaikuImagePackage
-			mkdepend-1.7-r1a3-x86-gcc4-2011-05-23.zip
-			: $(baseURL)/mkdepend-1.7-r1a3-x86-gcc4-2011-05-23.zip ;
+			$(baseURL)/mkdepend-1.7-r1a3-x86-gcc4-2011-05-23.zip ;
 		InstallOptionalHaikuImagePackage
-			make-3.82-r1a3-x86-gcc4-2011-05-23.zip
-			: $(baseURL)/make-3.82-r1a3-x86-gcc4-2011-05-23.zip ;
+			$(baseURL)/make-3.82-r1a3-x86-gcc4-2011-05-23.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			bison-2.4.3-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/bison-2.4.3-2-x86_gcc2.hpkg
+			$(hpkgBaseURL)/bison-2.4.3-2-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			m4-1.4.16-3-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/m4-1.4.16-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/m4-1.4.16-3-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			flex-2.5.35-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/flex-2.5.35-2-x86_gcc2.hpkg
+			$(hpkgBaseURL)/flex-2.5.35-2-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			jam-2.5-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/jam-2.5-1-x86_gcc2.hpkg
+			$(hpkgBaseURL)/jam-2.5-1-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			mkdepend-1.7-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/mkdepend-1.7-1-x86_gcc2.hpkg
+			$(hpkgBaseURL)/mkdepend-1.7-1-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			make-3.82-3-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/make-3.82-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/make-3.82-3-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -594,16 +547,13 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentJava ] {
 		Echo "No optional package DevelopmentJava available for gcc2" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			gnu-classpath-0.98-r1a3-x86-gcc4-2011-06-08.zip
-			: $(baseURL)/gnu-classpath-0.98-r1a3-x86-gcc4-2011-06-08.zip ;
+			$(baseURL)/gnu-classpath-0.98-r1a3-x86-gcc4-2011-06-08.zip ;
 		InstallOptionalHaikuImagePackage
-			jamvm-1.5.4-r1a3-x86-gcc4-2011-06-08.zip
-			: $(baseURL)/jamvm-1.5.4-r1a3-x86-gcc4-2011-06-08.zip ;
+			$(baseURL)/jamvm-1.5.4-r1a3-x86-gcc4-2011-06-08.zip ;
 		AddSymlinkToHaikuImage common bin
 			: /boot/common/bin/jamvm : java ;
 		InstallOptionalHaikuImagePackage
-			ecj-3.6.2-haiku-2011-06-08.zip
-			: $(baseURL)/ecj-3.6.2-haiku-2011-06-08.zip ;
+			$(baseURL)/ecj-3.6.2-haiku-2011-06-08.zip ;
 	}
 }
 
@@ -626,12 +576,10 @@ if [ IsOptionalHaikuImagePackageAdded DMIDecode ] {
 		Echo "No optional package DMIDecode available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			dmidecode-2.11-x86-gcc4-2011-11-02.zip
-			: http://revolf.free.fr/beos/dmidecode-2.11-x86-gcc4-2011-11-02.zip ;
+			http://revolf.free.fr/beos/dmidecode-2.11-x86-gcc4-2011-11-02.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			dmidecode-2.11-x86-gcc2-2011-11-02.zip
-			: http://revolf.free.fr/beos/dmidecode-2.11-x86-gcc2-2011-11-02.zip ;
+			http://revolf.free.fr/beos/dmidecode-2.11-x86-gcc2-2011-11-02.zip ;
 	}
 }
 
@@ -643,13 +591,11 @@ if [ IsOptionalHaikuImagePackageAdded Doxygen ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				doxygen-1.6.3-x86-gcc4-2010-05-17.zip
-				: $(baseURL)/doxygen-1.6.3-x86-gcc4-2010-05-17.zip
+				$(baseURL)/doxygen-1.6.3-x86-gcc4-2010-05-17.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				doxygen-1.6.3-1-gcc2_x86.hpkg
-				: $(hpkgBaseURL)/doxygen-1.6.3-1-gcc2_x86.hpkg
+				$(hpkgBaseURL)/doxygen-1.6.3-1-gcc2_x86.hpkg
 				: common packages ;
 		}
 	}
@@ -663,13 +609,11 @@ if [ IsOptionalHaikuImagePackageAdded Expat ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				expat-2.0.1-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/expat-2.0.1-r1a3-x86-gcc4-2011-05-24.zip
+				$(baseURL)/expat-2.0.1-r1a3-x86-gcc4-2011-05-24.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				expat-2.0.1-3-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/expat-2.0.1-3-x86_gcc2.hpkg
+				$(hpkgBaseURL)/expat-2.0.1-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -682,12 +626,10 @@ if [ IsOptionalHaikuImagePackageAdded Fastdep ] {
 		Echo "No optional package Fastdep available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			fastdep-0.16-r1a3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/fastdep-0.16-r1a3-x86-gcc4-2011-05-24.zip ;
+			$(baseURL)/fastdep-0.16-r1a3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			fastdep-0.16-r1a3-x86-gcc2-2011-05-18.zip
-			: $(baseURL)/fastdep-0.16-r1a3-x86-gcc2-2011-05-18.zip ;
+			$(baseURL)/fastdep-0.16-r1a3-x86-gcc2-2011-05-18.zip ;
 	}
 }
 
@@ -699,12 +641,10 @@ if [ IsOptionalHaikuImagePackageAdded friss ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				friss-24-r1a3-x86-gcc4-2011-05-31.zip
-				: $(baseURL)/friss-24-r1a3-x86-gcc4-2011-05-31.zip ;
+				$(baseURL)/friss-24-r1a3-x86-gcc4-2011-05-31.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				friss-24-r1a3-x86-gcc2-2011-05-31.zip
-				: $(baseURL)/friss-24-r1a3-x86-gcc2-2011-05-31.zip ;
+				$(baseURL)/friss-24-r1a3-x86-gcc2-2011-05-31.zip ;
 		}
 #		AddSymlinkToHaikuImage home config settings deskbar Desktop\ applets
 #			: /boot/apps/FRiSS/FRiSS ;
@@ -719,13 +659,11 @@ if [ IsOptionalHaikuImagePackageAdded GetText ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				gettext-0.18.1.1-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/gettext-0.18.1.1-r1a3-x86-gcc4-2011-05-24.zip
+				$(baseURL)/gettext-0.18.1.1-r1a3-x86-gcc4-2011-05-24.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				gettext-0.18.1.1-x86-gcc2-2011-02-07.zip
-				: $(baseURL)/gettext-0.18.1.1-x86-gcc2-2011-02-07.zip
+				$(baseURL)/gettext-0.18.1.1-x86-gcc2-2011-02-07.zip
 				: : true ;
 		}
 	}
@@ -739,13 +677,11 @@ if [ IsOptionalHaikuImagePackageAdded Git ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				git-1.7.5-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/git-1.7.5-r1a3-x86-gcc4-2011-05-24.zip
+				$(baseURL)/git-1.7.5-r1a3-x86-gcc4-2011-05-24.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				git-1.7.5-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/git-1.7.5-1-x86_gcc2.hpkg
+				$(hpkgBaseURL)/git-1.7.5-1-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -759,13 +695,11 @@ if [ IsOptionalHaikuImagePackageAdded GPerf ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				gperf-3.0.4-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/gperf-3.0.4-r1a3-x86-gcc4-2011-05-24.zip
+				$(baseURL)/gperf-3.0.4-r1a3-x86-gcc4-2011-05-24.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				gperf-3.0.4-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/gperf-3.0.4-r1a3-x86-gcc2-2011-05-18.zip
+				$(baseURL)/gperf-3.0.4-r1a3-x86-gcc2-2011-05-18.zip
 				: : true ;
 		}
 	}
@@ -779,13 +713,11 @@ if [ IsOptionalHaikuImagePackageAdded Groff ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				groff-1.20.1-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/groff-1.20.1-r1a3-x86-gcc4-2011-05-24.zip
+				$(baseURL)/groff-1.20.1-r1a3-x86-gcc4-2011-05-24.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				 groff-1.20.1-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/groff-1.20.1-r1a3-x86-gcc2-2011-05-18.zip
+				$(baseURL)/groff-1.20.1-r1a3-x86-gcc2-2011-05-18.zip
 				: : true ;
 		}
 	}
@@ -799,13 +731,13 @@ if [ IsOptionalHaikuImagePackageAdded ICU ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) = 2 {
 			# unzip gcc2
-			InstallOptionalHaikuImagePackage $(HAIKU_ICU_GCC_2_PACKAGE)
-				: $(hpkgBaseURL)/$(HAIKU_ICU_GCC_2_PACKAGE)
+			InstallOptionalHaikuImagePackage
+				$(hpkgBaseURL)/$(HAIKU_ICU_GCC_2_PACKAGE)
 				: system packages ;
 		} else {
 			# unzip gcc4
-			InstallOptionalHaikuImagePackage $(HAIKU_ICU_GCC_4_PACKAGE)
-				: $(baseURL)/$(HAIKU_ICU_GCC_4_PACKAGE)
+			InstallOptionalHaikuImagePackage
+				$(baseURL)/$(HAIKU_ICU_GCC_4_PACKAGE)
 				: system lib ;
 			}
 		}
@@ -814,8 +746,8 @@ if [ IsOptionalHaikuImagePackageAdded ICU ] {
 
 # ICU-devel
 if [ IsOptionalHaikuImagePackageAdded ICU-devel ] {
-	InstallOptionalHaikuImagePackage $(HAIKU_ICU_DEVEL_PACKAGE)
-		: $(hpkgBaseURL)/$(HAIKU_ICU_DEVEL_PACKAGE)
+	InstallOptionalHaikuImagePackage
+		$(hpkgBaseURL)/$(HAIKU_ICU_DEVEL_PACKAGE)
 		: common packages ;
 
 	local arch = $(TARGET_ARCH) ;
@@ -838,12 +770,10 @@ if [ IsOptionalHaikuImagePackageAdded KeymapSwitcher ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				KeymapSwitcher-1.2.6-r1a3-x86-gcc4-2011-06-12.zip
-				: $(baseURL)/KeymapSwitcher-1.2.6-r1a3-x86-gcc4-2011-06-12.zip ;
+				$(baseURL)/KeymapSwitcher-1.2.6-r1a3-x86-gcc4-2011-06-12.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				KeymapSwitcher-1.2.6-r1a3-x86-gcc2-2011-06-12.zip
-				: $(baseURL)/KeymapSwitcher-1.2.6-r1a3-x86-gcc2-2011-06-12.zip ;
+				$(baseURL)/KeymapSwitcher-1.2.6-r1a3-x86-gcc2-2011-06-12.zip ;
 		}
 		AddSymlinkToHaikuImage home config settings deskbar Preferences
 			: /boot/common/bin/KeymapSwitcher ;
@@ -858,13 +788,11 @@ if [ IsOptionalHaikuImagePackageAdded LibEvent ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				libevent-2.0.10-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/lib/libevent-2.0.10-r1a3-x86-gcc4-2011-05-24.zip
+				$(baseURL)/lib/libevent-2.0.10-r1a3-x86-gcc4-2011-05-24.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				libevent-2.0.10-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/lib/libevent-2.0.10-r1a3-x86-gcc2-2011-05-18.zip
+				$(baseURL)/lib/libevent-2.0.10-r1a3-x86-gcc2-2011-05-18.zip
 				: : true ;
 		}
 	}
@@ -878,12 +806,10 @@ if [ IsOptionalHaikuImagePackageAdded LibIconv ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				libiconv-1.13.1-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/libiconv-1.13.1-r1a3-x86-gcc4-2011-05-24.zip ;
+				$(baseURL)/libiconv-1.13.1-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				libiconv-1.13.1-3-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/libiconv-1.13.1-3-x86_gcc2.hpkg
+				$(hpkgBaseURL)/libiconv-1.13.1-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -897,8 +823,8 @@ if [ IsOptionalHaikuImagePackageAdded LibLayout ] {
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		Echo "No optional package LibLayout available for gcc4" ;
 	} else {
-		InstallOptionalHaikuImagePackage liblayout-1.4.0-gcc2-2009-03-08.zip
-			: $(baseURL)/liblayout-1.4.0-gcc2-2009-03-08.zip ;
+		InstallOptionalHaikuImagePackage
+			$(baseURL)/liblayout-1.4.0-gcc2-2009-03-08.zip ;
 	}
 }
 
@@ -909,12 +835,10 @@ if [ IsOptionalHaikuImagePackageAdded Libmng ] {
 		Echo "No optional package Libmng available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			libmng-1.0.10-r1a3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/lib/libmng-1.0.10-r1a3-x86-gcc4-2011-05-24.zip ;
+			$(baseURL)/lib/libmng-1.0.10-r1a3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			libmng-1.0.10-r1a3-x86-gcc2-2011-05-18.zip
-			: $(baseURL)/lib/libmng-1.0.10-r1a3-x86-gcc2-2011-05-18.zip ;
+			$(baseURL)/lib/libmng-1.0.10-r1a3-x86-gcc2-2011-05-18.zip ;
 	}
 }
 
@@ -924,8 +848,8 @@ if [ IsOptionalHaikuImagePackageAdded LibSolv ] {
 	if ! $(HAIKU_LIBSOLV_PACKAGE) {
 		Echo "No optional package LibSolv available for $(TARGET_ARCH)" ;
 	} else {
-		InstallOptionalHaikuImagePackage $(HAIKU_LIBSOLV_PACKAGE)
-			: $(hpkgBaseURL)/$(HAIKU_LIBSOLV_PACKAGE)
+		InstallOptionalHaikuImagePackage
+			$(hpkgBaseURL)/$(HAIKU_LIBSOLV_PACKAGE)
 			: system packages ;
 	}
 }
@@ -938,12 +862,10 @@ if [ IsOptionalHaikuImagePackageAdded LibXML2 ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				libxml2-2.7.8-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/libxml2-2.7.8-r1a3-x86-gcc4-2011-05-24.zip ;
+				$(baseURL)/libxml2-2.7.8-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				libxml2-2.7.8-3-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/libxml2-2.7.8-3-x86_gcc2.hpkg
+				$(hpkgBaseURL)/libxml2-2.7.8-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -956,12 +878,10 @@ if [ IsOptionalHaikuImagePackageAdded LibXSLT ] {
 		Echo "No optional package LibXSLT available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			libxslt-1.1.26-r1a3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/libxslt-1.1.26-r1a3-x86-gcc4-2011-05-24.zip ;
+			$(baseURL)/libxslt-1.1.26-r1a3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			libxslt-1.1.26-r1a3-x86-gcc2-2011-05-18.zip
-			: $(baseURL)/libxslt-1.1.26-r1a3-x86-gcc2-2011-05-18.zip
+			$(baseURL)/libxslt-1.1.26-r1a3-x86-gcc2-2011-05-18.zip
 			: : true ;
 	}
 }
@@ -974,8 +894,8 @@ if [ IsOptionalHaikuImagePackageAdded Links ] {
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		Echo "No optional package Links available for gcc4" ;
 	} else {
-		InstallOptionalHaikuImagePackage Links.zip
-			: $(baseURL)/links-x86-gcc2-2008-05-03.zip ;
+		InstallOptionalHaikuImagePackage
+			$(baseURL)/links-x86-gcc2-2008-05-03.zip ;
 		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/home/config/bin/links ;
 	}
@@ -989,13 +909,11 @@ if [ IsOptionalHaikuImagePackageAdded Lua ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				lua-5.1.4-x86-gcc4-2010-10-30.zip
-				: $(baseURL)/lua-5.1.4-x86-gcc4-2010-10-30.zip
+				$(baseURL)/lua-5.1.4-x86-gcc4-2010-10-30.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				lua-5.1.4-3-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/lua-5.1.4-3-r1a3-x86-gcc2-2011-05-18.zip
+				$(baseURL)/lua-5.1.4-3-r1a3-x86-gcc2-2011-05-18.zip
 				: : true ;
 		}
 	}
@@ -1008,12 +926,10 @@ if [ IsOptionalHaikuImagePackageAdded Man ] {
 		Echo "No optional package Man available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			 man-1.6f-r1a3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/man-1.6f-r1a3-x86-gcc4-2011-05-24.zip ;
+			$(baseURL)/man-1.6f-r1a3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			 man-1.6f-r1a3-x86-gcc2-2011-05-18.zip
-			: $(baseURL)/man-1.6f-r1a3-x86-gcc2-2011-05-18.zip ;
+			$(baseURL)/man-1.6f-r1a3-x86-gcc2-2011-05-18.zip ;
 	}
 }
 
@@ -1031,13 +947,11 @@ if [ IsOptionalHaikuImagePackageAdded Mercurial ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				mercurial-1.8.3-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/mercurial-1.8.3-r1a3-x86-gcc4-2011-05-24.zip
+				$(baseURL)/mercurial-1.8.3-r1a3-x86-gcc4-2011-05-24.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				mercurial-1.8.3-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/mercurial-1.8.3-1-x86_gcc2.hpkg
+				$(hpkgBaseURL)/mercurial-1.8.3-1-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1051,12 +965,10 @@ if [ IsOptionalHaikuImagePackageAdded Nano ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				nano-2.2.6-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/nano-2.2.6-r1a3-x86-gcc4-2011-05-24.zip ;
+				$(baseURL)/nano-2.2.6-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				nano-2.2.6-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/nano-2.2.6-1-x86_gcc2.hpkg
+				$(hpkgBaseURL)/nano-2.2.6-1-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1070,12 +982,10 @@ if [ IsOptionalHaikuImagePackageAdded Neon ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				neon-0.29.6-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/neon-0.29.6-r1a3-x86-gcc4-2011-05-24.zip ;
+				$(baseURL)/neon-0.29.6-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				neon-0.29.6-3-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/neon-0.29.6-3-x86_gcc2.hpkg
+				$(hpkgBaseURL)/neon-0.29.6-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1121,8 +1031,7 @@ if [ IsOptionalHaikuImagePackageAdded NetSurf ] {
 		Echo "No optional package NetSurf available for gcc4" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			netsurf-2.7-r1a3-x86-gcc2-2011-06-04.zip
-			: $(baseURL)/netsurf-2.7-r1a3-x86-gcc2-2011-06-04.zip ;
+			$(baseURL)/netsurf-2.7-r1a3-x86-gcc2-2011-06-04.zip ;
 		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/NetSurf/NetSurf ;
 	}
@@ -1137,11 +1046,9 @@ if [ IsOptionalHaikuImagePackageAdded OCaml ] {
 		Echo "No optional package OCaml available for gcc4" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			ocaml-3.11.1-r1a1-x86-gcc2-2009-09-06.zip
-			: $(baseURL)/ocaml-3.11.1-r1a1-x86-gcc2-2009-09-06.zip ;
+			$(baseURL)/ocaml-3.11.1-r1a1-x86-gcc2-2009-09-06.zip ;
 		InstallOptionalHaikuImagePackage
-			camlp5-5.12-r1a1-x86-gcc2-2009-09-06.zip
-			: $(baseURL)/camlp5-5.12-r1a1-x86-gcc2-2009-09-06.zip ;
+			$(baseURL)/camlp5-5.12-r1a1-x86-gcc2-2009-09-06.zip ;
 	}
 }
 
@@ -1152,8 +1059,7 @@ if [ IsOptionalHaikuImagePackageAdded OpenSound ] {
 		Echo "No optional package OpenSound available for $(TARGET_ARCH)" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			opensound-4.2-r1a2-x86-gcc2-2010-05-01.zip
-			: $(baseURL)/opensound-4.2-r1a2-x86-gcc2-2010-05-01.zip ;
+			$(baseURL)/opensound-4.2-r1a2-x86-gcc2-2010-05-01.zip ;
 	}
 }
 
@@ -1170,12 +1076,10 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSH ] {
 
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				openssh-5.9p1-x86-gcc4-2011-09-08.zip
-				: $(baseURL)/openssh-5.9p1-x86-gcc4-2011-09-08.zip ;
+				$(baseURL)/openssh-5.9p1-x86-gcc4-2011-09-08.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				openssh-5.8p2-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/openssh-5.8p2-1-x86_gcc2.hpkg
+				$(hpkgBaseURL)/openssh-5.8p2-1-x86_gcc2.hpkg
 				: common packages ;
 		}
 
@@ -1191,11 +1095,9 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSL ] {
 		Echo "No optional package OpenSSL available for $(TARGET_ARCH)" ;
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
-			InstallOptionalHaikuImagePackage $(HAIKU_OPENSSL_PACKAGE)
-				: $(HAIKU_OPENSSL_URL) ;
+			InstallOptionalHaikuImagePackage $(HAIKU_OPENSSL_URL) ;
 		} else {
-			InstallOptionalHaikuImagePackage $(HAIKU_OPENSSL_PACKAGE)
-				: $(HAIKU_OPENSSL_URL)
+			InstallOptionalHaikuImagePackage $(HAIKU_OPENSSL_URL)
 				: common packages ;
 		}
 	}
@@ -1209,12 +1111,10 @@ if [ IsOptionalHaikuImagePackageAdded P7zip ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				p7zip-9.13-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/p7zip-9.13-r1a3-x86-gcc4-2011-05-24.zip ;
+				$(baseURL)/p7zip-9.13-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				p7zip-9.13-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/p7zip-9.13-1-x86_gcc2.hpkg
+				$(hpkgBaseURL)/p7zip-9.13-1-x86_gcc2.hpkg
 				: common packages ;
 		}
 		AddExpanderRuleToHaikuImage "application/x-7z-compressed" : .7z
@@ -1233,12 +1133,10 @@ if [ IsOptionalHaikuImagePackageAdded Paladin ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				paladin-1.3-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/paladin-1.3-r1a3-x86-gcc4-2011-05-24.zip ;
+				$(baseURL)/paladin-1.3-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				paladin-1.3-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/paladin-1.3-r1a3-x86-gcc2-2011-05-18.zip ;
+				$(baseURL)/paladin-1.3-r1a3-x86-gcc2-2011-05-18.zip ;
 		}
 
 		AddSymlinkToHaikuImage home config settings deskbar Applications
@@ -1256,12 +1154,10 @@ if [ IsOptionalHaikuImagePackageAdded PCRE ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				libpcre-8.12-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/libpcre-8.12-r1a3-x86-gcc4-2011-05-24.zip ;
+				$(baseURL)/libpcre-8.12-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				libpcre-8.12-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/libpcre-8.12-1-x86_gcc2.hpkg
+				$(hpkgBaseURL)/libpcre-8.12-1-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1275,12 +1171,10 @@ if [ IsOptionalHaikuImagePackageAdded Pe ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				pe-2.4.3-600-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/pe-2.4.3-600-r1a3-x86-gcc4-2011-05-24.zip ;
+				$(baseURL)/pe-2.4.3-600-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				pe-2.4.3_600-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/pe-2.4.3_600-1-x86_gcc2.hpkg
+				$(hpkgBaseURL)/pe-2.4.3_600-1-x86_gcc2.hpkg
 				: common packages ;
 		}
 		AddSymlinkToHaikuImage home config settings deskbar Applications
@@ -1296,13 +1190,11 @@ if [ IsOptionalHaikuImagePackageAdded Perl ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				perl-5.10.1-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/perl-5.10.1-r1a3-x86-gcc4-2011-05-24.zip
+				$(baseURL)/perl-5.10.1-r1a3-x86-gcc4-2011-05-24.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				perl-5.10.1-3-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/perl-5.10.1-3-x86_gcc2.hpkg
+				$(hpkgBaseURL)/perl-5.10.1-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1316,13 +1208,11 @@ if [ IsOptionalHaikuImagePackageAdded Python ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				python-2.6.7-x86-gcc4-2011-06-24.zip
-				: $(baseURL)/python-2.6.7-x86-gcc4-2011-06-24.zip
+				$(baseURL)/python-2.6.7-x86-gcc4-2011-06-24.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				python-2.6.6-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/python-2.6.6-1-x86_gcc2.hpkg
+				$(hpkgBaseURL)/python-2.6.6-1-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1336,13 +1226,11 @@ if [ IsOptionalHaikuImagePackageAdded Rsync ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				rsync-3.0.7-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/rsync-3.0.7-r1a3-x86-gcc4-2011-05-24.zip
+				$(baseURL)/rsync-3.0.7-r1a3-x86-gcc4-2011-05-24.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				rsync-3.0.7-r1a3-x86-gcc2-2011-05-18.zip
-				: $(baseURL)/rsync-3.0.7-r1a3-x86-gcc2-2011-05-18.zip
+				$(baseURL)/rsync-3.0.7-r1a3-x86-gcc2-2011-05-18.zip
 				: : true ;
 		}
 	}
@@ -1355,12 +1243,10 @@ if [ IsOptionalHaikuImagePackageAdded Ruby ] {
 		Echo "No optional package Ruby available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			ruby-1.9.1-r1a3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/ruby-1.9.1-r1a3-x86-gcc4-2011-05-24.zip ;
+			$(baseURL)/ruby-1.9.1-r1a3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			ruby-1.9.1-r1a3-x86-gcc2-2011-05-31.zip
-			: $(baseURL)/ruby-1.9.1-r1a3-x86-gcc2-2011-06-01.zip ;
+			$(baseURL)/ruby-1.9.1-r1a3-x86-gcc2-2011-06-01.zip ;
 	}
 }
 
@@ -1371,12 +1257,10 @@ if [ IsOptionalHaikuImagePackageAdded Sed ] {
 		Echo "No optional package Sed available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			sed-4.2.1-r1a3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/sed-4.2.1-r1a3-x86-gcc4-2011-05-24.zip ;
+			$(baseURL)/sed-4.2.1-r1a3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			sed-4.2.1-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/sed-4.2.1-2-x86_gcc2.hpkg
+			$(hpkgBaseURL)/sed-4.2.1-2-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -1389,12 +1273,10 @@ if [ IsOptionalHaikuImagePackageAdded SQLite ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				sqlite-3.7.5-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/sqlite-3.7.5-r1a3-x86-gcc4-2011-05-24.zip ;
+				$(baseURL)/sqlite-3.7.5-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				sqlite-3.7.5-4-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/sqlite-3.7.5-4-x86_gcc2.hpkg
+				$(hpkgBaseURL)/sqlite-3.7.5-4-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1408,13 +1290,11 @@ if [ IsOptionalHaikuImagePackageAdded Subversion ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				subversion-1.6.17-x86-gcc4-2011-08-03.zip
-				: $(baseURL)/subversion-1.6.17-x86-gcc4-2011-08-03.zip
+				$(baseURL)/subversion-1.6.17-x86-gcc4-2011-08-03.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				subversion-1.6.15-3-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/subversion-1.6.15-3-x86_gcc2.hpkg
+				$(hpkgBaseURL)/subversion-1.6.15-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1427,12 +1307,10 @@ if [ IsOptionalHaikuImagePackageAdded TagLib ] {
 		Echo "No optional package TagLib available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			taglib-1.6.3-r1r3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/taglib-1.6.3-r1r3-x86-gcc4-2011-05-24.zip ;
+			$(baseURL)/taglib-1.6.3-r1r3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			taglib-1.6.3-r1a3-x86-gcc2-2011-05-20.zip
-			: $(baseURL)/taglib-1.6.3-r1a3-x86-gcc2-2011-05-20.zip ;
+			$(baseURL)/taglib-1.6.3-r1a3-x86-gcc2-2011-05-20.zip ;
 	}
 }
 
@@ -1444,12 +1322,10 @@ if [ IsOptionalHaikuImagePackageAdded Tar ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				tar-1.25-r1a3-x86-gcc4-2011-05-24.zip
-				: $(baseURL)/tar-1.25-r1a3-x86-gcc4-2011-05-24.zip ;
+				$(baseURL)/tar-1.25-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				tar-1.26-2-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/tar-1.26-2-x86_gcc2.hpkg
+				$(hpkgBaseURL)/tar-1.26-2-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1458,16 +1334,16 @@ if [ IsOptionalHaikuImagePackageAdded Tar ] {
 
 # TimGMSoundFont
 if [ IsOptionalHaikuImagePackageAdded TimGMSoundFont ] {
-	InstallOptionalHaikuImagePackage TimGMSoundFont-2010-06-16.hpkg
-		: $(hpkgBaseURL)/TimGMSoundFont-2010-06-16.hpkg
+	InstallOptionalHaikuImagePackage
+		$(hpkgBaseURL)/TimGMSoundFont-2010-06-16.hpkg
 		: system packages ;
 }
 
 
 # TrackerNewTemplates
 if [ IsOptionalHaikuImagePackageAdded TrackerNewTemplates ] {
-	InstallOptionalHaikuImagePackage TrackerNewTemplates-2010-04-26.zip
-		: $(baseURL)/TrackerNewTemplates-2010-04-26.zip
+	InstallOptionalHaikuImagePackage
+		$(baseURL)/TrackerNewTemplates-2010-04-26.zip
 		: home config settings Tracker "Tracker New Templates"
 	;
 }
@@ -1480,13 +1356,11 @@ if [ IsOptionalHaikuImagePackageAdded Transmission ] {
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
 			InstallOptionalHaikuImagePackage
-				transmission-2.21-r1a3-x86-gcc4-2011-05-27.zip
-				: $(baseURL)/transmission-2.21-r1a3-x86-gcc4-2011-05-27.zip
+				$(baseURL)/transmission-2.21-r1a3-x86-gcc4-2011-05-27.zip
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				transmission-2.21-r1a3-x86-gcc2-2011-05-27.zip
-				: $(baseURL)/transmission-2.21-r1a3-x86-gcc2-2011-05-27.zip
+				$(baseURL)/transmission-2.21-r1a3-x86-gcc2-2011-05-27.zip
 				: : true ;
 		}
 	}
@@ -1551,12 +1425,12 @@ if [ IsOptionalHaikuImagePackageAdded Vim ] {
 		Echo "No optional package Vim available for $(TARGET_ARCH)" ;
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
-			InstallOptionalHaikuImagePackage vim-7.3-r1a3-x86-gcc4-2011-05-26.zip
-				:  $(baseURL)/vim-7.3-r1a3-x86-gcc4-2011-05-26.zip
+			InstallOptionalHaikuImagePackage
+				$(baseURL)/vim-7.3-r1a3-x86-gcc4-2011-05-26.zip
 				: : true ;
 		} else {
-			InstallOptionalHaikuImagePackage vim-7.3-r1a3-x86-gcc2-2011-05-26.zip
-				:  $(baseURL)/vim-7.3-r1a3-x86-gcc2-2011-05-26.zip
+			InstallOptionalHaikuImagePackage
+				$(baseURL)/vim-7.3-r1a3-x86-gcc2-2011-05-26.zip
 				: : true ;
 		}
 		AddSymlinkToHaikuImage home config settings deskbar Applications
@@ -1573,12 +1447,11 @@ if [ IsOptionalHaikuImagePackageAdded Vision ] {
 		Echo "No optional package Vision available for $(TARGET_ARCH)" ;
 	} else {
 		if $(HAIKU_GCC_VERSION[1]) >= 4 {
-			InstallOptionalHaikuImagePackage vision-908-r1a3-x86-gcc4-2011-06-07.zip
-				: $(baseURL)/vision-908-r1a3-x86-gcc4-2011-06-07.zip ;
+			InstallOptionalHaikuImagePackage
+				$(baseURL)/vision-908-r1a3-x86-gcc4-2011-06-07.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				vision-908-1-x86_gcc2.hpkg
-				: $(hpkgBaseURL)/vision-908-1-x86_gcc2.hpkg
+				$(hpkgBaseURL)/vision-908-1-x86_gcc2.hpkg
 				: common packages ;
 		}
 		AddSymlinkToHaikuImage home config settings deskbar Applications
@@ -1595,8 +1468,7 @@ if [ IsOptionalHaikuImagePackageAdded WebPositive ] {
 		Echo "No optional package WebPositive available for gcc2" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			WebPositive-r1a3-gcc4-x86-r580-2011-06-02.zip
-			: $(baseURL)/WebPositive-r1a3-gcc4-x86-r580-2011-06-02.zip ;
+			$(baseURL)/WebPositive-r1a3-gcc4-x86-r580-2011-06-02.zip ;
 		AddSymlinkToHaikuImage home config settings deskbar Applications
 			: /boot/apps/WebPositive/WebPositive ;
 	}
@@ -1674,8 +1546,8 @@ if [ IsOptionalHaikuImagePackageAdded WonderBrush ] {
 		Echo "No optional package WonderBrush available for gcc4" ;
 	} else {
 # TODO: Package as HPKG!
-#		InstallOptionalHaikuImagePackage WonderBrush-2.1.2.zip
-#			: $(baseURL)/WonderBrush-2.1.2-x86-gcc2-2008-11-08.zip
+#		InstallOptionalHaikuImagePackage
+#			$(baseURL)/WonderBrush-2.1.2-x86-gcc2-2008-11-08.zip
 #			: common apps ;
 #		AddSymlinkToHaikuImage home config settings deskbar Applications
 #			: /boot/apps/WonderBrush/WonderBrush ;
@@ -1689,12 +1561,10 @@ if [ IsOptionalHaikuImagePackageAdded wpa_supplicant ] {
 		Echo "No optional package wpa_supplicant available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			wpa_supplicant-0.7.3-x86-gcc4-2011-10-05.zip
-			: $(baseURL)/wpa_supplicant-0.7.3-x86-gcc4-2011-10-05.zip ;
+			$(baseURL)/wpa_supplicant-0.7.3-x86-gcc4-2011-10-05.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			wpa_supplicant-0.7.3-x86-gcc2-2011-10-05.zip
-			: $(baseURL)/wpa_supplicant-0.7.3-x86-gcc2-2011-10-05.zip ;
+			$(baseURL)/wpa_supplicant-0.7.3-x86-gcc2-2011-10-05.zip ;
 	}
 }
 
@@ -1702,8 +1572,7 @@ if [ IsOptionalHaikuImagePackageAdded wpa_supplicant ] {
 # WQY-MicroHei
 if [ IsOptionalHaikuImagePackageAdded WQY-MicroHei ] {
 	InstallOptionalHaikuImagePackage
-		wqy-microhei-0.2.0-beta-1-x86_gcc2.hpkg
-		: $(hpkgBaseURL)/wqy-microhei-0.2.0-beta-1-x86_gcc2.hpkg
+		$(hpkgBaseURL)/wqy-microhei-0.2.0-beta-1-x86_gcc2.hpkg
 		: common packages ;
 }
 
@@ -1714,8 +1583,7 @@ if [ IsOptionalHaikuImagePackageAdded XZ-Utils ] {
 		Echo "No optional package XZ-Utils available for $(TARGET_ARCH)" ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			xz-utils-5.0.1-2-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/xz-utils-5.0.1-2-x86_gcc2.hpkg
+			$(hpkgBaseURL)/xz-utils-5.0.1-2-x86_gcc2.hpkg
 			: common packages ;
 		AddExpanderRuleToHaikuImage "application/x-xz" : .tar.xz
 			: "tar -Jtvf \\0045s"
@@ -1739,12 +1607,10 @@ if [ IsOptionalHaikuImagePackageAdded Yasm ] {
 		Echo "No optional package Yasm available for $(TARGET_ARCH)" ;
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		InstallOptionalHaikuImagePackage
-			yasm-1.1.0-r1a3-x86-gcc4-2011-05-24.zip
-			: $(baseURL)/yasm-1.1.0-r1a3-x86-gcc4-2011-05-24.zip ;
+			$(baseURL)/yasm-1.1.0-r1a3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			yasm-1.1.0-1-x86_gcc2.hpkg
-			: $(hpkgBaseURL)/yasm-1.1.0-1-x86_gcc2.hpkg
+			$(hpkgBaseURL)/yasm-1.1.0-1-x86_gcc2.hpkg
 			: common packages ;
 	}
 }

From 4210ed011a39e4e1b3fcba4c7c0d18844b4b3522 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 15 Apr 2013 01:36:59 +0200
Subject: [PATCH 0418/1170] Fix BMessage::GetInfo() return value check

Since B_OK is 0, the change doesn't affect the semantics.
---
 src/kits/package/DaemonClient.cpp | 2 +-
 src/kits/package/PackageInfo.cpp  | 6 +++---
 2 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/kits/package/DaemonClient.cpp b/src/kits/package/DaemonClient.cpp
index 10d35c0de0..f14801f51e 100644
--- a/src/kits/package/DaemonClient.cpp
+++ b/src/kits/package/DaemonClient.cpp
@@ -107,7 +107,7 @@ BDaemonClient::_ExtractPackageInfoSet(const BMessage& message,
 	// get the number of items
 	type_code type;
 	int32 count;
-	if (message.GetInfo(field, &type, &count)) {
+	if (message.GetInfo(field, &type, &count) != B_OK) {
 		// the field is missing
 		return B_OK;
 	}
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index ed9d27f318..b0bd3b9e7b 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -2033,7 +2033,7 @@ BPackageInfo::_ExtractStringList(BMessage* archive, const char* field,
 	// get the number of items
 	type_code type;
 	int32 count;
-	if (archive->GetInfo(field, &type, &count)) {
+	if (archive->GetInfo(field, &type, &count) != B_OK) {
 		// the field is missing
 		return B_OK;
 	}
@@ -2071,7 +2071,7 @@ BPackageInfo::_ExtractResolvables(BMessage* archive, const char* field,
 	// get the number of items
 	type_code type;
 	int32 count;
-	if (archive->GetInfo(nameField, &type, &count)) {
+	if (archive->GetInfo(nameField, &type, &count) != B_OK) {
 		// the field is missing
 		return B_OK;
 	}
@@ -2130,7 +2130,7 @@ BPackageInfo::_ExtractResolvableExpressions(BMessage* archive,
 	// get the number of items
 	type_code type;
 	int32 count;
-	if (archive->GetInfo(nameField, &type, &count)) {
+	if (archive->GetInfo(nameField, &type, &count) != B_OK) {
 		// the field is missing
 		return B_OK;
 	}

From 8d85f8e41e831cbfe7cce55716be763b6d939ef3 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 16 Apr 2013 17:05:06 +0200
Subject: [PATCH 0419/1170] Update libsolv package

The Haiku repository support has been upstreamed and the maintainer,
Michael Schroeder, has fixed and improved a few things.
---
 build/jam/OptionalBuildFeatures | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures
index a3e087d068..65f7483d52 100644
--- a/build/jam/OptionalBuildFeatures
+++ b/build/jam/OptionalBuildFeatures
@@ -221,7 +221,7 @@ if $(TARGET_ARCH) != x86 {
 	Echo "Libsolv not available for $(TARGET_ARCH)." ;
 } else if $(HAIKU_GCC_VERSION[1]) = 2 {
 	HAIKU_LIBSOLV_PACKAGE
-		= libsolv-0.3.0_haiku_2013_04_15-1-x86_gcc2.hpkg ;
+		= libsolv-0.3.0_haiku_2013_04_16-1-x86_gcc2.hpkg ;
 } else {
 	Echo "Libsolv not available for gcc4." ;
 }

From caba55ee61b631944493d91212a89f6a0360ee0f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 16 Apr 2013 20:34:52 +0200
Subject: [PATCH 0420/1170] Revert to previous libsolv package

In the latest one the version comparison is broken.
---
 build/jam/OptionalBuildFeatures | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures
index 65f7483d52..a3e087d068 100644
--- a/build/jam/OptionalBuildFeatures
+++ b/build/jam/OptionalBuildFeatures
@@ -221,7 +221,7 @@ if $(TARGET_ARCH) != x86 {
 	Echo "Libsolv not available for $(TARGET_ARCH)." ;
 } else if $(HAIKU_GCC_VERSION[1]) = 2 {
 	HAIKU_LIBSOLV_PACKAGE
-		= libsolv-0.3.0_haiku_2013_04_16-1-x86_gcc2.hpkg ;
+		= libsolv-0.3.0_haiku_2013_04_15-1-x86_gcc2.hpkg ;
 } else {
 	Echo "Libsolv not available for gcc4." ;
 }

From a8b23e3ecf784de00897f3a4840e38f08e79f8fd Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 16 Apr 2013 20:43:20 +0200
Subject: [PATCH 0421/1170] pkgman resolve-dependencies: Allow specifying
 multiple packages

---
 .../pkgman/command_resolve_dependencies.cpp   | 63 +++++++++++++------
 1 file changed, 43 insertions(+), 20 deletions(-)

diff --git a/src/bin/pkgman/command_resolve_dependencies.cpp b/src/bin/pkgman/command_resolve_dependencies.cpp
index 73882332d3..575719a570 100644
--- a/src/bin/pkgman/command_resolve_dependencies.cpp
+++ b/src/bin/pkgman/command_resolve_dependencies.cpp
@@ -32,18 +32,18 @@ using namespace BPackageKit;
 
 
 static const char* const kShortUsage =
-	"  %command%   [  ] ...\n"
-	"    Resolves all packages a given package depends on.\n";
+	"  %command%  ...  [  ] ...\n"
+	"    Resolves all packages the given packages depend on.\n";
 
 static const char* const kLongUsage =
-	"Usage: %program% %command%   [  ] ...\n"
-	"Resolves and lists all packages a given package depends on. Fails, if\n"
+	"Usage: %program% %command%  ...  [  ] ...\n"
+	"Resolves and lists all packages the given packages depend on. Fails, if\n"
 	"not all dependencies could be resolved.\n"
 	"\n"
 	"Arguments:\n"
 	"  \n"
 	"    The HPKG or package info file of the package for which the\n"
-	"    dependencies shall be resolved.\n"
+	"    dependencies shall be resolved. Multiple files can be specified.\n"
 	"  \n"
 	"    Path to a directory containing packages from which the package's\n"
 	"    dependencies shall be resolved. Multiple directories can be\n"
@@ -76,7 +76,8 @@ check_problems(BSolver* solver, const char* errorContext)
 
 
 static void
-verify_result(const BSolverResult& result, BSolverPackage* specifiedPackage)
+verify_result(const BSolverResult& result,
+	const PackagePathMap& specifiedPackagePaths)
 {
 	// create the solver
 	BSolver* solver;
@@ -85,14 +86,14 @@ verify_result(const BSolverResult& result, BSolverPackage* specifiedPackage)
 		DIE(error, "failed to create solver");
 
 	// Add an installation repository and add all of the result packages save
-	// the specified package.
+	// the specified packages.
 	BSolverRepository installation;
 	RepositoryBuilder installationBuilder(installation, "installation");
 
 	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
 			i++) {
 		BSolverPackage* package = element->Package();
-		if (package != specifiedPackage)
+		if (specifiedPackagePaths.find(package) == specifiedPackagePaths.end())
 			installationBuilder.AddPackage(package->Info());
 	}
 	installationBuilder.AddToSolver(solver, true);
@@ -131,14 +132,26 @@ ResolveDependenciesCommand::Execute(int argc, const char* const* argv)
 		}
 	}
 
-	// The remaining arguments are the package (info) file and the repository
+	// The remaining arguments are the package (info) files and the repository
 	// directories (at least one), optionally with priorities.
 	if (argc < optind + 2)
 		PrintUsageAndExit(true);
 
-	const char* packagePath = argv[optind++];
-	int repositoryDirectoryCount = argc - optind;
+	// Determine where the package list ends and the repository list starts.
+	const char* const* specifiedPackages = argv + optind;
+	for (; optind < argc; optind++) {
+		const char* path = argv[optind];
+		struct stat st;
+		if (stat(path, &st) != 0)
+			DIE(errno, "failed to stat() \"%s\"", path);
+
+		if (S_ISDIR(st.st_mode))
+			break;
+	}
+
 	const char* const* repositoryDirectories = argv + optind;
+	int repositoryDirectoryCount = argc - optind;
+	int specifiedPackageCount = repositoryDirectories - specifiedPackages;
 
 	// create the solver
 	BSolver* solver;
@@ -173,17 +186,27 @@ ResolveDependenciesCommand::Execute(int argc, const char* const* argv)
 			.AddToSolver(solver);
 	}
 
-	// add a repository with only the specified package
+	// add a repository with only the specified packages
+	PackagePathMap specifiedPackagePaths;
 	BSolverRepository dummyRepository;
-	RepositoryBuilder(dummyRepository, "dummy", "specified package")
-		.AddPackage(packagePath)
-		.AddToSolver(solver);
-	BSolverPackage* specifiedPackage = dummyRepository.PackageAt(0);
+	{
+		RepositoryBuilder builder(dummyRepository, "dummy",
+				"specified packages");
+		builder.SetPackagePathMap(&specifiedPackagePaths);
+
+		for (int i = 0; i < specifiedPackageCount; i++)
+			builder.AddPackage(specifiedPackages[i]);
+
+		builder.AddToSolver(solver);
+	}
 
 	// resolve
 	BSolverPackageSpecifierList packagesToInstall;
-	if (!packagesToInstall.AppendSpecifier(specifiedPackage))
-		DIE(B_NO_MEMORY, "failed to add specified package");
+	for (PackagePathMap::const_iterator it = specifiedPackagePaths.begin();
+		it != specifiedPackagePaths.end(); ++it) {
+		if (!packagesToInstall.AppendSpecifier(it->first))
+			DIE(B_NO_MEMORY, "failed to add specified package");
+	}
 
 	error = solver->Install(packagesToInstall);
 	if (error != B_OK)
@@ -197,14 +220,14 @@ ResolveDependenciesCommand::Execute(int argc, const char* const* argv)
 		DIE(error, "failed to resolve package dependencies");
 
 	// Verify that the resolved packages don't depend on the specified package.
-	verify_result(result, specifiedPackage);
+	verify_result(result, specifiedPackagePaths);
 
 	// print packages
 	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
 			i++) {
 		// skip the specified package
 		BSolverPackage* package = element->Package();
-		if (package == specifiedPackage)
+		if (specifiedPackagePaths.find(package) != specifiedPackagePaths.end())
 			continue;
 
 		// resolve and print the path

From ceb18a3777b38ce6a97e5bcd15d3c57731b39e76 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 18 Apr 2013 14:35:59 +0200
Subject: [PATCH 0422/1170] packagefs: Fix typo in debug output

---
 src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
index 2e330d0976..77f833e662 100644
--- a/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/kernel_interface.cpp
@@ -291,7 +291,7 @@ packagefs_ioctl(fs_volume* fsVolume, fs_vnode* fsNode, void* cookie,
 	Volume* volume = (Volume*)fsVolume->private_volume;
 	Node* node = (Node*)fsNode->private_node;
 
-	FUNCTION("volume: %p, node: %p (%lld), cookie: %p, operation: %" B_PRI32u
+	FUNCTION("volume: %p, node: %p (%lld), cookie: %p, operation: %" B_PRIu32
 		", buffer: %p, size: %zu\n", volume, node, node->ID(), cookie,
 		operation, buffer, size);
 	TOUCH(cookie);

From d0367de056d3aa4c9c9f3c4d19f4233899a33f0d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 18 Apr 2013 14:38:24 +0200
Subject: [PATCH 0423/1170] packagefs: Switch to new rule for pre-release
 version part

---
 src/add-ons/kernel/file_systems/packagefs/Version.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Version.cpp b/src/add-ons/kernel/file_systems/packagefs/Version.cpp
index b5206bb5e2..3ea5660d52 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Version.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Version.cpp
@@ -173,7 +173,9 @@ Version::ToString(char* buffer, size_t bufferSize) const
 	// We need to normalize the version string somewhat. If a subpart is given,
 	// make sure that also the superparts are defined, using a placeholder. This
 	// avoids clashes, e.g. if one version defines major and minor and one only
-	// major and micro.
+	// major and micro. In principle that should not be necessary, though. Valid
+	// packages should have valid versions, which means that the existence of a
+	// subpart implies the existence of all superparts.
 	const char* major = fMajor;
 	const char* minor = fMinor;
 	const char* micro = fMicro;
@@ -197,7 +199,7 @@ Version::ToString(char* buffer, size_t bufferSize) const
 
 	if (fPreRelease != NULL) {
 		size_t offset = std::min(bufferSize, size);
-		size += snprintf(buffer + offset, bufferSize - offset, "-%s",
+		size += snprintf(buffer + offset, bufferSize - offset, "[%s]",
 			fPreRelease);
 	}
 

From defc1f774aceb747e6d6b7e3a63b5258cfd345ed Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 18 Apr 2013 14:41:27 +0200
Subject: [PATCH 0424/1170] BPackage{Version,Info}: Switch to new pre-release
 rule

Also add several checks in the package-info parser to enforce the
 requirement of package/resolvable names and
version components.
---
 src/kits/package/PackageInfo.cpp    | 216 ++++++++++++++++++++++------
 src/kits/package/PackageVersion.cpp |   2 +-
 2 files changed, 170 insertions(+), 48 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index b0bd3b9e7b..57ac1d23fe 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -7,6 +7,7 @@
 #include 
 
 #include 
+#include 
 #include 
 #include 
 
@@ -84,7 +85,8 @@ private:
 			Token				_NextToken();
 			void				_RewindTo(const Token& token);
 
-			void				_ParseStringValue(BString* value);
+			void				_ParseStringValue(BString* value,
+									const char** _tokenPos = NULL);
 			uint32				_ParseFlags();
 			void				_ParseArchitectureValue(
 									BPackageArchitecture* value);
@@ -106,6 +108,13 @@ private:
 
 			void				_Parse(BPackageInfo* packageInfo);
 
+	static	bool				_IsAlphaNumUnderscore(const BString& string,
+									int32* _errorPos = NULL);
+	static	bool				_IsAlphaNumUnderscore(const char* string,
+									int32* _errorPos = NULL);
+	static	bool				_IsAlphaNumUnderscore(const char* start,
+									const char* end, int32* _errorPos = NULL);
+
 private:
 			ParseErrorListener*	fListener;
 			const char*			fPos;
@@ -335,7 +344,8 @@ BPackageInfo::Parser::_NextToken()
 		{
 			const char* start = fPos;
 			while (isalnum(*fPos) || *fPos == '.' || *fPos == '-'
-				|| *fPos == '_' || *fPos == ':' || *fPos == '+') {
+				|| *fPos == '_' || *fPos == ':' || *fPos == '+' || *fPos == '['
+				|| *fPos == ']') {
 				fPos++;
 			}
 			if (fPos == start)
@@ -357,13 +367,15 @@ BPackageInfo::Parser::_RewindTo(const Token& token)
 
 
 void
-BPackageInfo::Parser::_ParseStringValue(BString* value)
+BPackageInfo::Parser::_ParseStringValue(BString* value, const char** _tokenPos)
 {
 	Token string = _NextToken();
 	if (string.type != TOKEN_QUOTED_STRING && string.type != TOKEN_WORD)
 		throw ParseError("expected quoted-string or word", string.pos);
 
 	*value = string.text;
+	if (_tokenPos != NULL)
+		*_tokenPos = string.pos;
 }
 
 
@@ -409,21 +421,18 @@ BPackageInfo::Parser::_ParseVersionValue(Token& word, BPackageVersion* value,
 
 	// get the revision number
 	uint32 revision = 0;
-	int32 lastDashPos = word.text.FindLast('-');
-	if (lastDashPos >= 0) {
-		// Might be either the revision number or, if that is optional, a
-		// pre-release. The former always is a number, the latter starts with a
-		// non-digit.
-		if (isdigit(word.text[lastDashPos + 1])) {
-			int number = atoi(word.text.String() + lastDashPos + 1);
-			if (number <= 0) {
-				throw ParseError("revision number must be > 0",
-					word.pos + word.text.Length());
-			}
-			revision = number;
-			word.text.Truncate(lastDashPos);
-			lastDashPos = word.text.FindLast('-');
+	int32 dashPos = word.text.FindLast('-');
+	if (dashPos >= 0) {
+		char* end;
+		long long number = strtoll(word.text.String() + dashPos + 1, &end,
+			0);
+		if (*end != '\0' || number < 0 || number > UINT_MAX) {
+			throw ParseError("revision must be a number > 0 and < UINT_MAX",
+				word.pos + dashPos + 1);
 		}
+
+		revision = (uint32)number;
+		word.text.Truncate(dashPos);
 	}
 
 	if (revision == 0 && !revisionIsOptional) {
@@ -433,14 +442,27 @@ BPackageInfo::Parser::_ParseVersionValue(Token& word, BPackageVersion* value,
 
 	// get the pre-release string
 	BString preRelease;
-	if (lastDashPos >= 0) {
-		if (isdigit(word.text[lastDashPos + 1])) {
-			throw ParseError("pre-release number must not start with a digit",
-				word.pos + word.text.Length());
+	if (word.text.Length() > 0 && word.text[word.text.Length() - 1] == ']') {
+		int32 openingBracket = word.text.FindLast('[');
+		if (openingBracket < 0) {
+			throw ParseError("unmatched ']' in version string",
+				word.pos + word.text.Length() - 1);
 		}
 
-		word.text.CopyInto(preRelease, lastDashPos + 1, word.text.Length());
-		word.text.Truncate(lastDashPos);
+		word.text.CopyInto(preRelease, openingBracket + 1,
+			word.text.Length() - openingBracket - 2);
+		word.text.Truncate(openingBracket);
+
+		if (preRelease.IsEmpty()) {
+			throw ParseError("invalid empty pre-release string",
+				word.pos + openingBracket + 1);
+		}
+
+		int32 errorPos;
+		if (!_IsAlphaNumUnderscore(preRelease, &errorPos)) {
+			throw ParseError("invalid character in pre-release string",
+				word.pos + openingBracket + 1 + errorPos);
+		}
 	}
 
 	// get major, minor, and micro strings
@@ -456,13 +478,31 @@ BPackageInfo::Parser::_ParseVersionValue(Token& word, BPackageVersion* value,
 		if (secondDotPos == firstDotPos + 1)
 			throw ParseError("expected minor version", word.pos + secondDotPos);
 
-		if (secondDotPos < 0)
+		if (secondDotPos < 0) {
 			word.text.CopyInto(minor, firstDotPos + 1, word.text.Length());
-		else {
+		} else {
 			word.text.CopyInto(minor, firstDotPos + 1,
 				secondDotPos - (firstDotPos + 1));
 			word.text.CopyInto(micro, secondDotPos + 1, word.text.Length());
+
+			int32 errorPos;
+			if (!_IsAlphaNumUnderscore(micro, &errorPos)) {
+				throw ParseError("invalid character in micro version string",
+					word.pos + secondDotPos + 1 + errorPos);
+			}
 		}
+
+		int32 errorPos;
+		if (!_IsAlphaNumUnderscore(minor, &errorPos)) {
+			throw ParseError("invalid character in minor version string",
+				word.pos + firstDotPos + 1 + errorPos);
+		}
+	}
+
+	int32 errorPos;
+	if (!_IsAlphaNumUnderscore(major, &errorPos)) {
+		throw ParseError("invalid character in major version string",
+			word.pos + errorPos);
 	}
 
 	value->SetTo(major, minor, micro, preRelease, revision);
@@ -476,7 +516,7 @@ BPackageInfo::Parser::_ParseList(ListElementParser& elementParser,
 	Token openBracket = _NextToken();
 	if (openBracket.type != TOKEN_OPEN_BRACE) {
 		if (!allowSingleNonListElement)
-			throw ParseError("expected start of list ('[')", openBracket.pos);
+			throw ParseError("expected start of list ('{')", openBracket.pos);
 
 		elementParser(openBracket);
 		return;
@@ -620,6 +660,26 @@ BPackageInfo::Parser::_ParseResolvableList(
 				}
 			}
 
+			if (colonPos >= 0) {
+				int32 errorPos;
+				if (!_IsAlphaNumUnderscore(token.text.String(),
+						token.text.String() + colonPos, &errorPos)) {
+					throw ParseError("invalid character in resolvable name",
+						token.pos + errorPos);
+				}
+				if (!_IsAlphaNumUnderscore(token.text.String() + colonPos + 1,
+						&errorPos)) {
+					throw ParseError("invalid character in resolvable name",
+						token.pos + colonPos + 1 + errorPos);
+				}
+			} else {
+				int32 errorPos;
+				if (!_IsAlphaNumUnderscore(token.text, &errorPos)) {
+					throw ParseError("invalid character in resolvable name",
+						token.pos + errorPos);
+				}
+			}
+
 			// parse version
 			BPackageVersion version;
 			Token op = parser._NextToken();
@@ -629,7 +689,7 @@ BPackageInfo::Parser::_ParseResolvableList(
 				|| op.type == TOKEN_CLOSE_BRACE) {
 				parser._RewindTo(op);
 			} else
-				throw ParseError("expected '=', comma or ']'", op.pos);
+				throw ParseError("expected '=', comma or '}'", op.pos);
 
 			// parse compatible version
 			BPackageVersion compatibleVersion;
@@ -677,26 +737,47 @@ BPackageInfo::Parser::_ParseResolvableExprList(
 					token.pos);
 			}
 
-		BPackageVersion version;
-			Token op = parser._NextToken();
-		if (op.type == TOKEN_OPERATOR_LESS
-			|| op.type == TOKEN_OPERATOR_LESS_EQUAL
-			|| op.type == TOKEN_OPERATOR_EQUAL
-			|| op.type == TOKEN_OPERATOR_NOT_EQUAL
-			|| op.type == TOKEN_OPERATOR_GREATER_EQUAL
-			|| op.type == TOKEN_OPERATOR_GREATER) {
-				parser._ParseVersionValue(&version, true);
-		} else if (op.type == TOKEN_ITEM_SEPARATOR
-			|| op.type == TOKEN_CLOSE_BRACE) {
-				parser._RewindTo(op);
-		} else {
-			throw ParseError(
-				"expected '<', '<=', '==', '!=', '>=', '>', comma or ']'",
-				op.pos);
-		}
+			int32 colonPos = token.text.FindFirst(':');
+			if (colonPos >= 0) {
+				int32 errorPos;
+				if (!_IsAlphaNumUnderscore(token.text.String(),
+						token.text.String() + colonPos, &errorPos)) {
+					throw ParseError("invalid character in resolvable name",
+						token.pos + errorPos);
+				}
+				if (!_IsAlphaNumUnderscore(token.text.String() + colonPos + 1,
+						&errorPos)) {
+					throw ParseError("invalid character in resolvable name",
+						token.pos + colonPos + 1 + errorPos);
+				}
+			} else {
+				int32 errorPos;
+				if (!_IsAlphaNumUnderscore(token.text, &errorPos)) {
+					throw ParseError("invalid character in resolvable name",
+						token.pos + errorPos);
+				}
+			}
 
-		BPackageResolvableOperator resolvableOperator
-			= (BPackageResolvableOperator)(op.type - TOKEN_OPERATOR_LESS);
+			BPackageVersion version;
+				Token op = parser._NextToken();
+			if (op.type == TOKEN_OPERATOR_LESS
+				|| op.type == TOKEN_OPERATOR_LESS_EQUAL
+				|| op.type == TOKEN_OPERATOR_EQUAL
+				|| op.type == TOKEN_OPERATOR_NOT_EQUAL
+				|| op.type == TOKEN_OPERATOR_GREATER_EQUAL
+				|| op.type == TOKEN_OPERATOR_GREATER) {
+					parser._ParseVersionValue(&version, true);
+			} else if (op.type == TOKEN_ITEM_SEPARATOR
+				|| op.type == TOKEN_CLOSE_BRACE) {
+					parser._RewindTo(op);
+			} else {
+				throw ParseError(
+					"expected '<', '<=', '=', '==', '!=', '>=', '>', comma or "
+						"'}'", op.pos);
+			}
+
+			BPackageResolvableOperator resolvableOperator
+				= (BPackageResolvableOperator)(op.type - TOKEN_OPERATOR_LESS);
 
 			value->AddItem(new BPackageResolvableExpression(token.text,
 			resolvableOperator, version));
@@ -745,7 +826,15 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 			case B_PACKAGE_INFO_NAME:
 			{
 				BString name;
-				_ParseStringValue(&name);
+				const char* namePos;
+				_ParseStringValue(&name, &namePos);
+
+				int32 errorPos;
+				if (!_IsAlphaNumUnderscore(name, &errorPos)) {
+					throw ParseError("invalid character in package name",
+						namePos + errorPos);
+				}
+
 				packageInfo->SetName(name);
 				break;
 			}
@@ -842,6 +931,39 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 }
 
 
+/*static*/ inline bool
+BPackageInfo::Parser::_IsAlphaNumUnderscore(const BString& string,
+	int32* _errorPos)
+{
+	return _IsAlphaNumUnderscore(string.String(),
+		string.String() + string.Length(), _errorPos);
+}
+
+
+/*static*/ inline bool
+BPackageInfo::Parser::_IsAlphaNumUnderscore(const char* string,
+	int32* _errorPos)
+{
+	return _IsAlphaNumUnderscore(string, string + strlen(string), _errorPos);
+}
+
+
+/*static*/ bool
+BPackageInfo::Parser::_IsAlphaNumUnderscore(const char* start, const char* end,
+	int32* _errorPos)
+{
+	for (const char* c = start; c < end; c++) {
+		if (!isalnum(*c) && *c != '_') {
+			if (_errorPos != NULL)
+				*_errorPos = c - start;
+			return false;
+		}
+	}
+
+	return true;
+}
+
+
 const char* BPackageInfo::kElementNames[B_PACKAGE_INFO_ENUM_COUNT] = {
 	"name",
 	"summary",
diff --git a/src/kits/package/PackageVersion.cpp b/src/kits/package/PackageVersion.cpp
index 6aedbad07e..b63d4f5a03 100644
--- a/src/kits/package/PackageVersion.cpp
+++ b/src/kits/package/PackageVersion.cpp
@@ -133,7 +133,7 @@ BPackageVersion::ToString() const
 	}
 
 	if (!fPreRelease.IsEmpty())
-		string << '-' << fPreRelease;
+		string << '[' << fPreRelease << ']';
 
 	if (fRevision > 0)
 		string << '-' << fRevision;

From 7b2d06214738875b3da5a19cfebabec7f9d7ace6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 18 Apr 2013 14:43:15 +0200
Subject: [PATCH 0425/1170] Enforce current package rules for packages built
 from tree

* Replace '-' in package name by '_'.
* Use new '[...]' notation for pre-release version component.
---
 build/jam/HaikuPackages                       | 24 +++++++++----------
 build/jam/OptionalPackages                    |  8 +++----
 src/data/package_infos/haiku                  |  4 ++--
 .../{haiku-devel => haiku_devel}              |  8 +++----
 .../{haiku-userguide => haiku_userguide}      |  6 ++---
 .../{haiku-welcome => haiku_welcome}          |  6 ++---
 .../{makefile-engine => makefile_engine}      |  6 ++---
 7 files changed, 31 insertions(+), 31 deletions(-)
 rename src/data/package_infos/{haiku-devel => haiku_devel} (79%)
 rename src/data/package_infos/{haiku-userguide => haiku_userguide} (75%)
 rename src/data/package_infos/{haiku-welcome => haiku_welcome} (77%)
 rename src/data/package_infos/{makefile-engine => makefile_engine} (77%)

diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages
index cda49ffdeb..896cdcd288 100644
--- a/build/jam/HaikuPackages
+++ b/build/jam/HaikuPackages
@@ -355,10 +355,10 @@ CopyDirectoryToPackage documentation
 BuildHaikuPackage $(haikuPackage) : haiku ;
 
 
-#pragma mark - haiku-devel.hpkg
+#pragma mark - haiku_devel.hpkg
 
 
-local haikuDevelPackage = haiku-devel.hpkg ;
+local haikuDevelPackage = haiku_devel.hpkg ;
 HaikuPackage $(haikuDevelPackage) ;
 
 local arch = $(TARGET_ARCH) ;
@@ -435,13 +435,13 @@ if $(HAIKU_GCC_VERSION[1]) = 2 {
 		: [ FDirName $(HAIKU_TOP) headers cpp ] : 2.95.3 : -x .svn ;
 }
 
-BuildHaikuPackage $(haikuDevelPackage) : haiku-devel ;
+BuildHaikuPackage $(haikuDevelPackage) : haiku_devel ;
 
 
-#pragma mark - haiku-userguide.hpkg
+#pragma mark - haiku_userguide.hpkg
 
 
-local haikuUserGuidePackage = haiku-userguide.hpkg ;
+local haikuUserGuidePackage = haiku_userguide.hpkg ;
 HaikuPackage $(haikuUserGuidePackage) ;
 
 CopyDirectoryToPackage documentation : [ FDirName $(HAIKU_TOP) docs userguide ]
@@ -449,13 +449,13 @@ CopyDirectoryToPackage documentation : [ FDirName $(HAIKU_TOP) docs userguide ]
 SEARCH on userguide = [ FDirName $(HAIKU_TOP) data bin ] ;
 AddFilesToPackage bin : userguide ;
 
-BuildHaikuPackage $(haikuUserGuidePackage) : haiku-userguide ;
+BuildHaikuPackage $(haikuUserGuidePackage) : haiku_userguide ;
 
 
-#pragma mark - haiku-welcome.hpkg
+#pragma mark - haiku_welcome.hpkg
 
 
-local haikuWelcomePackage = haiku-welcome.hpkg ;
+local haikuWelcomePackage = haiku_welcome.hpkg ;
 HaikuPackage $(haikuWelcomePackage) ;
 
 CopyDirectoryToPackage documentation : [ FDirName $(HAIKU_TOP) docs welcome ]
@@ -463,13 +463,13 @@ CopyDirectoryToPackage documentation : [ FDirName $(HAIKU_TOP) docs welcome ]
 SEARCH on welcome = [ FDirName $(HAIKU_TOP) data bin ] ;
 AddFilesToPackage bin : welcome ;
 
-BuildHaikuPackage $(haikuWelcomePackage) : haiku-welcome ;
+BuildHaikuPackage $(haikuWelcomePackage) : haiku_welcome ;
 
 
-#pragma mark - makefile-engine.hpkg
+#pragma mark - makefile_engine.hpkg
 
 
-local makefileEnginePackage = makefile-engine.hpkg ;
+local makefileEnginePackage = makefile_engine.hpkg ;
 HaikuPackage $(makefileEnginePackage) ;
 
 # skeleton makefile and makefile-engine
@@ -480,4 +480,4 @@ local makefileEngineFiles =
 SEARCH on $(makefileEngineFiles) = [ FDirName $(HAIKU_TOP) data develop ] ;
 AddFilesToPackage develop etc : $(makefileEngineFiles) ;
 
-BuildHaikuPackage $(makefileEnginePackage) : makefile-engine ;
+BuildHaikuPackage $(makefileEnginePackage) : makefile_engine ;
diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index d31636966c..be28c41153 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -565,8 +565,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentMin ] && $(TARGET_ARCH) = x86 {
 			$(HAIKU_GCC_VERSION[1]) ;
 	}
 
-	AddFilesToHaikuImage system packages : haiku-devel.hpkg ;
-	AddFilesToHaikuImage common packages : makefile-engine.hpkg ;
+	AddFilesToHaikuImage system packages : haiku_devel.hpkg ;
+	AddFilesToHaikuImage common packages : makefile_engine.hpkg ;
 }
 
 
@@ -1477,8 +1477,8 @@ if [ IsOptionalHaikuImagePackageAdded WebPositive ] {
 
 # Welcome
 if [ IsOptionalHaikuImagePackageAdded Welcome ] {
-	AddFilesToHaikuImage system packages : haiku-userguide.hpkg ;
-	AddFilesToHaikuImage system packages : haiku-welcome.hpkg ;
+	AddFilesToHaikuImage system packages : haiku_userguide.hpkg ;
+	AddFilesToHaikuImage system packages : haiku_welcome.hpkg ;
 
 	AddSymlinkToHaikuImage home Desktop	: /boot/system/bin/welcome
 		: Welcome ;
diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku
index c72c65d1fb..d9e60fd01e 100644
--- a/src/data/package_infos/haiku
+++ b/src/data/package_infos/haiku
@@ -1,5 +1,5 @@
 name 			haiku
-version			R1-alpha3_pm-1
+version			R1[alpha3_pm]-1
 architecture	x86_gcc2
 summary			"The Haiku base system"
 
@@ -16,7 +16,7 @@ licenses {
 }
 
 provides {
-	haiku=R1-alpha3_pm-1 compat>=R1-alpha1
+	haiku=R1[alpha3_pm]-1 compat>=R1[alpha1]
 	coreutils=8.4 compat>=0.0
 	diffutils=2.8.1 compat>=0.0
 	findutils=4.2.33 compat>=0.0
diff --git a/src/data/package_infos/haiku-devel b/src/data/package_infos/haiku_devel
similarity index 79%
rename from src/data/package_infos/haiku-devel
rename to src/data/package_infos/haiku_devel
index de21f9a864..f9a734b64f 100644
--- a/src/data/package_infos/haiku-devel
+++ b/src/data/package_infos/haiku_devel
@@ -1,5 +1,5 @@
-name			haiku-devel
-version			R1-alpha3_pm-1
+name			haiku_devel
+version			R1[alpha3_pm]-1
 architecture	x86_gcc2
 summary			"The Haiku base system development files"
 
@@ -14,9 +14,9 @@ copyrights		"2001-2011 Haiku, Inc. et al"
 licenses		"MIT"
 
 provides {
-	haiku-devel=R1-alpha3_pm-1
+	haiku_devel=R1[alpha3_pm]-1
 }
 
 requires {
-	haiku
+	haiku == R1[alpha3_pm]-1
 }
diff --git a/src/data/package_infos/haiku-userguide b/src/data/package_infos/haiku_userguide
similarity index 75%
rename from src/data/package_infos/haiku-userguide
rename to src/data/package_infos/haiku_userguide
index cfef5a6d25..2b0dd50927 100644
--- a/src/data/package_infos/haiku-userguide
+++ b/src/data/package_infos/haiku_userguide
@@ -1,5 +1,5 @@
-name			haiku-userguide
-version			R1-alpha3_pm-1
+name			haiku_userguide
+version			R1[alpha3_pm]-1
 architecture	any
 summary			"The Haiku user documentation"
 description		"The Haiku user documentation."
@@ -11,7 +11,7 @@ copyrights		"2001-2011 Haiku, Inc. et al"
 licenses		MIT
 
 provides {
-	haiku-userguide=R1-alpha3_pm-1
+	haiku_userguide=R1[alpha3_pm]-1
 }
 
 requires {
diff --git a/src/data/package_infos/haiku-welcome b/src/data/package_infos/haiku_welcome
similarity index 77%
rename from src/data/package_infos/haiku-welcome
rename to src/data/package_infos/haiku_welcome
index b5c349e233..cdbc2a33b9 100644
--- a/src/data/package_infos/haiku-welcome
+++ b/src/data/package_infos/haiku_welcome
@@ -1,5 +1,5 @@
-name			haiku-welcome
-version			R1-alpha3_pm-1
+name			haiku_welcome
+version			R1[alpha3_pm]-1
 architecture	any
 summary			"The Haiku welcome documentation"
 description		"The Haiku welcome documentation for new users."
@@ -11,7 +11,7 @@ copyrights		"2001-2011 Haiku, Inc. et al"
 licenses		"MIT"
 
 provides {
-	haiku-welcome=R1-alpha3_pm-1
+	haiku_welcome=R1[alpha3_pm]-1
 }
 
 requires {
diff --git a/src/data/package_infos/makefile-engine b/src/data/package_infos/makefile_engine
similarity index 77%
rename from src/data/package_infos/makefile-engine
rename to src/data/package_infos/makefile_engine
index 31387409a1..5f6238ddad 100644
--- a/src/data/package_infos/makefile-engine
+++ b/src/data/package_infos/makefile_engine
@@ -1,5 +1,5 @@
-name			makefile-engine
-version			R1-alpha3_pm-1
+name			makefile_engine
+version			R1[alpha3_pm]-1
 architecture	any
 summary			"The makefile engine"
 description 	"A simple generic makefile engine and makefile template."
@@ -11,7 +11,7 @@ copyrights		"? Be Inc. 2001-2011 Haiku, Inc."
 licenses		MIT
 
 provides {
-	makefile-engine=R1-alpha3_pm-1
+	makefile_engine=R1[alpha3_pm]-1
 }
 
 requires {

From 5e6adff9893e2566c886da1f46159967a93b15c5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 18 Apr 2013 15:12:04 +0200
Subject: [PATCH 0426/1170] BPackageVersion::ToString(): Return empty string,
 if invalid

---
 src/kits/package/PackageVersion.cpp | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/src/kits/package/PackageVersion.cpp b/src/kits/package/PackageVersion.cpp
index b63d4f5a03..0a0a947f8d 100644
--- a/src/kits/package/PackageVersion.cpp
+++ b/src/kits/package/PackageVersion.cpp
@@ -124,6 +124,9 @@ BPackageVersion::Compare(const BPackageVersion& other) const
 BString
 BPackageVersion::ToString() const
 {
+	if (InitCheck() != B_OK)
+		return BString();
+
 	BString string = fMajor;
 
 	if (fMinor.Length() > 0) {

From 7fa369956e1b30f61679ae5552b5f018a9e76578 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 18 Apr 2013 15:52:57 +0200
Subject: [PATCH 0427/1170] BOpenHashTable::Clear(): Set fItemCount to 0

If not empty, the count would afterwards be out of sync with reality.
---
 headers/private/kernel/util/OpenHashTable.h | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/headers/private/kernel/util/OpenHashTable.h b/headers/private/kernel/util/OpenHashTable.h
index be711c4ac8..a2af3aaf37 100644
--- a/headers/private/kernel/util/OpenHashTable.h
+++ b/headers/private/kernel/util/OpenHashTable.h
@@ -230,7 +230,7 @@ public:
 	*/
 	ValueType* Clear(bool returnElements = false)
 	{
-		if (this->fItemCount == 0)
+		if (fItemCount == 0)
 			return NULL;
 
 		ValueType* result = NULL;
@@ -256,6 +256,7 @@ public:
 		}
 
 		memset(this->fTable, 0, sizeof(ValueType*) * this->fTableSize);
+		fItemCount = 0;
 
 		return result;
 	}

From b7c89d42a67fa5b8d9087f0ab2948e286b335cf7 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 18 Apr 2013 17:44:28 +0200
Subject: [PATCH 0428/1170] packagefs: Use '~' as pre-release separator

"[...]" turns out to be not so good an idea after all. In the shell it
would require escaping.
---
 src/add-ons/kernel/file_systems/packagefs/Version.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/add-ons/kernel/file_systems/packagefs/Version.cpp b/src/add-ons/kernel/file_systems/packagefs/Version.cpp
index 3ea5660d52..849453f595 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Version.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Version.cpp
@@ -199,7 +199,7 @@ Version::ToString(char* buffer, size_t bufferSize) const
 
 	if (fPreRelease != NULL) {
 		size_t offset = std::min(bufferSize, size);
-		size += snprintf(buffer + offset, bufferSize - offset, "[%s]",
+		size += snprintf(buffer + offset, bufferSize - offset, "~%s",
 			fPreRelease);
 	}
 

From 9d81dc7655a984ce6dd0d79878215fe4d5748da6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 18 Apr 2013 17:48:25 +0200
Subject: [PATCH 0429/1170] BPackage{Info,Version}: Switch to '~' as
 pre-release separator

Also allow '.' in the pre-release string (as in "alpha4.1") and in
package and resolvable names.
---
 src/kits/package/PackageInfo.cpp    | 125 +++++++++++++---------------
 src/kits/package/PackageVersion.cpp |   2 +-
 2 files changed, 61 insertions(+), 66 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 57ac1d23fe..967cfc6b53 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -109,11 +109,17 @@ private:
 			void				_Parse(BPackageInfo* packageInfo);
 
 	static	bool				_IsAlphaNumUnderscore(const BString& string,
-									int32* _errorPos = NULL);
+									const char* additionalChars,
+									int32* _errorPos);
 	static	bool				_IsAlphaNumUnderscore(const char* string,
-									int32* _errorPos = NULL);
+									const char* additionalChars,
+									int32* _errorPos);
 	static	bool				_IsAlphaNumUnderscore(const char* start,
-									const char* end, int32* _errorPos = NULL);
+									const char* end,
+									const char* additionalChars,
+									int32* _errorPos);
+	static	bool				_IsValidResolvableName(const char* string,
+									int32* _errorPos);
 
 private:
 			ParseErrorListener*	fListener;
@@ -344,8 +350,8 @@ BPackageInfo::Parser::_NextToken()
 		{
 			const char* start = fPos;
 			while (isalnum(*fPos) || *fPos == '.' || *fPos == '-'
-				|| *fPos == '_' || *fPos == ':' || *fPos == '+' || *fPos == '['
-				|| *fPos == ']') {
+				|| *fPos == '_' || *fPos == ':' || *fPos == '+'
+				|| *fPos == '~') {
 				fPos++;
 			}
 			if (fPos == start)
@@ -442,26 +448,21 @@ BPackageInfo::Parser::_ParseVersionValue(Token& word, BPackageVersion* value,
 
 	// get the pre-release string
 	BString preRelease;
-	if (word.text.Length() > 0 && word.text[word.text.Length() - 1] == ']') {
-		int32 openingBracket = word.text.FindLast('[');
-		if (openingBracket < 0) {
-			throw ParseError("unmatched ']' in version string",
-				word.pos + word.text.Length() - 1);
-		}
-
-		word.text.CopyInto(preRelease, openingBracket + 1,
-			word.text.Length() - openingBracket - 2);
-		word.text.Truncate(openingBracket);
+	int32 tildePos = word.text.FindLast('~');
+	if (tildePos >= 0) {
+		word.text.CopyInto(preRelease, tildePos + 1,
+			word.text.Length() - tildePos - 1);
+		word.text.Truncate(tildePos);
 
 		if (preRelease.IsEmpty()) {
 			throw ParseError("invalid empty pre-release string",
-				word.pos + openingBracket + 1);
+				word.pos + tildePos + 1);
 		}
 
 		int32 errorPos;
-		if (!_IsAlphaNumUnderscore(preRelease, &errorPos)) {
+		if (!_IsAlphaNumUnderscore(preRelease, ".", &errorPos)) {
 			throw ParseError("invalid character in pre-release string",
-				word.pos + openingBracket + 1 + errorPos);
+				word.pos + tildePos + 1 + errorPos);
 		}
 	}
 
@@ -486,21 +487,21 @@ BPackageInfo::Parser::_ParseVersionValue(Token& word, BPackageVersion* value,
 			word.text.CopyInto(micro, secondDotPos + 1, word.text.Length());
 
 			int32 errorPos;
-			if (!_IsAlphaNumUnderscore(micro, &errorPos)) {
+			if (!_IsAlphaNumUnderscore(micro, "", &errorPos)) {
 				throw ParseError("invalid character in micro version string",
 					word.pos + secondDotPos + 1 + errorPos);
 			}
 		}
 
 		int32 errorPos;
-		if (!_IsAlphaNumUnderscore(minor, &errorPos)) {
+		if (!_IsAlphaNumUnderscore(minor, "", &errorPos)) {
 			throw ParseError("invalid character in minor version string",
 				word.pos + firstDotPos + 1 + errorPos);
 		}
 	}
 
 	int32 errorPos;
-	if (!_IsAlphaNumUnderscore(major, &errorPos)) {
+	if (!_IsAlphaNumUnderscore(major, "", &errorPos)) {
 		throw ParseError("invalid character in major version string",
 			word.pos + errorPos);
 	}
@@ -660,24 +661,10 @@ BPackageInfo::Parser::_ParseResolvableList(
 				}
 			}
 
-			if (colonPos >= 0) {
-				int32 errorPos;
-				if (!_IsAlphaNumUnderscore(token.text.String(),
-						token.text.String() + colonPos, &errorPos)) {
-					throw ParseError("invalid character in resolvable name",
-						token.pos + errorPos);
-				}
-				if (!_IsAlphaNumUnderscore(token.text.String() + colonPos + 1,
-						&errorPos)) {
-					throw ParseError("invalid character in resolvable name",
-						token.pos + colonPos + 1 + errorPos);
-				}
-			} else {
-				int32 errorPos;
-				if (!_IsAlphaNumUnderscore(token.text, &errorPos)) {
-					throw ParseError("invalid character in resolvable name",
-						token.pos + errorPos);
-				}
+			int32 errorPos;
+			if (!_IsValidResolvableName(token.text, &errorPos)) {
+				throw ParseError("invalid character in resolvable name",
+					token.pos + errorPos);
 			}
 
 			// parse version
@@ -737,25 +724,10 @@ BPackageInfo::Parser::_ParseResolvableExprList(
 					token.pos);
 			}
 
-			int32 colonPos = token.text.FindFirst(':');
-			if (colonPos >= 0) {
-				int32 errorPos;
-				if (!_IsAlphaNumUnderscore(token.text.String(),
-						token.text.String() + colonPos, &errorPos)) {
-					throw ParseError("invalid character in resolvable name",
-						token.pos + errorPos);
-				}
-				if (!_IsAlphaNumUnderscore(token.text.String() + colonPos + 1,
-						&errorPos)) {
-					throw ParseError("invalid character in resolvable name",
-						token.pos + colonPos + 1 + errorPos);
-				}
-			} else {
-				int32 errorPos;
-				if (!_IsAlphaNumUnderscore(token.text, &errorPos)) {
-					throw ParseError("invalid character in resolvable name",
-						token.pos + errorPos);
-				}
+			int32 errorPos;
+			if (!_IsValidResolvableName(token.text, &errorPos)) {
+				throw ParseError("invalid character in resolvable name",
+					token.pos + errorPos);
 			}
 
 			BPackageVersion version;
@@ -830,7 +802,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				_ParseStringValue(&name, &namePos);
 
 				int32 errorPos;
-				if (!_IsAlphaNumUnderscore(name, &errorPos)) {
+				if (!_IsAlphaNumUnderscore(name, ".", &errorPos)) {
 					throw ParseError("invalid character in package name",
 						namePos + errorPos);
 				}
@@ -933,27 +905,28 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 
 /*static*/ inline bool
 BPackageInfo::Parser::_IsAlphaNumUnderscore(const BString& string,
-	int32* _errorPos)
+	const char* additionalChars, int32* _errorPos)
 {
 	return _IsAlphaNumUnderscore(string.String(),
-		string.String() + string.Length(), _errorPos);
+		string.String() + string.Length(), additionalChars, _errorPos);
 }
 
 
 /*static*/ inline bool
 BPackageInfo::Parser::_IsAlphaNumUnderscore(const char* string,
-	int32* _errorPos)
+	const char* additionalChars, int32* _errorPos)
 {
-	return _IsAlphaNumUnderscore(string, string + strlen(string), _errorPos);
+	return _IsAlphaNumUnderscore(string, string + strlen(string),
+		additionalChars, _errorPos);
 }
 
 
 /*static*/ bool
 BPackageInfo::Parser::_IsAlphaNumUnderscore(const char* start, const char* end,
-	int32* _errorPos)
+	const char* additionalChars, int32* _errorPos)
 {
 	for (const char* c = start; c < end; c++) {
-		if (!isalnum(*c) && *c != '_') {
+		if (!isalnum(*c) && *c != '_' && strchr(additionalChars, *c) == NULL) {
 			if (_errorPos != NULL)
 				*_errorPos = c - start;
 			return false;
@@ -964,6 +937,28 @@ BPackageInfo::Parser::_IsAlphaNumUnderscore(const char* start, const char* end,
 }
 
 
+/*static*/ bool
+BPackageInfo::Parser::_IsValidResolvableName(const char* string,
+	int32* _errorPos)
+{
+	int32 errorPos;
+	if (const char* colon = strchr(string, ':')) {
+		if (_IsAlphaNumUnderscore(string, colon, ".", &errorPos)) {
+			if (_IsAlphaNumUnderscore(colon + 1, ".", &errorPos))
+				return true;
+			errorPos += colon + 1 - string;
+		}
+	} else {
+		if (_IsAlphaNumUnderscore(string, ".", &errorPos))
+			return true;
+	}
+
+	if (_errorPos != NULL)
+		*_errorPos = errorPos;
+	return false;
+}
+
+
 const char* BPackageInfo::kElementNames[B_PACKAGE_INFO_ENUM_COUNT] = {
 	"name",
 	"summary",
diff --git a/src/kits/package/PackageVersion.cpp b/src/kits/package/PackageVersion.cpp
index 0a0a947f8d..157aec8c25 100644
--- a/src/kits/package/PackageVersion.cpp
+++ b/src/kits/package/PackageVersion.cpp
@@ -136,7 +136,7 @@ BPackageVersion::ToString() const
 	}
 
 	if (!fPreRelease.IsEmpty())
-		string << '[' << fPreRelease << ']';
+		string << '~' << fPreRelease;
 
 	if (fRevision > 0)
 		string << '-' << fRevision;

From 06b4ebe51c4eb83f00f912cf88fe13a41e5d9a6d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 18 Apr 2013 17:50:06 +0200
Subject: [PATCH 0430/1170] package-infos in tree: use '~' as pre-release
 separator

---
 src/data/package_infos/haiku           | 4 ++--
 src/data/package_infos/haiku_devel     | 6 +++---
 src/data/package_infos/haiku_userguide | 4 ++--
 src/data/package_infos/haiku_welcome   | 4 ++--
 src/data/package_infos/makefile_engine | 4 ++--
 5 files changed, 11 insertions(+), 11 deletions(-)

diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku
index d9e60fd01e..c7fb256813 100644
--- a/src/data/package_infos/haiku
+++ b/src/data/package_infos/haiku
@@ -1,5 +1,5 @@
 name 			haiku
-version			R1[alpha3_pm]-1
+version			R1~alpha3_pm-1
 architecture	x86_gcc2
 summary			"The Haiku base system"
 
@@ -16,7 +16,7 @@ licenses {
 }
 
 provides {
-	haiku=R1[alpha3_pm]-1 compat>=R1[alpha1]
+	haiku=R1~alpha3_pm-1 compat>=R1~alpha1
 	coreutils=8.4 compat>=0.0
 	diffutils=2.8.1 compat>=0.0
 	findutils=4.2.33 compat>=0.0
diff --git a/src/data/package_infos/haiku_devel b/src/data/package_infos/haiku_devel
index f9a734b64f..b4ff007c5d 100644
--- a/src/data/package_infos/haiku_devel
+++ b/src/data/package_infos/haiku_devel
@@ -1,5 +1,5 @@
 name			haiku_devel
-version			R1[alpha3_pm]-1
+version			R1~alpha3_pm-1
 architecture	x86_gcc2
 summary			"The Haiku base system development files"
 
@@ -14,9 +14,9 @@ copyrights		"2001-2011 Haiku, Inc. et al"
 licenses		"MIT"
 
 provides {
-	haiku_devel=R1[alpha3_pm]-1
+	haiku_devel=R1~alpha3_pm-1
 }
 
 requires {
-	haiku == R1[alpha3_pm]-1
+	haiku == R1~alpha3_pm-1
 }
diff --git a/src/data/package_infos/haiku_userguide b/src/data/package_infos/haiku_userguide
index 2b0dd50927..4d8c2319de 100644
--- a/src/data/package_infos/haiku_userguide
+++ b/src/data/package_infos/haiku_userguide
@@ -1,5 +1,5 @@
 name			haiku_userguide
-version			R1[alpha3_pm]-1
+version			R1~alpha3_pm-1
 architecture	any
 summary			"The Haiku user documentation"
 description		"The Haiku user documentation."
@@ -11,7 +11,7 @@ copyrights		"2001-2011 Haiku, Inc. et al"
 licenses		MIT
 
 provides {
-	haiku_userguide=R1[alpha3_pm]-1
+	haiku_userguide=R1~alpha3_pm-1
 }
 
 requires {
diff --git a/src/data/package_infos/haiku_welcome b/src/data/package_infos/haiku_welcome
index cdbc2a33b9..a076a9e076 100644
--- a/src/data/package_infos/haiku_welcome
+++ b/src/data/package_infos/haiku_welcome
@@ -1,5 +1,5 @@
 name			haiku_welcome
-version			R1[alpha3_pm]-1
+version			R1~alpha3_pm-1
 architecture	any
 summary			"The Haiku welcome documentation"
 description		"The Haiku welcome documentation for new users."
@@ -11,7 +11,7 @@ copyrights		"2001-2011 Haiku, Inc. et al"
 licenses		"MIT"
 
 provides {
-	haiku_welcome=R1[alpha3_pm]-1
+	haiku_welcome=R1~alpha3_pm-1
 }
 
 requires {
diff --git a/src/data/package_infos/makefile_engine b/src/data/package_infos/makefile_engine
index 5f6238ddad..39314a0cf3 100644
--- a/src/data/package_infos/makefile_engine
+++ b/src/data/package_infos/makefile_engine
@@ -1,5 +1,5 @@
 name			makefile_engine
-version			R1[alpha3_pm]-1
+version			R1~alpha3_pm-1
 architecture	any
 summary			"The makefile engine"
 description 	"A simple generic makefile engine and makefile template."
@@ -11,7 +11,7 @@ copyrights		"? Be Inc. 2001-2011 Haiku, Inc."
 licenses		MIT
 
 provides {
-	makefile_engine=R1[alpha3_pm]-1
+	makefile_engine=R1~alpha3_pm-1
 }
 
 requires {

From ea8b5c257d37d7dacc221a3535548d03edfa3871 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Thu, 18 Apr 2013 18:43:47 +0200
Subject: [PATCH 0431/1170] BPackageInfo parser: Allow '.' in micro version
 component

Otherwise we'd have to encode e.g. "cvs-1.12.13.1" differently.
---
 src/kits/package/PackageInfo.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 967cfc6b53..15e425859e 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -487,7 +487,7 @@ BPackageInfo::Parser::_ParseVersionValue(Token& word, BPackageVersion* value,
 			word.text.CopyInto(micro, secondDotPos + 1, word.text.Length());
 
 			int32 errorPos;
-			if (!_IsAlphaNumUnderscore(micro, "", &errorPos)) {
+			if (!_IsAlphaNumUnderscore(micro, ".", &errorPos)) {
 				throw ParseError("invalid character in micro version string",
 					word.pos + secondDotPos + 1 + errorPos);
 			}

From b50e5e330702837e70cb1a1ef04d37aacf327fa3 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 19 Apr 2013 01:31:47 +0200
Subject: [PATCH 0432/1170] package[_repo]: Print version correctly

Use BPackageVersion::ToString() instead of assembling the version
string manually. This fixes the incorrect pre-release separator.
---
 src/bin/package/command_list.cpp      | 10 +---------
 src/bin/package_repo/command_list.cpp | 10 +---------
 2 files changed, 2 insertions(+), 18 deletions(-)

diff --git a/src/bin/package/command_list.cpp b/src/bin/package/command_list.cpp
index 63569b16a0..3c0909c751 100644
--- a/src/bin/package/command_list.cpp
+++ b/src/bin/package/command_list.cpp
@@ -265,15 +265,7 @@ private:
 
 	static void _PrintPackageVersion(const BPackageVersionData& version)
 	{
-		printf("%s", version.major);
-		if (version.minor != NULL && version.minor[0] != '\0')
-			printf(".%s", version.minor);
-		if (version.micro != NULL && version.micro[0] != '\0')
-			printf(".%s", version.micro);
-		if (version.preRelease != NULL && version.preRelease[0] != '\0')
-			printf("-%s", version.preRelease);
-		if (version.revision > 0)
-			printf("-%" B_PRIu32, version.revision);
+		printf("%s", BPackageVersion(version).ToString().String());
 	}
 
 private:
diff --git a/src/bin/package_repo/command_list.cpp b/src/bin/package_repo/command_list.cpp
index 38d2842722..9faa532a8b 100644
--- a/src/bin/package_repo/command_list.cpp
+++ b/src/bin/package_repo/command_list.cpp
@@ -231,15 +231,7 @@ struct RepositoryContentListHandler : BRepositoryContentHandler {
 private:
 	static void _PrintPackageVersion(const BPackageVersionData& version)
 	{
-		printf("%s", version.major);
-		if (version.minor != NULL && version.minor[0] != '\0')
-			printf(".%s", version.minor);
-		if (version.micro != NULL && version.micro[0] != '\0')
-			printf(".%s", version.micro);
-		if (version.preRelease != NULL && version.preRelease[0] != '\0')
-			printf("-%s", version.preRelease);
-		if (version.revision > 0)
-			printf("-%" B_PRIu32, version.revision);
+		printf("%s", BPackageVersion(version).ToString().String());
 	}
 
 private:

From f16dbba4422edc0a409b8e781bbb3608ccd61e45 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 19 Apr 2013 01:34:26 +0200
Subject: [PATCH 0433/1170] Update libsolv package

---
 build/jam/OptionalBuildFeatures | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures
index a3e087d068..8cbad213b8 100644
--- a/build/jam/OptionalBuildFeatures
+++ b/build/jam/OptionalBuildFeatures
@@ -221,7 +221,7 @@ if $(TARGET_ARCH) != x86 {
 	Echo "Libsolv not available for $(TARGET_ARCH)." ;
 } else if $(HAIKU_GCC_VERSION[1]) = 2 {
 	HAIKU_LIBSOLV_PACKAGE
-		= libsolv-0.3.0_haiku_2013_04_15-1-x86_gcc2.hpkg ;
+		= libsolv-0.3.0_haiku_2013_04_18-1-x86_gcc2.hpkg ;
 } else {
 	Echo "Libsolv not available for gcc4." ;
 }

From cba60307b80a1b91619960b7b9dcf30745c8370a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 19 Apr 2013 16:04:27 +0200
Subject: [PATCH 0434/1170] BPackageInfo::Parser: Relax package/resolvable name
 rules

Now we allow any character but '-', '/', and whitespace.
---
 src/kits/package/PackageInfo.cpp | 21 +++++++--------------
 1 file changed, 7 insertions(+), 14 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 15e425859e..89e645f26e 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -802,7 +802,7 @@ BPackageInfo::Parser::_Parse(BPackageInfo* packageInfo)
 				_ParseStringValue(&name, &namePos);
 
 				int32 errorPos;
-				if (!_IsAlphaNumUnderscore(name, ".", &errorPos)) {
+				if (!_IsValidResolvableName(name, &errorPos)) {
 					throw ParseError("invalid character in package name",
 						namePos + errorPos);
 				}
@@ -941,21 +941,14 @@ BPackageInfo::Parser::_IsAlphaNumUnderscore(const char* start, const char* end,
 BPackageInfo::Parser::_IsValidResolvableName(const char* string,
 	int32* _errorPos)
 {
-	int32 errorPos;
-	if (const char* colon = strchr(string, ':')) {
-		if (_IsAlphaNumUnderscore(string, colon, ".", &errorPos)) {
-			if (_IsAlphaNumUnderscore(colon + 1, ".", &errorPos))
-				return true;
-			errorPos += colon + 1 - string;
+	for (const char* c = string; *c != '\0'; c++) {
+		if (*c == '-' || *c == '/' || isspace(*c)) {
+			if (_errorPos != NULL)
+				*_errorPos = c - string;
+			return false;
 		}
-	} else {
-		if (_IsAlphaNumUnderscore(string, ".", &errorPos))
-			return true;
 	}
-
-	if (_errorPos != NULL)
-		*_errorPos = errorPos;
-	return false;
+	return true;
 }
 
 

From 00b5554e118bf70414d455dbaa6a4ce4d5eaea6a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 19 Apr 2013 16:06:11 +0200
Subject: [PATCH 0435/1170] pkgman: Print correct error when parsing package
 info failed

---
 src/bin/pkgman/RepositoryBuilder.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/bin/pkgman/RepositoryBuilder.cpp b/src/bin/pkgman/RepositoryBuilder.cpp
index 1b7e0e9b1a..be765ee4d9 100644
--- a/src/bin/pkgman/RepositoryBuilder.cpp
+++ b/src/bin/pkgman/RepositoryBuilder.cpp
@@ -91,7 +91,7 @@ RepositoryBuilder::AddPackage(const char* path, BSolverPackage** _package)
 	}
 
 	if (error != B_OK)
-		DIE(errno, "failed to read package info from \"%s\"", path);
+		DIE(error, "failed to read package info from \"%s\"", path);
 
 	// add the package
 	BSolverPackage* package;

From 3c6784e95caa334caa98f6f61b0d08385fa21e0b Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Fri, 19 Apr 2013 16:21:42 +0200
Subject: [PATCH 0436/1170] BPackageInfo::Parser: Be a bit stricter wrt. names
 after all

Also disallow the operator characters in names.
---
 src/kits/package/PackageInfo.cpp | 20 ++++++++++++++++----
 1 file changed, 16 insertions(+), 4 deletions(-)

diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 89e645f26e..f61b68f121 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -942,11 +942,23 @@ BPackageInfo::Parser::_IsValidResolvableName(const char* string,
 	int32* _errorPos)
 {
 	for (const char* c = string; *c != '\0'; c++) {
-		if (*c == '-' || *c == '/' || isspace(*c)) {
-			if (_errorPos != NULL)
-				*_errorPos = c - string;
-			return false;
+		switch (*c) {
+			case '-':
+			case '/':
+			case '<':
+			case '>':
+			case '=':
+			case '!':
+				break;
+			default:
+				if (!isspace(*c))
+					continue;
+				break;
 		}
+
+		if (_errorPos != NULL)
+			*_errorPos = c - string;
+		return false;
 	}
 	return true;
 }

From cf0a957ff6c0dea52e5790a67a8fd6a179e77fe2 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 00:29:24 +0200
Subject: [PATCH 0437/1170] BMessage: Add {Add,Find}Strings()

They add a BStringList to/extract it from a B_STRING_TYPE field.
---
 headers/os/app/Message.h |  3 +++
 src/kits/app/Message.cpp | 45 ++++++++++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/headers/os/app/Message.h b/headers/os/app/Message.h
index 2920a1a3a2..50e092063d 100644
--- a/headers/os/app/Message.h
+++ b/headers/os/app/Message.h
@@ -24,6 +24,7 @@ class BBlockCache;
 class BMessenger;
 class BHandler;
 class BString;
+class BStringList;
 struct entry_ref;
 
 
@@ -125,6 +126,7 @@ class BMessage {
 		status_t		AddSize(const char* name, BSize aSize);
 		status_t		AddString(const char *name, const char *aString);
 		status_t		AddString(const char *name, const BString &aString);
+		status_t		AddStrings(const char *name, const BStringList &list);
 		status_t		AddInt8(const char *name, int8 value);
 		status_t		AddUInt8(const char *name, uint8 value);
 		status_t		AddInt16(const char *name, int16 value);
@@ -170,6 +172,7 @@ class BMessage {
 		status_t		FindString(const char *name, int32 index, const char **string) const;
 		status_t		FindString(const char *name, BString *string) const;
 		status_t		FindString(const char *name, int32 index, BString *string) const;
+		status_t		FindStrings(const char *name, BStringList *list) const;
 		status_t		FindInt8(const char *name, int8 *value) const;
 		status_t		FindInt8(const char *name, int32 index, int8 *value) const;
 		status_t		FindUInt8(const char *name, uint8 *value) const;
diff --git a/src/kits/app/Message.cpp b/src/kits/app/Message.cpp
index a4af4651c1..9837ed30d8 100644
--- a/src/kits/app/Message.cpp
+++ b/src/kits/app/Message.cpp
@@ -28,6 +28,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -2531,6 +2532,20 @@ BMessage::AddString(const char *name, const BString &string)
 }
 
 
+status_t
+BMessage::AddStrings(const char *name, const BStringList &list)
+{
+	int32 count = list.CountStrings();
+	for (int32 i = 0; i < count; i++) {
+		status_t error = AddString(name, list.StringAt(i));
+		if (error != B_OK)
+			return error;
+	}
+
+	return B_OK;
+}
+
+
 status_t
 BMessage::AddPointer(const char *name, const void *pointer)
 {
@@ -2691,6 +2706,36 @@ BMessage::FindString(const char *name, int32 index, BString *string) const
 }
 
 
+status_t
+BMessage::FindStrings(const char *name, BStringList *list) const
+{
+	if (list == NULL)
+		return B_BAD_VALUE;
+
+	list->MakeEmpty();
+
+	// get the number of items
+	type_code type;
+	int32 count;
+	if (GetInfo(name, &type, &count) != B_OK)
+		return B_NAME_NOT_FOUND;
+
+	if (type != B_STRING_TYPE)
+		return B_BAD_DATA;
+
+	for (int32 i = 0; i < count; i++) {
+		BString string;
+		status_t error = FindString(name, i, &string);
+		if (error != B_OK)
+			return error;
+		if (!list->Add(string))
+			return B_NO_MEMORY;
+	}
+
+	return B_OK;
+}
+
+
 status_t
 BMessage::FindPointer(const char *name, void **pointer) const
 {

From 7a27bcd1132c79d60658b7424990b1ad632886a9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 00:33:13 +0200
Subject: [PATCH 0438/1170] BPackageInfo: Make use of
 BMessage::{Add,Find}Strings()

---
 headers/os/package/PackageInfo.h |  2 --
 src/kits/package/PackageInfo.cpp | 48 ++++++--------------------------
 2 files changed, 8 insertions(+), 42 deletions(-)

diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h
index bdab0a868a..9efaea3028 100644
--- a/headers/os/package/PackageInfo.h
+++ b/headers/os/package/PackageInfo.h
@@ -174,8 +174,6 @@ private:
 	static	status_t			_AddVersion(BMessage* archive,
 									const char* field,
 									const BPackageVersion& version);
-	static	status_t			_AddStringList(BMessage* archive,
-									const char* field, const BStringList& list);
 	static	status_t			_AddResolvables(BMessage* archive,
 									const char* field,
 									const ResolvableList& resolvables);
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index f61b68f121..4d14eee0ac 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -1867,11 +1867,11 @@ BPackageInfo::Archive(BMessage* archive, bool deep) const
 		|| (error = archive->AddUInt32("flags", fFlags)) != B_OK
 		|| (error = archive->AddInt32("architecture", fArchitecture)) != B_OK
 		|| (error = _AddVersion(archive, "version", fVersion)) != B_OK
-		|| (error = _AddStringList(archive, "copyrights", fCopyrightList))
+		|| (error = archive->AddStrings("copyrights", fCopyrightList))
 			!= B_OK
-		|| (error = _AddStringList(archive, "licenses", fLicenseList)) != B_OK
-		|| (error = _AddStringList(archive, "urls", fURLList)) != B_OK
-		|| (error = _AddStringList(archive, "source-urls", fSourceURLList))
+		|| (error = archive->AddStrings("licenses", fLicenseList)) != B_OK
+		|| (error = archive->AddStrings("urls", fURLList)) != B_OK
+		|| (error = archive->AddStrings("source-urls", fSourceURLList))
 			!= B_OK
 		|| (error = _AddResolvables(archive, "provides", fProvidesList)) != B_OK
 		|| (error = _AddResolvableExpressions(archive, "requires",
@@ -1882,7 +1882,7 @@ BPackageInfo::Archive(BMessage* archive, bool deep) const
 			fConflictsList)) != B_OK
 		|| (error = _AddResolvableExpressions(archive, "freshens",
 			fFreshensList)) != B_OK
-		|| (error = _AddStringList(archive, "replaces", fReplacesList)) != B_OK
+		|| (error = archive->AddStrings("replaces", fReplacesList)) != B_OK
 		|| (error = archive->AddString("checksum", fChecksum)) != B_OK
 		|| (error = archive->AddString("install-path", fInstallPath)) != B_OK) {
 		return error;
@@ -2010,21 +2010,6 @@ BPackageInfo::_AddVersion(BMessage* archive, const char* field,
 }
 
 
-/*static*/ status_t
-BPackageInfo::_AddStringList(BMessage* archive, const char* field,
-	const BStringList& list)
-{
-	int32 count = list.CountStrings();
-	for (int32 i = 0; i < count; i++) {
-		status_t error = archive->AddString(field, list.StringAt(i));
-		if (error != B_OK)
-			return error;
-	}
-
-	return B_OK;
-}
-
-
 /*static*/ status_t
 BPackageInfo::_AddResolvables(BMessage* archive, const char* field,
 	const ResolvableList& resolvables)
@@ -2152,26 +2137,9 @@ BPackageInfo::_ExtractVersion(BMessage* archive, const char* field, int32 index,
 BPackageInfo::_ExtractStringList(BMessage* archive, const char* field,
 	BStringList& _list)
 {
-	// get the number of items
-	type_code type;
-	int32 count;
-	if (archive->GetInfo(field, &type, &count) != B_OK) {
-		// the field is missing
-		return B_OK;
-	}
-	if (type != B_STRING_TYPE)
-		return B_BAD_DATA;
-
-	for (int32 i = 0; i < count; i++) {
-		BString string;
-		status_t error = archive->FindString(field, i, &string);
-		if (error != B_OK)
-			return error;
-		if (!_list.Add(string))
-			return B_NO_MEMORY;
-	}
-
-	return B_OK;
+	status_t error = archive->FindStrings(field, &_list);
+	return error == B_NAME_NOT_FOUND ? B_OK : error;
+		// If the field doesn't exist, that's OK.
 }
 
 

From 85d2badf007cb152215485db7916578ed6700504 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 01:28:18 +0200
Subject: [PATCH 0439/1170] package daemon: Add support for activation change
 request

* daemon: Handle new request B_MESSAGE_COMMIT_TRANSACTION. It activates
  and deactivates given sets of packages. The new packages must be
  placed in a directory in the administrative directory. The daemon
  moves them to the packages directory and the deactivated packages to
  a subdirectory it creates. It also save the old activation state
  there.
* Add private BActivationTransaction, describing an activation change
  transaction.
* BDaemonClient: Add CommitTransaction(), which sends a given
  BActivationTransaction as a B_MESSAGE_COMMIT_TRANSACTION request to
  the daemon.

Completely untested yet.
---
 .../private/package/ActivationTransaction.h   |   1 +
 .../private/package/ActivationTransaction.h   |  70 ++
 headers/private/package/DaemonClient.h        |  49 +
 headers/private/package/DaemonDefs.h          |  41 +-
 src/build/libpackage/Jamfile                  |   1 +
 src/kits/package/ActivationTransaction.cpp    | 158 +++
 src/kits/package/DaemonClient.cpp             | 149 ++-
 src/kits/package/Jamfile                      |   1 +
 src/servers/package/Package.cpp               |   4 +-
 src/servers/package/Package.h                 |  16 +
 src/servers/package/PackageDaemon.cpp         |   7 +-
 src/servers/package/Root.cpp                  |  64 +-
 src/servers/package/Root.h                    |  12 +-
 src/servers/package/Volume.cpp                | 993 +++++++++++++++---
 src/servers/package/Volume.h                  |  38 +-
 15 files changed, 1434 insertions(+), 170 deletions(-)
 create mode 100644 headers/build/private/package/ActivationTransaction.h
 create mode 100644 headers/private/package/ActivationTransaction.h
 create mode 100644 src/kits/package/ActivationTransaction.cpp

diff --git a/headers/build/private/package/ActivationTransaction.h b/headers/build/private/package/ActivationTransaction.h
new file mode 100644
index 0000000000..39e231882e
--- /dev/null
+++ b/headers/build/private/package/ActivationTransaction.h
@@ -0,0 +1 @@
+#include <../private/package/ActivationTransaction.h>
diff --git a/headers/private/package/ActivationTransaction.h b/headers/private/package/ActivationTransaction.h
new file mode 100644
index 0000000000..11b5094325
--- /dev/null
+++ b/headers/private/package/ActivationTransaction.h
@@ -0,0 +1,70 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef _PACKAGE__PRIVATE__ACTIVATION_TRANSACTION_H_
+#define _PACKAGE__PRIVATE__ACTIVATION_TRANSACTION_H_
+
+
+#include 
+#include 
+
+
+namespace BPackageKit {
+namespace BPrivate {
+
+
+class BActivationTransaction {
+public:
+								BActivationTransaction();
+								BActivationTransaction(
+									BPackageInstallationLocation location,
+									int64 changeCount,
+									const BString& directoryName,
+									const BStringList& packagesToActivate,
+									const BStringList& packagesToDeactivate);
+								~BActivationTransaction();
+
+			status_t			InitCheck() const;
+			status_t			SetTo(BPackageInstallationLocation location,
+									int64 changeCount,
+									const BString& directoryName,
+									const BStringList& packagesToActivate,
+									const BStringList& packagesToDeactivate);
+
+			BPackageInstallationLocation Location() const;
+			void				SetLocation(
+									BPackageInstallationLocation location);
+
+			int64				ChangeCount() const;
+			void				SetChangeCount(int64 changeCount);
+
+			const BString&		TransactionDirectoryName() const;
+			void				SetTransactionDirectoryName(
+									const BString& directoryName);
+
+			const BStringList&	PackagesToActivate() const;
+			void				SetPackagesToActivate(
+									const BStringList& packages);
+
+			const BStringList&	PackagesToDeactivate() const;
+			void				SetPackagesToDeactivate(
+									const BStringList& packages);
+
+private:
+			BPackageInstallationLocation fLocation;
+			int64				fChangeCount;
+			BString				fTransactionDirectoryName;
+			BStringList			fPackagesToActivate;
+			BStringList			fPackagesToDeactivate;
+};
+
+
+}	// namespace BPrivate
+}	// namespace BPackageKit
+
+
+#endif	// _PACKAGE__PRIVATE__ACTIVATION_TRANSACTION_H_
diff --git a/headers/private/package/DaemonClient.h b/headers/private/package/DaemonClient.h
index e16b3e3499..bcad84ad59 100644
--- a/headers/private/package/DaemonClient.h
+++ b/headers/private/package/DaemonClient.h
@@ -11,6 +11,9 @@
 
 #include 
 #include 
+#include 
+
+#include 
 
 
 namespace BPackageKit {
@@ -23,7 +26,13 @@ class BPackageInfoSet;
 namespace BPrivate {
 
 
+class BActivationTransaction;
+
+
 class BDaemonClient {
+public:
+			class BCommitTransactionResult;
+
 public:
 								BDaemonClient();
 								~BDaemonClient();
@@ -31,17 +40,57 @@ public:
 			status_t			GetInstallationLocationInfo(
 									BPackageInstallationLocation location,
 									BInstallationLocationInfo& _info);
+			status_t			CommitTransaction(
+									const BActivationTransaction& transaction,
+									BCommitTransactionResult& _result);
 
 private:
 			status_t			_InitMessenger();
 			status_t			_ExtractPackageInfoSet(const BMessage& message,
 									const char* field, BPackageInfoSet& _infos);
 
+			status_t			_CommitTransaction(
+									const BActivationTransaction& transaction,
+									BCommitTransactionResult& _result);
+
 private:
 			BMessenger			fDaemonMessenger;
 };
 
 
+class BDaemonClient::BCommitTransactionResult {
+public:
+								BCommitTransactionResult();
+								BCommitTransactionResult(int32 error,
+									const BString& errorMessage,
+									const BString& errorPackage,
+									const BString& oldStateDirectory);
+								~BCommitTransactionResult();
+
+			void				SetTo(int32 error, const BString& errorMessage,
+									const BString& errorPackage,
+									const BString& oldStateDirectory);
+
+			status_t			Error() const;
+			BDaemonError		DaemonError() const;
+									// may be B_DAEMON_OK, even if Error() is
+									// != B_OK, then Error() is as specific as
+									// is known
+			const BString&		ErrorMessage() const;
+									// may be empty, even on error
+			const BString&		ErrorPackage() const;
+									// may be empty, even on error
+
+			const BString&		OldStateDirectory() const;
+
+private:
+			int32				fError;
+			BString				fErrorMessage;
+			BString				fErrorPackage;
+			BString				fOldStateDirectory;
+};
+
+
 }	// namespace BPrivate
 }	// namespace BPackageKit
 
diff --git a/headers/private/package/DaemonDefs.h b/headers/private/package/DaemonDefs.h
index 3bde3b742b..76a323133a 100644
--- a/headers/private/package/DaemonDefs.h
+++ b/headers/private/package/DaemonDefs.h
@@ -17,7 +17,11 @@ namespace BPrivate {
 
 
 enum BDaemonError {
-	B_DAEMON_OK
+	B_DAEMON_OK = 0,
+	B_DAEMON_CHANGE_COUNT_MISMATCH,
+	B_DAEMON_BAD_REQUEST,
+	B_DAEMON_NO_SUCH_PACKAGE,
+	B_DAEMON_PACKAGE_ALREADY_EXISTS
 };
 
 
@@ -36,11 +40,40 @@ enum {
 		//		archived BPackageInfos of the active packages
 		// "inactive packages": message[]
 		//		archived BPackageInfos of the inactive packages
+
+	B_MESSAGE_COMMIT_TRANSACTION		= 'PKTC',
+		// "location": int32
+		//		the respective installation location constant
+		// "change count": int64
+		//		the expected change count of the installation location; fail,
+		//		if something has changed in the meantime
+		// "transaction": string
+		//		name of the transaction directory (subdirectory of the
+		//		administrative directory) where to-be-activated packages live
+		// "activate": string[]
+		//		file names of the packages to activate; must be in the
+		//		transaction directory
+		// "deactivate": string[]
+		//		file names of the packages to activate; must be in the
+		//		transaction directory
+	B_MESSAGE_COMMIT_TRANSACTION_REPLY	= 'PKTR'
+		// "error": int32
+		//		regular error code or BDaemonError describing how committing
+		//		the transaction went
+		// "error message": string
+		//		[error case only] gives some additional information what went
+		//		wrong; optional
+		// "error package": string
+		//		[error case only] file name of the package causing the error,
+		//		if any in particarly; optional
+		// "old state": string
+		//		name of the directory (subdirectory of the administrative
+		//		directory) containing the deactivated packages
 };
 
 
-#endif	// _PACKAGE__PRIVATE__DAEMON_DEFS_H_
-
-
 }	// namespace BPrivate
 }	// namespace BPackageKit
+
+
+#endif	// _PACKAGE__PRIVATE__DAEMON_DEFS_H_
diff --git a/src/build/libpackage/Jamfile b/src/build/libpackage/Jamfile
index 65a24be213..1d99a84d1b 100644
--- a/src/build/libpackage/Jamfile
+++ b/src/build/libpackage/Jamfile
@@ -67,6 +67,7 @@ BuildPlatformSharedLibrary libpackage_build.so
 	:
 	ActivateRepositoryCacheJob.cpp
 	ActivateRepositoryConfigJob.cpp
+	ActivationTransaction.cpp
 	AddRepositoryRequest.cpp
 	Attributes.cpp
 	BlockBufferCacheNoLock.cpp
diff --git a/src/kits/package/ActivationTransaction.cpp b/src/kits/package/ActivationTransaction.cpp
new file mode 100644
index 0000000000..838b071774
--- /dev/null
+++ b/src/kits/package/ActivationTransaction.cpp
@@ -0,0 +1,158 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+
+namespace BPackageKit {
+namespace BPrivate {
+
+
+BActivationTransaction::BActivationTransaction()
+	:
+	fLocation(B_PACKAGE_INSTALLATION_LOCATION_ENUM_COUNT),
+	fChangeCount(0),
+	fTransactionDirectoryName(),
+	fPackagesToActivate(),
+	fPackagesToDeactivate()
+{
+}
+
+
+BActivationTransaction::BActivationTransaction(
+	BPackageInstallationLocation location, int64 changeCount,
+	const BString& directoryName, const BStringList& packagesToActivate,
+	const BStringList& packagesToDeactivate)
+	:
+	fLocation(location),
+	fChangeCount(changeCount),
+	fTransactionDirectoryName(directoryName),
+	fPackagesToActivate(packagesToActivate),
+	fPackagesToDeactivate(packagesToDeactivate)
+{
+}
+
+
+BActivationTransaction::~BActivationTransaction()
+{
+}
+
+
+status_t
+BActivationTransaction::InitCheck() const
+{
+	if (fLocation < 0 || fLocation >= B_PACKAGE_INSTALLATION_LOCATION_ENUM_COUNT
+		|| fTransactionDirectoryName.IsEmpty()
+		|| (fPackagesToActivate.IsEmpty() && fPackagesToDeactivate.IsEmpty())) {
+		return B_BAD_VALUE;
+	}
+	return B_OK;
+}
+
+status_t
+BActivationTransaction::SetTo(BPackageInstallationLocation location,
+	int64 changeCount, const BString& directoryName,
+	const BStringList& packagesToActivate,
+	const BStringList& packagesToDeactivate)
+{
+	if (location < 0 || location >= B_PACKAGE_INSTALLATION_LOCATION_ENUM_COUNT
+		|| directoryName.IsEmpty()
+		|| (packagesToActivate.IsEmpty() && packagesToDeactivate.IsEmpty())) {
+		return B_BAD_VALUE;
+	}
+
+	fLocation = location;
+	fChangeCount = changeCount;
+	fTransactionDirectoryName = directoryName;
+	fPackagesToActivate = packagesToActivate;
+	fPackagesToDeactivate = packagesToDeactivate;
+
+	if (fPackagesToActivate.CountStrings() != packagesToActivate.CountStrings()
+		|| fPackagesToDeactivate.CountStrings()
+			!= packagesToDeactivate.CountStrings()) {
+		return B_NO_MEMORY;
+	}
+
+	return B_OK;
+}
+
+
+BPackageInstallationLocation
+BActivationTransaction::Location() const
+{
+	return fLocation;
+}
+
+
+void
+BActivationTransaction::SetLocation(BPackageInstallationLocation location)
+{
+	fLocation = location;
+}
+
+
+int64
+BActivationTransaction::ChangeCount() const
+{
+	return fChangeCount;
+}
+
+
+void
+BActivationTransaction::SetChangeCount(int64 changeCount)
+{
+	fChangeCount = changeCount;
+}
+
+
+const BString&
+BActivationTransaction::TransactionDirectoryName() const
+{
+	return fTransactionDirectoryName;
+}
+
+
+void
+BActivationTransaction::SetTransactionDirectoryName(
+	const BString& directoryName)
+{
+	fTransactionDirectoryName = directoryName;
+}
+
+
+const BStringList&
+BActivationTransaction::PackagesToActivate() const
+{
+	return fPackagesToActivate;
+}
+
+
+void
+BActivationTransaction::SetPackagesToActivate(const BStringList& packages)
+{
+	fPackagesToActivate = packages;
+}
+
+
+const BStringList&
+BActivationTransaction::PackagesToDeactivate() const
+{
+	return fPackagesToDeactivate;
+}
+
+
+void
+BActivationTransaction::SetPackagesToDeactivate(const BStringList& packages)
+{
+	fPackagesToDeactivate = packages;
+}
+
+
+}	// namespace BPrivate
+}	// namespace BPackageKit
diff --git a/src/kits/package/DaemonClient.cpp b/src/kits/package/DaemonClient.cpp
index f14801f51e..8d2c1bf310 100644
--- a/src/kits/package/DaemonClient.cpp
+++ b/src/kits/package/DaemonClient.cpp
@@ -12,13 +12,16 @@
 #include 
 #include 
 
-#include 
+#include 
 
 
 namespace BPackageKit {
 namespace BPrivate {
 
 
+// #pragma mark - BCommitTransactionResult
+
+
 BDaemonClient::BDaemonClient()
 	:
 	fDaemonMessenger()
@@ -87,6 +90,19 @@ BDaemonClient::GetInstallationLocationInfo(
 }
 
 
+status_t
+BDaemonClient::CommitTransaction(const BActivationTransaction& transaction,
+	BCommitTransactionResult& _result)
+{
+	status_t error = _CommitTransaction(transaction, _result);
+		// B_OK just indicates that _result has been initialized.
+	if (error != B_OK)
+		_result.SetTo(error, BString(), BString(), BString());
+
+	return _result.Error();
+}
+
+
 status_t
 BDaemonClient::_InitMessenger()
 {
@@ -133,5 +149,136 @@ BDaemonClient::_ExtractPackageInfoSet(const BMessage& message,
 }
 
 
+status_t
+BDaemonClient::_CommitTransaction(const BActivationTransaction& transaction,
+	BCommitTransactionResult& _result)
+{
+	if (transaction.InitCheck() != B_OK)
+		return B_BAD_VALUE;
+
+	status_t error = _InitMessenger();
+	if (error != B_OK)
+		return error;
+
+	// send the request
+	BMessage request(B_MESSAGE_COMMIT_TRANSACTION);
+	if ((error = request.AddInt32("location", transaction.Location())) != B_OK
+		|| (error = request.AddInt64("change count",
+			transaction.ChangeCount())) != B_OK
+		|| (error = request.AddString("transaction",
+			transaction.TransactionDirectoryName())) != B_OK
+		|| (error = request.AddStrings("activate",
+			transaction.PackagesToActivate())) != B_OK
+		|| (error = request.AddStrings("deactivate",
+			transaction.PackagesToDeactivate())) != B_OK) {
+		return error;
+	}
+
+	BMessage reply;
+	fDaemonMessenger.SendMessage(&request, &reply);
+	if (reply.what != B_MESSAGE_COMMIT_TRANSACTION_REPLY)
+		return B_ERROR;
+
+	// extract the result
+	int32 requestError;
+	error = reply.FindInt32("error", &requestError);
+	if (error != B_OK)
+		return error;
+
+	BString errorMessage;
+	BString errorPackage;
+	BString oldStateDirectory;
+	if (requestError == 0) {
+		error = reply.FindString("old state", &oldStateDirectory);
+		if (error != B_OK)
+			return error;
+	} else {
+		reply.FindString("error message", &errorMessage);
+		reply.FindString("error package", &errorPackage);
+	}
+
+	_result.SetTo(requestError, errorMessage, errorPackage, oldStateDirectory);
+	return B_OK;
+		// Even on error. B_OK just indicates that we have initialized _result.
+}
+
+
+// #pragma mark - BCommitTransactionResult
+
+
+BDaemonClient::BCommitTransactionResult::BCommitTransactionResult()
+	:
+	fError(B_NO_INIT),
+	fErrorMessage(),
+	fErrorPackage(),
+	fOldStateDirectory()
+{
+}
+
+
+BDaemonClient::BCommitTransactionResult::BCommitTransactionResult(int32 error,
+	const BString& errorMessage, const BString& errorPackage,
+	const BString& oldStateDirectory)
+	:
+	fError(error),
+	fErrorMessage(errorMessage),
+	fErrorPackage(errorPackage),
+	fOldStateDirectory(oldStateDirectory)
+{
+}
+
+
+BDaemonClient::BCommitTransactionResult::~BCommitTransactionResult()
+{
+}
+
+
+void
+BDaemonClient::BCommitTransactionResult::SetTo(int32 error,
+	const BString& errorMessage, const BString& errorPackage,
+	const BString& oldStateDirectory)
+{
+	fError = error;
+	fErrorMessage = errorMessage;
+	fErrorPackage = errorPackage;
+	fOldStateDirectory = oldStateDirectory;
+}
+
+
+status_t
+BDaemonClient::BCommitTransactionResult::Error() const
+{
+	return fError <= 0 ? fError : B_ERROR;
+}
+
+
+BDaemonError
+BDaemonClient::BCommitTransactionResult::DaemonError() const
+{
+	return fError > 0 ? (BDaemonError)fError : B_DAEMON_OK;
+}
+
+
+const BString&
+BDaemonClient::BCommitTransactionResult::ErrorMessage() const
+{
+	return fErrorMessage;
+}
+
+
+const BString&
+BDaemonClient::BCommitTransactionResult::ErrorPackage() const
+{
+	return fErrorPackage;
+}
+
+
+const BString&
+BDaemonClient::BCommitTransactionResult::OldStateDirectory() const
+{
+	return fOldStateDirectory;
+}
+
+
 }	// namespace BPrivate
 }	// namespace BPackageKit
diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile
index 8ebcc9ce2f..6df66e5cb2 100644
--- a/src/kits/package/Jamfile
+++ b/src/kits/package/Jamfile
@@ -46,6 +46,7 @@ SharedLibrary libpackage.so
 	:
 	ActivateRepositoryCacheJob.cpp
 	ActivateRepositoryConfigJob.cpp
+	ActivationTransaction.cpp
 	AddRepositoryRequest.cpp
 	Attributes.cpp
 	BlockBufferCacheNoLock.cpp
diff --git a/src/servers/package/Package.cpp b/src/servers/package/Package.cpp
index c88767ee0d..74d6740aae 100644
--- a/src/servers/package/Package.cpp
+++ b/src/servers/package/Package.cpp
@@ -25,7 +25,9 @@ Package::Package()
 	fInfo(),
 	fActive(false),
 	fFileNameHashTableNext(NULL),
-	fNodeRefHashTableNext(NULL)
+	fNodeRefHashTableNext(NULL),
+	fIgnoreEntryCreated(0),
+	fIgnoreEntryRemoved(0)
 {
 }
 
diff --git a/src/servers/package/Package.h b/src/servers/package/Package.h
index b93fed8a2f..e2ac3dd7f0 100644
--- a/src/servers/package/Package.h
+++ b/src/servers/package/Package.h
@@ -39,6 +39,20 @@ public:
 			void				SetActive(bool active)
 									{ fActive = active; }
 
+			int32				EntryCreatedIgnoreLevel() const
+									{ return fIgnoreEntryCreated; }
+			void				IncrementEntryCreatedIgnoreLevel()
+									{ fIgnoreEntryCreated++; }
+			void				DecrementEntryCreatedIgnoreLevel()
+									{ fIgnoreEntryCreated--; }
+
+			int32				EntryRemovedIgnoreLevel() const
+									{ return fIgnoreEntryRemoved; }
+			void				IncrementEntryRemovedIgnoreLevel()
+									{ fIgnoreEntryRemoved++; }
+			void				DecrementEntryRemovedIgnoreLevel()
+									{ fIgnoreEntryRemoved--; }
+
 			Package*&			FileNameHashTableNext()
 									{ return fFileNameHashTableNext; }
 			Package*&			NodeRefHashTableNext()
@@ -51,6 +65,8 @@ private:
 			bool				fActive;
 			Package*			fFileNameHashTableNext;
 			Package*			fNodeRefHashTableNext;
+			int32				fIgnoreEntryCreated;
+			int32				fIgnoreEntryRemoved;
 };
 
 
diff --git a/src/servers/package/PackageDaemon.cpp b/src/servers/package/PackageDaemon.cpp
index 58d76c045f..426d5e3592 100644
--- a/src/servers/package/PackageDaemon.cpp
+++ b/src/servers/package/PackageDaemon.cpp
@@ -86,11 +86,10 @@ PackageDaemon::MessageReceived(BMessage* message)
 		}
 
 		case B_MESSAGE_GET_INSTALLATION_LOCATION_INFO:
+		case B_MESSAGE_COMMIT_TRANSACTION:
 		{
-			if (fSystemRoot == NULL)
-				break;
-
-			fSystemRoot->HandleGetLocationInfoRequest(DetachCurrentMessage());
+			if (fSystemRoot != NULL)
+				fSystemRoot->HandleRequest(DetachCurrentMessage());
 			break;
 		}
 
diff --git a/src/servers/package/Root.cpp b/src/servers/package/Root.cpp
index fd0c4565c0..bb3ac96aad 100644
--- a/src/servers/package/Root.cpp
+++ b/src/servers/package/Root.cpp
@@ -17,9 +17,14 @@
 #include 
 #include 
 
+#include 
+
 #include "DebugSupport.h"
 
 
+using namespace BPackageKit::BPrivate;
+
+
 // #pragma mark - VolumeJob
 
 
@@ -42,11 +47,11 @@ private:
 };
 
 
-// #pragma mark - HandleGetLocationInfoRequestJob
+// #pragma mark - RequestJob
 
 
-struct Root::HandleGetLocationInfoRequestJob : public Job {
-	HandleGetLocationInfoRequestJob(Root* root, BMessage* message)
+struct Root::RequestJob : public Job {
+	RequestJob(Root* root, BMessage* message)
 		:
 		fRoot(root),
 		fMessage(message)
@@ -55,7 +60,7 @@ struct Root::HandleGetLocationInfoRequestJob : public Job {
 
 	virtual void Do()
 	{
-		fRoot->_HandleGetLocationInfoRequest(fMessage.Get());
+		fRoot->_HandleRequest(fMessage.Get());
 	}
 
 private:
@@ -209,10 +214,9 @@ Root::FindVolume(dev_t deviceID) const
 
 
 void
-Root::HandleGetLocationInfoRequest(BMessage* message)
+Root::HandleRequest(BMessage* message)
 {
-	HandleGetLocationInfoRequestJob* job
-		= new(std::nothrow) HandleGetLocationInfoRequestJob(this, message);
+	RequestJob* job = new(std::nothrow) RequestJob(this, message);
 	if (job == NULL) {
 		delete message;
 		return;
@@ -253,6 +257,22 @@ Root::_GetVolume(PackageFSMountType mountType)
 }
 
 
+Volume*
+Root::_GetVolume(BPackageInstallationLocation location)
+{
+	switch ((BPackageInstallationLocation)location) {
+		case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM:
+			return fSystemVolume;
+		case B_PACKAGE_INSTALLATION_LOCATION_COMMON:
+			return fCommonVolume;
+		case B_PACKAGE_INSTALLATION_LOCATION_HOME:
+			return fHomeVolume;
+		default:
+			return NULL;
+	}
+}
+
+
 Volume*
 Root::_NextVolumeFor(Volume* volume)
 {
@@ -314,7 +334,7 @@ Root::_ProcessNodeMonitorEvents(Volume* volume)
 
 
 void
-Root::_HandleGetLocationInfoRequest(BMessage* message)
+Root::_HandleRequest(BMessage* message)
 {
 	int32 location;
 	if (message->FindInt32("location", &location) != B_OK
@@ -325,23 +345,19 @@ Root::_HandleGetLocationInfoRequest(BMessage* message)
 
 	// get the volume and let it handle the message
 	AutoLocker locker(fLock);
-	Volume* volume;
-	switch ((BPackageInstallationLocation)location) {
-		case B_PACKAGE_INSTALLATION_LOCATION_SYSTEM:
-			volume = fSystemVolume;
-			break;
-		case B_PACKAGE_INSTALLATION_LOCATION_COMMON:
-			volume = fCommonVolume;
-			break;
-		case B_PACKAGE_INSTALLATION_LOCATION_HOME:
-			volume = fHomeVolume;
-			break;
-		default:
-			return;
-	}
+	Volume* volume = _GetVolume((BPackageInstallationLocation)location);
+	locker.Unlock();
 
-	if (volume != NULL)
-		volume->HandleGetLocationInfoRequest(message);
+	if (volume != NULL) {
+		switch (message->what) {
+			case B_MESSAGE_GET_INSTALLATION_LOCATION_INFO:
+				volume->HandleGetLocationInfoRequest(message);
+				break;
+			case B_MESSAGE_COMMIT_TRANSACTION:
+				volume->HandleCommitTransactionRequest(message);
+				break;
+		}
+	}
 }
 
 
diff --git a/src/servers/package/Root.h b/src/servers/package/Root.h
index 62aba1b8d3..512cd23abe 100644
--- a/src/servers/package/Root.h
+++ b/src/servers/package/Root.h
@@ -13,6 +13,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -41,7 +42,7 @@ public:
 
 			Volume*				FindVolume(dev_t deviceID) const;
 
-			void				HandleGetLocationInfoRequest(BMessage* message);
+			void				HandleRequest(BMessage* message);
 
 private:
 	// Volume::Listener
@@ -52,19 +53,20 @@ protected:
 
 private:
 			struct VolumeJob;
-			struct HandleGetLocationInfoRequestJob;
+			struct RequestJob;
 
-			friend struct HandleGetLocationInfoRequestJob;
+			friend struct RequestJob;
 
 private:
 			Volume**			_GetVolume(PackageFSMountType mountType);
+			Volume*				_GetVolume(
+									BPackageInstallationLocation location);
 			Volume*				_NextVolumeFor(Volume* volume);
 
 			void				_InitPackages(Volume* volume);
 			void				_DeleteVolume(Volume* volume);
 			void				_ProcessNodeMonitorEvents(Volume* volume);
-			void				_HandleGetLocationInfoRequest(
-									BMessage* message);
+			void				_HandleRequest(BMessage* message);
 
 			status_t			_QueueJob(Job* job);
 
diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index 401d760430..80225c4556 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -12,6 +12,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 
 #include 
@@ -87,6 +88,608 @@ private:
 };
 
 
+// #pragma mark - RelativePath
+
+
+struct Volume::RelativePath {
+	RelativePath(const char* component1 = NULL, const char* component2 = NULL,
+		const char* component3 = NULL)
+		:
+		fComponentCount(kMaxComponentCount)
+	{
+		fComponents[0] = component1;
+		fComponents[1] = component2;
+		fComponents[2] = component3;
+
+		for (size_t i = 0; i < kMaxComponentCount; i++) {
+			if (fComponents[i] == NULL) {
+				fComponentCount = i;
+				break;
+			}
+		}
+	}
+
+	bool IsEmpty() const
+	{
+		return fComponentCount == 0;
+	}
+
+	RelativePath HeadPath(size_t componentsToDropCount = 1)
+	{
+		RelativePath result;
+		if (componentsToDropCount < fComponentCount) {
+			result.fComponentCount = fComponentCount - componentsToDropCount;
+			for (size_t i = 0; i < result.fComponentCount; i++)
+				result.fComponents[i] = fComponents[i];
+		}
+
+		return result;
+	}
+
+	const char* LastComponent() const
+	{
+		return fComponentCount > 0 ? fComponents[fComponentCount - 1] : NULL;
+	}
+
+	BString ToString() const
+	{
+		if (fComponentCount == 0)
+			return BString();
+
+		size_t length = fComponentCount - 1;
+		for (size_t i = 0; i < fComponentCount; i++)
+			length += strlen(fComponents[i]);
+
+		BString result;
+		char* buffer = result.LockBuffer(length + 1);
+		if (buffer == NULL)
+			return BString();
+
+		for (size_t i = 0; i < fComponentCount; i++) {
+			if (i > 0) {
+				*buffer = '/';
+				buffer++;
+			}
+			strcpy(buffer, fComponents[i]);
+			buffer += strlen(buffer);
+		}
+
+		return result.UnlockBuffer();
+	}
+
+private:
+	static const size_t	kMaxComponentCount = 3;
+
+	const char*	fComponents[kMaxComponentCount];
+	size_t		fComponentCount;
+};
+
+
+// #pragma mark - Exception
+
+
+struct Volume::Exception {
+	Exception(int32 error, const char* errorMessage = NULL,
+		const char* packageName = NULL)
+		:
+		fError(error),
+		fErrorMessage(errorMessage),
+		fPackageName(packageName)
+	{
+	}
+
+	int32 Error() const
+	{
+		return fError;
+	}
+
+	const BString& ErrorMessage() const
+	{
+		return fErrorMessage;
+	}
+
+	const BString& PackageName() const
+	{
+		return fPackageName;
+	}
+
+	BString ToString() const
+	{
+		const char* error;
+		if (fError >= 0) {
+			switch (fError) {
+				case B_DAEMON_OK:
+					error = "no error";
+					break;
+				case B_DAEMON_CHANGE_COUNT_MISMATCH:
+					error = "transaction out of date";
+					break;
+				case B_DAEMON_BAD_REQUEST:
+					error = "invalid transaction";
+					break;
+				case B_DAEMON_NO_SUCH_PACKAGE:
+					error = "no such package";
+					break;
+				case B_DAEMON_PACKAGE_ALREADY_EXISTS:
+					error = "package already exists";
+					break;
+				default:
+					error = "unknown error";
+					break;
+			}
+		} else
+			error = strerror(fError);
+
+		BString string;
+		if (!fErrorMessage.IsEmpty()) {
+			string = fErrorMessage;
+			string << ": ";
+		}
+
+		string << error;
+
+		if (!fPackageName.IsEmpty())
+			string << ", package: \"" << fPackageName << '"';
+
+		return string;
+	}
+
+private:
+	int32		fError;
+	BString		fErrorMessage;
+	BString		fPackageName;
+};
+
+
+// #pragma mark - CommitTransactionHandler
+
+
+struct Volume::CommitTransactionHandler {
+	CommitTransactionHandler(Volume* volume, BMessage* request, BMessage& reply)
+		:
+		fVolume(volume),
+		fRequest(request),
+		fReply(reply),
+		fPackagesToActivate(20, true),
+		fPackagesToDeactivate(),
+		fAddedPackages(),
+		fRemovedPackages()
+	{
+	}
+
+	void HandleRequest()
+	{
+		// check the change count
+		int64 changeCount;
+		if (fRequest->FindInt64("change count", &changeCount) != B_OK)
+			throw Exception(B_DAEMON_CHANGE_COUNT_MISMATCH);
+
+		// collect the packages to deactivate
+		_GetPackagesToDeactivate();
+
+		// read the packages to activate
+		_ReadPackagesToActivate();
+
+		// anything to do at all?
+		if (fPackagesToActivate.IsEmpty() &&  fPackagesToDeactivate.empty()) {
+			throw Exception(B_DAEMON_BAD_REQUEST,
+				"no packages to activate or deactivate");
+		}
+
+		// create an old state directory
+		_CreateOldStateDirectory();
+
+		// move packages to deactivate to old state directory
+		_RemovePackagesToDeactivate();
+
+		// move packages to activate to packages directory
+		_AddPackagesToActivate();
+
+		// activate/deactivate packages
+		fVolume->_ChangePackageActivation(fAddedPackages, fRemovedPackages);
+
+		// removed packages have been deleted, new packages shall not be deleted
+		fAddedPackages.clear();
+		fRemovedPackages.clear();
+		fPackagesToActivate.MakeEmpty(false);
+		fPackagesToDeactivate.clear();
+	}
+
+	void Revert()
+	{
+		// move packages to activate back to transaction directory
+		_RevertAddPackagesToActivate();
+
+		// move packages to deactivate back to packages directory
+		_RevertRemovePackagesToDeactivate();
+
+		// remove old state directory
+		_RemoveOldStateDirectory();
+	}
+
+private:
+	typedef BObjectList PackageList;
+
+	void _GetPackagesToDeactivate()
+	{
+		static const char* const kPackagesToDeactivateFieldName = "deactivate";
+
+		// get the number of packages to activate
+		type_code type;
+		int32 packagesToDeactivateCount;
+		if (fRequest->GetInfo(kPackagesToDeactivateFieldName, &type,
+				&packagesToDeactivateCount) != B_OK) {
+			// the field is missing, i.e. no packages shall be deactivated
+			return;
+		}
+
+		for (int32 i = 0; i < packagesToDeactivateCount; i++) {
+			const char* packageName;
+			status_t error = fRequest->FindString(
+				kPackagesToDeactivateFieldName, i, &packageName);
+			if (error != B_OK)
+				throw Exception(error);
+
+			Package* package = fVolume->fPackagesByFileName.Lookup(packageName);
+			if (package == NULL) {
+				throw Exception(B_DAEMON_NO_SUCH_PACKAGE, "no such package",
+					packageName);
+			}
+
+			fPackagesToDeactivate.insert(package);
+
+			package->IncrementEntryRemovedIgnoreLevel();
+		}
+	}
+
+	void _ReadPackagesToActivate()
+	{
+		static const char* const kPackagesToActivateFieldName = "activate";
+
+		// get the number of packages to activate
+		type_code type;
+		int32 packagesToActivateCount;
+		if (fRequest->GetInfo(kPackagesToActivateFieldName, &type,
+				&packagesToActivateCount) != B_OK) {
+			// the field is missing, i.e. no packages shall be activated
+			return;
+		}
+
+		// get the name of the transaction directory
+		BString transactionDirectoryName;
+		if (packagesToActivateCount > 0) {
+			if (fRequest->FindString("transaction", &transactionDirectoryName)
+					!= B_OK) {
+				throw Exception(B_DAEMON_BAD_REQUEST);
+			}
+		}
+
+		// check the name -- we only allow a simple subdirectory of the admin
+		// directory
+		if (transactionDirectoryName.IsEmpty()
+			|| transactionDirectoryName.FindFirst('/') >= 0
+			|| transactionDirectoryName == "."
+			|| transactionDirectoryName == "..") {
+			throw Exception(B_DAEMON_BAD_REQUEST);
+		}
+
+		// open the directory
+		RelativePath directoryPath(kAdminDirectoryName,
+			transactionDirectoryName);
+		BDirectory directory;
+		status_t error = fVolume->_OpenPackagesSubDirectory(directoryPath,
+			false, directory);
+		if (error != B_OK)
+			throw Exception(error, "failed to open transaction directory");
+
+		error = directory.GetNodeRef(&fTransactionDirectoryRef);
+		if (error != B_OK) {
+			throw Exception(error,
+				"failed to get transaction directory node ref");
+		}
+
+		// read the packages
+		for (int32 i = 0; i < packagesToActivateCount; i++) {
+			const char* packageName;
+			error = fRequest->FindString(kPackagesToActivateFieldName, i,
+				&packageName);
+			if (error != B_OK)
+				throw Exception(error);
+
+			// make sure it doesn't clash with an already existing package
+			Package* package = fVolume->fPackagesByFileName.Lookup(packageName);
+			if (package != NULL
+				&& fPackagesToDeactivate.find(package)
+					== fPackagesToDeactivate.end()) {
+				throw Exception(B_DAEMON_PACKAGE_ALREADY_EXISTS, NULL,
+					packageName);
+			}
+
+			// read the package
+			entry_ref entryRef;
+			entryRef.device = fTransactionDirectoryRef.device;
+			entryRef.directory = fTransactionDirectoryRef.node;
+			if (entryRef.set_name(packageName) != B_OK)
+				throw Exception(B_NO_MEMORY);
+
+			package = new(std::nothrow) Package;
+			if (package == NULL || !fPackagesToActivate.AddItem(package)) {
+				delete package;
+				throw Exception(B_NO_MEMORY);
+			}
+
+			error = package->Init(entryRef);
+			if (error != B_OK)
+				throw Exception(error, "failed to read package", packageName);
+
+			package->IncrementEntryCreatedIgnoreLevel();
+		}
+	}
+
+	void _CreateOldStateDirectory()
+	{
+		// construct a nice name from the current date and time
+		time_t nowSeconds = time(NULL);
+		struct tm now;
+		BString baseName;
+		if (localtime_r(&nowSeconds, &now) != NULL) {
+			baseName.SetToFormat("state_%d-%02d-%02d_%02d:%02d:%02d",
+				1900 + now.tm_year, now.tm_mon + 1, now.tm_mday, now.tm_hour,
+				now.tm_min, now.tm_sec);
+		} else
+			baseName = "state";
+
+		if (baseName.IsEmpty())
+			throw Exception(B_NO_MEMORY);
+
+		// make sure the directory doesn't exist yet
+		BDirectory adminDirectory;
+		status_t error = fVolume->_OpenPackagesSubDirectory(
+			RelativePath(kAdminDirectoryName), true, adminDirectory);
+		if (error != B_OK)
+			throw Exception(error, "failed to open administrative directory");
+
+		int uniqueId = 1;
+		BString directoryName = baseName;
+		while (BEntry(&adminDirectory, directoryName).Exists()) {
+			directoryName.SetToFormat("%s-%d", baseName.String(), uniqueId++);
+			if (directoryName.IsEmpty())
+				throw Exception(B_NO_MEMORY);
+		}
+
+		// create the directory
+		error = adminDirectory.CreateDirectory(directoryName,
+			&fOldStateDirectory);
+		if (error != B_OK)
+			throw Exception(error, "failed to create old state directory");
+
+		fOldStateDirectoryName = directoryName;
+
+		// write the old activation file
+		BEntry activationFile;
+		error = fVolume->_WriteActivationFile(
+			RelativePath(kAdminDirectoryName, directoryName),
+			kActivationFileName, PackageSet(), PackageSet(), activationFile);
+		if (error != B_OK)
+			throw Exception(error, "failed to write old activation file");
+
+		// add the old state directory to the reply
+		error = fReply.AddString("old state", fOldStateDirectoryName);
+		if (error != B_OK)
+			throw Exception(error, "failed to add field to reply");
+	}
+
+	void _RemovePackagesToDeactivate()
+	{
+		if (fPackagesToDeactivate.empty())
+			return;
+
+		for (PackageSet::const_iterator it = fPackagesToDeactivate.begin();
+			it != fPackagesToDeactivate.end(); ++it) {
+			// get an BEntry for the package
+			Package* package = *it;
+			entry_ref entryRef;
+			entryRef.device = fVolume->fPackagesDirectoryRef.device;
+			entryRef.directory = fVolume->fPackagesDirectoryRef.node;
+			if (entryRef.set_name(package->FileName()) != B_OK)
+				throw Exception(B_NO_MEMORY);
+
+			BEntry entry;
+			status_t error = entry.SetTo(&entryRef);
+			if (error != B_OK) {
+				throw Exception(error, "failed to get package entry",
+					package->FileName());
+			}
+
+			// move entry
+			fRemovedPackages.insert(package);
+
+			error = entry.MoveTo(&fOldStateDirectory);
+			if (error != B_OK) {
+				fRemovedPackages.erase(package);
+				throw Exception(error,
+					"failed to move old package from packages directory",
+					package->FileName());
+			}
+		}
+	}
+
+	void _AddPackagesToActivate()
+	{
+		if (fPackagesToActivate.IsEmpty())
+			return;
+
+		// open packages directory
+		BDirectory packagesDirectory;
+		status_t error
+			= packagesDirectory.SetTo(&fVolume->fPackagesDirectoryRef);
+		if (error != B_OK)
+			throw Exception(error, "failed to open packages directory");
+
+		int32 count = fPackagesToActivate.CountItems();
+		for (int32 i = 0; i < count; i++) {
+			// get an BEntry for the package
+			Package* package = fPackagesToActivate.ItemAt(i);
+			entry_ref entryRef;
+			entryRef.device = fTransactionDirectoryRef.device;
+			entryRef.directory = fTransactionDirectoryRef.node;
+			if (entryRef.set_name(package->FileName()) != B_OK)
+				throw Exception(B_NO_MEMORY);
+
+			BEntry entry;
+			error = entry.SetTo(&entryRef);
+			if (error != B_OK) {
+				throw Exception(error, "failed to get package entry",
+					package->FileName());
+			}
+
+			// move entry
+			fAddedPackages.insert(package);
+
+			error = entry.MoveTo(&packagesDirectory);
+			if (error != B_OK) {
+				fAddedPackages.erase(package);
+				throw Exception(error,
+					"failed to move new package to packages directory",
+					package->FileName());
+			}
+
+			// also add the package to the volume
+			fVolume->_AddPackage(package);
+		}
+	}
+
+	void _RevertAddPackagesToActivate()
+	{
+		if (fAddedPackages.empty())
+			return;
+
+		// open transaction directory
+		BDirectory transactionDirectory;
+		status_t error = transactionDirectory.SetTo(&fTransactionDirectoryRef);
+		if (error != B_OK) {
+			ERROR("failed to open transaction directory: %s\n",
+				strerror(error));
+		}
+
+		for (PackageSet::iterator it = fAddedPackages.begin();
+			it != fAddedPackages.end(); ++it) {
+			// remove package from the volume
+			Package* package = *it;
+			fVolume->_RemovePackage(package);
+
+			if (transactionDirectory.InitCheck() != B_OK)
+				continue;
+
+			// get BEntry for the package
+			entry_ref entryRef;
+			entryRef.device = fVolume->fPackagesDirectoryRef.device;
+			entryRef.directory = fVolume->fPackagesDirectoryRef.node;
+			if (entryRef.set_name(package->FileName()) != B_OK) {
+				ERROR("out of memory\n");
+				continue;
+			}
+
+			BEntry entry;
+			error = entry.SetTo(&entryRef);
+			if (error != B_OK) {
+				ERROR("failed to get entry for package \"%s\": %s\n",
+					package->FileName().String(), strerror(error));
+				continue;
+			}
+
+			// move entry
+			error = entry.MoveTo(&transactionDirectory);
+			if (error != B_OK) {
+				ERROR("failed to move new package \"%s\" back to transaction "
+					"directory: %s\n", package->FileName().String(),
+					strerror(error));
+				continue;
+			}
+		}
+	}
+
+	void _RevertRemovePackagesToDeactivate()
+	{
+		if (fRemovedPackages.empty())
+			return;
+
+		// open packages directory
+		BDirectory packagesDirectory;
+		status_t error
+			= packagesDirectory.SetTo(&fVolume->fPackagesDirectoryRef);
+		if (error != B_OK) {
+			throw Exception(error, "failed to open packages directory");
+			ERROR("failed to open packages directory: %s\n",
+				strerror(error));
+			return;
+		}
+
+		for (PackageSet::iterator it = fRemovedPackages.begin();
+			it != fRemovedPackages.end(); ++it) {
+			// get an BEntry for the package
+			Package* package = *it;
+			BEntry entry;
+			status_t error = entry.SetTo(&fOldStateDirectory,
+				package->FileName());
+			if (error != B_OK) {
+				ERROR("failed to get entry for package \"%s\": %s\n",
+					package->FileName().String(), strerror(error));
+				continue;
+			}
+
+			// move entry
+			error = entry.MoveTo(&packagesDirectory);
+			if (error != B_OK) {
+				ERROR("failed to move old package \"%s\" back to packages "
+					"directory: %s\n", package->FileName().String(),
+					strerror(error));
+				continue;
+			}
+		}
+	}
+
+	void _RemoveOldStateDirectory()
+	{
+		if (fOldStateDirectory.InitCheck() != B_OK)
+			return;
+
+		// remove the old activation file (it won't exist, if creating it
+		// failed)
+		BEntry(&fOldStateDirectory, kActivationFileName).Remove();
+
+		// Now the directory should be empty. If it isn't, it still contains
+		// some old package file, which we failed to move back.
+		BEntry entry;
+		status_t error = fOldStateDirectory.GetEntry(&entry);
+		if (error != B_OK) {
+			ERROR("failed to get entry for old state directory: %s\n",
+				strerror(error));
+			return;
+		}
+
+		error = entry.Remove();
+		if (error != B_OK) {
+			ERROR("failed to remove old state directory: %s\n",
+				strerror(error));
+			return;
+		}
+	}
+
+private:
+	Volume*		fVolume;
+	BMessage*	fRequest;
+	BMessage&	fReply;
+	PackageList	fPackagesToActivate;
+	PackageSet	fPackagesToDeactivate;
+	PackageSet	fAddedPackages;
+	PackageSet	fRemovedPackages;
+	BDirectory	fOldStateDirectory;
+	BString		fOldStateDirectoryName;
+	node_ref	fTransactionDirectoryRef;
+};
+
+
 // #pragma mark - Volume
 
 
@@ -383,6 +986,42 @@ Volume::HandleGetLocationInfoRequest(BMessage* message)
 }
 
 
+void
+Volume::HandleCommitTransactionRequest(BMessage* message)
+{
+	// Prepare the reply in so far that we can at least set the error code
+	// without risk of failure.
+	BMessage reply(B_MESSAGE_COMMIT_TRANSACTION_REPLY);
+	if (reply.AddInt32("error", B_ERROR) != B_OK)
+		return;
+
+	// perform the request
+	CommitTransactionHandler handler(this, message, reply);
+	int32 error;
+	try {
+		handler.HandleRequest();
+		error = B_DAEMON_OK;
+	} catch (Exception& exception) {
+		error = exception.Error();
+
+		if (!exception.ErrorMessage().IsEmpty())
+			reply.AddString("error message", exception.ErrorMessage());
+		if (!exception.PackageName().IsEmpty())
+			reply.AddString("error package", exception.PackageName());
+	} catch (std::bad_alloc& exception) {
+		error = B_NO_MEMORY;
+	}
+
+	// revert on error
+	if (error != B_DAEMON_OK)
+		handler.Revert();
+
+	// send the reply
+	reply.ReplaceInt32("error", error);
+	message->SendReply(&reply, (BHandler*)NULL, kCommunicationTimeout);
+}
+
+
 void
 Volume::Unmounted()
 {
@@ -477,127 +1116,19 @@ Volume::ProcessPendingPackageActivationChanges()
 {
 	if (!HasPendingPackageActivationChanges())
 		return;
-INFORM("Volume::ProcessPendingPackageActivationChanges(): activating %zu, deactivating %zu packages\n",
-fPackagesToBeActivated.size(), fPackagesToBeDeactivated.size());
 
-	// compute the size of the allocation we need for the activation change
-	// request
-	int32 itemCount
-		= fPackagesToBeActivated.size() + fPackagesToBeDeactivated.size();
-	size_t requestSize = sizeof(PackageFSActivationChangeRequest)
-		+ itemCount * sizeof(PackageFSActivationChangeItem);
-
-	for (PackageSet::iterator it = fPackagesToBeActivated.begin();
-		 it != fPackagesToBeActivated.end(); ++it) {
-		requestSize += (*it)->FileName().Length() + 1;
-	}
-
-	for (PackageSet::iterator it = fPackagesToBeDeactivated.begin();
-		 it != fPackagesToBeDeactivated.end(); ++it) {
-		requestSize += (*it)->FileName().Length() + 1;
-	}
-
-	// allocate and prepare the request
-	PackageFSActivationChangeRequest* request
-		= (PackageFSActivationChangeRequest*)malloc(requestSize);
-	if (request == NULL) {
-		ERROR("out of memory\n");
-		return;
-	}
-	MemoryDeleter requestDeleter(request);
-
-	request->itemCount = itemCount;
-
-	PackageFSActivationChangeItem* item = &request->items[0];
-	char* nameBuffer = (char*)(item + itemCount);
-
-	for (PackageSet::iterator it = fPackagesToBeActivated.begin();
-		it != fPackagesToBeActivated.end(); ++it, item++) {
-		_FillInActivationChangeItem(item, PACKAGE_FS_ACTIVATE_PACKAGE, *it,
-			nameBuffer);
-	}
-
-	for (PackageSet::iterator it = fPackagesToBeDeactivated.begin();
-		it != fPackagesToBeDeactivated.end(); ++it, item++) {
-		_FillInActivationChangeItem(item, PACKAGE_FS_DEACTIVATE_PACKAGE, *it,
-			nameBuffer);
-	}
-
-	// issue the request
-	int fd = OpenRootDirectory();
-	if (fd < 0) {
-		ERROR("Volume::ProcessPendingPackageActivationChanges(): failed to "
-			"open root directory: %s", strerror(fd));
-		return;
-	}
-	FileDescriptorCloser fdCloser(fd);
-
-	if (ioctl(fd, PACKAGE_FS_OPERATION_CHANGE_ACTIVATION, request, requestSize)
-			!= 0) {
-// TODO: We need more error information and error handling!
-		ERROR("Volume::ProcessPendingPackageActivationChanges(): failed to "
-			"activate packages: %s\n", strerror(errno));
-		return;
-	}
-
-	// Update our state, i.e. remove deactivated packages and mark activated
-	// packages accordingly.
-	for (PackageSet::iterator it = fPackagesToBeActivated.begin();
-		it != fPackagesToBeActivated.end(); ++it) {
-		(*it)->SetActive(true);
-		fChangeCount++;
-	}
-
-	for (PackageSet::iterator it = fPackagesToBeDeactivated.begin();
-		it != fPackagesToBeDeactivated.end(); ++it) {
-		Package* package = *it;
-		_RemovePackage(package);
-		delete package;
+	try {
+		_ChangePackageActivation(fPackagesToBeActivated,
+			fPackagesToBeDeactivated);
+	} catch (Exception& exception) {
+		ERROR("Volume::ProcessPendingPackageActivationChanges(): package "
+			"activation failed: %s\n", exception.ToString().String());
+// TODO: Notify the user!
 	}
 
+	// clear the activation/deactivation sets in any event
 	fPackagesToBeActivated.clear();
 	fPackagesToBeDeactivated.clear();
-
-	// write the package activation file
-
-	// create the content
-	BString activationFileContent;
-	for (PackageFileNameHashTable::Iterator it
-			= fPackagesByFileName.GetIterator(); it.HasNext();) {
-		Package* package = it.Next();
-		if (package->IsActive())
-			activationFileContent << package->FileName() << '\n';
-	}
-
-	// open and write the temporary file
-	BFile activationFile;
-	BEntry activationFileEntry;
-	status_t error = _OpenPackagesFile(kAdminDirectoryName,
-		kTemporaryActivationFileName,
-		B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE, activationFile,
-		&activationFileEntry);
-	if (error != B_OK) {
-		ERROR("Volume::ProcessPendingPackageActivationChanges(): failed to "
-			"create activation file: %s\n", strerror(error));
-		return;
-	}
-
-	ssize_t bytesWritten = activationFile.Write(activationFileContent.String(),
-		activationFileContent.Length());
-	if (bytesWritten < 0) {
-		ERROR("Volume::ProcessPendingPackageActivationChanges(): failed to "
-			"write activation file: %s\n", strerror(bytesWritten));
-		return;
-	}
-
-	// rename the temporary file to the final file
-	error = activationFileEntry.Rename(kActivationFileName, true);
-	if (error != B_OK) {
-		ERROR("Volume::ProcessPendingPackageActivationChanges(): failed to "
-			"rename temporary activation file to final file: %s\n",
-			strerror(error));
-		return;
-	}
 }
 
 
@@ -681,6 +1212,13 @@ void
 Volume::_PackagesEntryCreated(const char* name)
 {
 INFORM("Volume::_PackagesEntryCreated(\"%s\")\n", name);
+	// Ignore the event, if we generated it ourselves.
+	Package* package = fPackagesByFileName.Lookup(name);
+	if (package->EntryCreatedIgnoreLevel() > 0) {
+		package->DecrementEntryCreatedIgnoreLevel();
+		return;
+	}
+
 	entry_ref entry;
 	entry.device = fPackagesDirectoryRef.device;
 	entry.directory = fPackagesDirectoryRef.node;
@@ -690,7 +1228,7 @@ INFORM("Volume::_PackagesEntryCreated(\"%s\")\n", name);
 		return;
 	}
 
-	Package* package = new(std::nothrow) Package;
+	package = new(std::nothrow) Package;
 	if (package == NULL) {
 		ERROR("out of memory\n");
 		return;
@@ -723,6 +1261,12 @@ INFORM("Volume::_PackagesEntryRemoved(\"%s\")\n", name);
 	if (package == NULL)
 		return;
 
+	// Ignore the event, if we generated it ourselves.
+	if (package->EntryRemovedIgnoreLevel() > 0) {
+		package->DecrementEntryRemovedIgnoreLevel();
+		return;
+	}
+
 	// Remove the package from the packages-to-be-activated set, if it is in
 	// there (unlikely, unless we see a create-remove-create sequence).
 	PackageSet::iterator it = fPackagesToBeActivated.find(package);
@@ -907,16 +1451,17 @@ Volume::_AddRepository(BSolver* solver, BSolverRepository& repository,
 
 
 status_t
-Volume::_OpenPackagesFile(const char* subDirectoryPath, const char* fileName,
-	uint32 openMode, BFile& _file, BEntry* _entry)
+Volume::_OpenPackagesFile(const RelativePath& subDirectoryPath,
+	const char* fileName, uint32 openMode, BFile& _file, BEntry* _entry)
 {
 	BDirectory directory;
-	if (subDirectoryPath != NULL) {
+	if (!subDirectoryPath.IsEmpty()) {
 		status_t error = _OpenPackagesSubDirectory(subDirectoryPath,
 			(openMode & B_CREATE_FILE) != 0, directory);
 		if (error != B_OK) {
 			ERROR("Volume::_OpenPackagesFile(): failed to open packages "
-				"subdirectory \"%s\": %s\n", subDirectoryPath, strerror(error));
+				"subdirectory \"%s\": %s\n",
+				subDirectoryPath.ToString().String(), strerror(error));
 			RETURN_ERROR(error);
 		}
 	} else {
@@ -942,7 +1487,7 @@ Volume::_OpenPackagesFile(const char* subDirectoryPath, const char* fileName,
 
 
 status_t
-Volume::_OpenPackagesSubDirectory(const char* path, bool create,
+Volume::_OpenPackagesSubDirectory(const RelativePath& path, bool create,
 	BDirectory& _directory)
 {
 	// open the packages directory
@@ -954,16 +1499,22 @@ Volume::_OpenPackagesSubDirectory(const char* path, bool create,
 		RETURN_ERROR(error);
 	}
 
+	// get a string for the path
+	BString pathString = path.ToString();
+	if (pathString.IsEmpty())
+		RETURN_ERROR(B_NO_MEMORY);
+
 	// If creating is not allowed, just try to open it.
 	if (!create)
-		RETURN_ERROR(_directory.SetTo(&directory, path));
+		RETURN_ERROR(_directory.SetTo(&directory, pathString));
 
 	// get an absolute path and create the subdirectory
 	BPath absolutePath;
-	error = absolutePath.SetTo(&directory, path);
+	error = absolutePath.SetTo(&directory, pathString);
 	if (error != B_OK) {
 		ERROR("Volume::_OpenConfigSubDirectory(): failed to get absolute path "
-			"for subdirectory \"%s\": %s\n", path, strerror(error));
+			"for subdirectory \"%s\": %s\n", pathString.String(),
+			strerror(error));
 		RETURN_ERROR(error);
 	}
 
@@ -971,9 +1522,197 @@ Volume::_OpenPackagesSubDirectory(const char* path, bool create,
 		S_IRWXU | S_IRGRP | S_IXGRP | S_IROTH | S_IXOTH);
 	if (error != B_OK) {
 		ERROR("Volume::_OpenConfigSubDirectory(): failed to create packages "
-			"subdirectory \"%s\": %s\n", path, strerror(error));
+			"subdirectory \"%s\": %s\n", pathString.String(),
+			strerror(error));
 		RETURN_ERROR(error);
 	}
 
-	RETURN_ERROR(_directory.SetTo(&directory, path));
+	RETURN_ERROR(_directory.SetTo(&directory, pathString));
+}
+
+
+status_t
+Volume::_CreateActivationFileContent(const PackageSet& toActivate,
+	const PackageSet& toDeactivate, BString& _content)
+{
+	BString activationFileContent;
+	for (PackageFileNameHashTable::Iterator it
+			= fPackagesByFileName.GetIterator(); it.HasNext();) {
+		Package* package = it.Next();
+		if (package->IsActive()
+			&& toDeactivate.find(package) == toDeactivate.end()) {
+			int32 length = activationFileContent.Length();
+			activationFileContent << package->FileName() << '\n';
+			if (activationFileContent.Length()
+					< length + package->FileName().Length() + 1) {
+				return B_NO_MEMORY;
+			}
+		}
+	}
+
+	for (PackageSet::const_iterator it = toActivate.begin();
+		it != toActivate.end(); ++it) {
+		Package* package = *it;
+		int32 length = activationFileContent.Length();
+		activationFileContent << package->FileName() << '\n';
+		if (activationFileContent.Length()
+				< length + package->FileName().Length() + 1) {
+			return B_NO_MEMORY;
+		}
+	}
+
+	_content = activationFileContent;
+	return B_OK;
+}
+
+
+status_t
+Volume::_WriteActivationFile(const RelativePath& directoryPath,
+	const char* fileName, const PackageSet& toActivate,
+	const PackageSet& toDeactivate,
+	BEntry& _entry)
+{
+	// create the content
+	BString activationFileContent;
+	status_t error = _CreateActivationFileContent(fPackagesToBeActivated,
+		fPackagesToBeDeactivated, activationFileContent);
+	if (error != B_OK)
+		return error;
+
+	// write the file
+	BEntry activationFileEntry;
+	error = _WriteTextFile(directoryPath, fileName, activationFileContent,
+		activationFileEntry);
+	if (error != B_OK) {
+		ERROR("Volume::_WriteActivationFile(): failed to write activation "
+			"file \"%s/%s\": %s\n", directoryPath.ToString().String(), fileName,
+			strerror(error));
+		return error;
+	}
+
+	return B_OK;
+}
+
+
+status_t
+Volume::_WriteTextFile(const RelativePath& directoryPath, const char* fileName,
+	const BString& content, BEntry& _entry)
+{
+	BFile file;
+	status_t error = _OpenPackagesFile(directoryPath,
+		fileName, B_READ_WRITE | B_CREATE_FILE | B_ERASE_FILE, file, &_entry);
+	if (error != B_OK) {
+		ERROR("Volume::_WriteTextFile(): failed to create file \"%s/%s\": %s\n",
+			directoryPath.ToString().String(), fileName, strerror(error));
+		return error;
+	}
+
+	ssize_t bytesWritten = file.Write(content.String(),
+		content.Length());
+	if (bytesWritten < 0) {
+		ERROR("Volume::_WriteTextFile(): failed to write file \"%s/%s\": %s\n",
+			directoryPath.ToString().String(), fileName,
+			strerror(bytesWritten));
+		return bytesWritten;
+	}
+
+	return B_OK;
+}
+
+
+void
+Volume::_ChangePackageActivation(const PackageSet& packagesToActivate,
+	const PackageSet& packagesToDeactivate)
+{
+INFORM("Volume::ProcessPendingPackageActivationChanges(): activating %zu, deactivating %zu packages\n",
+packagesToActivate.size(), packagesToDeactivate.size());
+
+	// write the temporary package activation file
+	BEntry activationFileEntry;
+	status_t error = _WriteActivationFile(RelativePath(kAdminDirectoryName),
+		kTemporaryActivationFileName, packagesToActivate, packagesToDeactivate,
+		activationFileEntry);
+	if (error != B_OK)
+		throw Exception(error, "failed to write activation file");
+
+	// compute the size of the allocation we need for the activation change
+	// request
+	int32 itemCount = packagesToActivate.size() + packagesToDeactivate.size();
+	size_t requestSize = sizeof(PackageFSActivationChangeRequest)
+		+ itemCount * sizeof(PackageFSActivationChangeItem);
+
+	for (PackageSet::iterator it = packagesToActivate.begin();
+		 it != packagesToActivate.end(); ++it) {
+		requestSize += (*it)->FileName().Length() + 1;
+	}
+
+	for (PackageSet::iterator it = packagesToDeactivate.begin();
+		 it != packagesToDeactivate.end(); ++it) {
+		requestSize += (*it)->FileName().Length() + 1;
+	}
+
+	// allocate and prepare the request
+	PackageFSActivationChangeRequest* request
+		= (PackageFSActivationChangeRequest*)malloc(requestSize);
+	if (request == NULL)
+		throw Exception(B_NO_MEMORY);
+	MemoryDeleter requestDeleter(request);
+
+	request->itemCount = itemCount;
+
+	PackageFSActivationChangeItem* item = &request->items[0];
+	char* nameBuffer = (char*)(item + itemCount);
+
+	for (PackageSet::iterator it = packagesToActivate.begin();
+		it != packagesToActivate.end(); ++it, item++) {
+		_FillInActivationChangeItem(item, PACKAGE_FS_ACTIVATE_PACKAGE, *it,
+			nameBuffer);
+	}
+
+	for (PackageSet::iterator it = packagesToDeactivate.begin();
+		it != packagesToDeactivate.end(); ++it, item++) {
+		_FillInActivationChangeItem(item, PACKAGE_FS_DEACTIVATE_PACKAGE, *it,
+			nameBuffer);
+	}
+
+	// issue the request
+	int fd = OpenRootDirectory();
+	if (fd < 0)
+		throw Exception(fd, "failed to open root directory");
+	FileDescriptorCloser fdCloser(fd);
+
+	if (ioctl(fd, PACKAGE_FS_OPERATION_CHANGE_ACTIVATION, request, requestSize)
+			!= 0) {
+// TODO: We need more error information and error handling!
+		throw Exception(errno, "ioctl() to de-/activate packages failed");
+	}
+
+	// rename the temporary activation file to the final file
+	error = activationFileEntry.Rename(kActivationFileName, true);
+	if (error != B_OK) {
+		throw Exception(error,
+			"failed to rename temporary activation file to final file");
+// TODO: We should probably try to reverse the activation changes, though that
+// will fail, if this method has been called in response to node monitoring
+// events. Alternatively moving the package activation file could be made part
+// of the ioctl(), since packagefs should be able to undo package changes until
+// the very end, unless running out of memory. In the end the situation would be
+// bad anyway, though, since the activation file may refer to removed packages
+// and things would be in an inconsistent state after rebooting.
+	}
+
+	// Update our state, i.e. remove deactivated packages and mark activated
+	// packages accordingly.
+	for (PackageSet::iterator it = packagesToActivate.begin();
+		it != packagesToActivate.end(); ++it) {
+		(*it)->SetActive(true);
+		fChangeCount++;
+	}
+
+	for (PackageSet::iterator it = fPackagesToBeDeactivated.begin();
+		it != fPackagesToBeDeactivated.end(); ++it) {
+		Package* package = *it;
+		_RemovePackage(package);
+		delete package;
+	}
 }
diff --git a/src/servers/package/Volume.h b/src/servers/package/Volume.h
index 8e65ff3fe1..51b644b78b 100644
--- a/src/servers/package/Volume.h
+++ b/src/servers/package/Volume.h
@@ -50,6 +50,8 @@ public:
 			void				InitialVerify(Volume* nextVolume,
 									Volume* nextNextVolume);
 			void				HandleGetLocationInfoRequest(BMessage* message);
+			void				HandleCommitTransactionRequest(
+									BMessage* message);
 
 			void				Unmounted();
 
@@ -88,8 +90,13 @@ public:
 
 private:
 			struct NodeMonitorEvent;
-			typedef DoublyLinkedList NodeMonitorEventList;
+			struct RelativePath;
+			struct Exception;
+			struct CommitTransactionHandler;
 
+			friend struct CommitTransactionHandler;
+
+			typedef DoublyLinkedList NodeMonitorEventList;
 			typedef std::set PackageSet;
 
 private:
@@ -117,11 +124,34 @@ private:
 									BSolverRepository& repository,
 							 		bool activeOnly, bool installed);
 
-			status_t			_OpenPackagesFile(const char* subDirectoryPath,
+			status_t			_OpenPackagesFile(
+									const RelativePath& subDirectoryPath,
 									const char* fileName, uint32 openMode,
 									BFile& _file, BEntry* _entry = NULL);
-			status_t			_OpenPackagesSubDirectory(const char* path,
-									bool create, BDirectory& _directory);
+			status_t			_OpenPackagesSubDirectory(
+									const RelativePath& path, bool create,
+									BDirectory& _directory);
+
+			status_t			_CreateActivationFileContent(
+									const PackageSet& toActivate,
+									const PackageSet& toDeactivate,
+									BString& _content);
+			status_t			_WriteActivationFile(
+									const RelativePath& directoryPath,
+									const char* fileName,
+									const PackageSet& toActivate,
+									const PackageSet& toDeactivate,
+									BEntry& _entry);
+
+			status_t			_WriteTextFile(
+									const RelativePath& directoryPath,
+									const char* fileName,
+									const BString& content, BEntry& _entry);
+
+			void				_ChangePackageActivation(
+									const PackageSet& packagesToActivate,
+									const PackageSet& packagesToDeactivate);
+									// throws Exception
 
 private:
 			BString				fPath;

From f71be99bd913f8cc8aab59b97f656dec32f06837 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 13:26:34 +0200
Subject: [PATCH 0440/1170] BRequest: Add Process()

The method creates the initial jobs for the request and processes the
jobs from the job queue until empty or an error occurs.
---
 headers/os/package/Request.h |  2 ++
 src/kits/package/Request.cpp | 24 ++++++++++++++++++++++++
 2 files changed, 26 insertions(+)

diff --git a/headers/os/package/Request.h b/headers/os/package/Request.h
index 57ae1af807..5414201366 100644
--- a/headers/os/package/Request.h
+++ b/headers/os/package/Request.h
@@ -32,6 +32,8 @@ public:
 
 			BJob*				PopRunnableJob();
 
+			status_t			Process(bool failIfCanceledOnly = false);
+
 protected:
 			status_t			QueueJob(BJob* job);
 
diff --git a/src/kits/package/Request.cpp b/src/kits/package/Request.cpp
index 7005c5e325..35c4058eeb 100644
--- a/src/kits/package/Request.cpp
+++ b/src/kits/package/Request.cpp
@@ -49,6 +49,30 @@ BRequest::PopRunnableJob()
 }
 
 
+status_t
+BRequest::Process(bool failIfCanceledOnly)
+{
+	status_t error = InitCheck();
+	if (error != B_OK)
+		return error;
+
+	error = CreateInitialJobs();
+	if (error != B_OK)
+		return error;
+
+	while (BJob* job = PopRunnableJob()) {
+		error = job->Run();
+		delete job;
+		if (error != B_OK) {
+			if (!failIfCanceledOnly || error == B_CANCELED)
+				return error;
+		}
+	}
+
+	return B_OK;
+}
+
+
 status_t
 BRequest::QueueJob(BJob* job)
 {

From e0d4161d42a235f3e365787ee0470fc61c8e668d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 13:28:36 +0200
Subject: [PATCH 0441/1170] pkgman: Make use of BRequest::Process()

---
 src/bin/pkgman/command_add_repo.cpp  | 39 +++++++++++-----------------
 src/bin/pkgman/command_drop_repo.cpp | 19 +++++---------
 src/bin/pkgman/command_refresh.cpp   | 26 ++++++-------------
 3 files changed, 30 insertions(+), 54 deletions(-)

diff --git a/src/bin/pkgman/command_add_repo.cpp b/src/bin/pkgman/command_add_repo.cpp
index b63583bf9e..798ae6a780 100644
--- a/src/bin/pkgman/command_add_repo.cpp
+++ b/src/bin/pkgman/command_add_repo.cpp
@@ -87,18 +87,13 @@ AddRepoCommand::Execute(int argc, const char* const* argv)
 	status_t result;
 	for (int i = 0; i < urlCount; ++i) {
 		AddRepositoryRequest addRequest(context, repoURLs[i], asUserRepository);
-		result = addRequest.InitCheck();
-		if (result != B_OK)
-			DIE(result, "unable to create request for adding repository");
-		result = addRequest.CreateInitialJobs();
-		if (result != B_OK)
-			DIE(result, "unable to create necessary jobs");
-
-		while (BJob* job = addRequest.PopRunnableJob()) {
-			result = job->Run();
-			delete job;
-			if (result == B_CANCELED)
-				return 1;
+		result = addRequest.Process(true);
+		if (result != B_OK) {
+			if (result != B_CANCELED) {
+				DIE(result, "request for adding repository \"%s\" failed",
+					repoURLs[i]);
+			}
+			return 1;
 		}
 
 		// now refresh the repo-cache of the new repository
@@ -106,19 +101,15 @@ AddRepoCommand::Execute(int argc, const char* const* argv)
 		BPackageRoster roster;
 		BRepositoryConfig repoConfig;
 		roster.GetRepositoryConfig(repoName, &repoConfig);
+		
 		BRefreshRepositoryRequest refreshRequest(context, repoConfig);
-		result = refreshRequest.InitCheck();
-		if (result != B_OK)
-			DIE(result, "unable to create request for refreshing repository");
-		result = refreshRequest.CreateInitialJobs();
-		if (result != B_OK)
-			DIE(result, "unable to create necessary jobs");
-
-		while (BJob* job = refreshRequest.PopRunnableJob()) {
-			result = job->Run();
-			delete job;
-			if (result == B_CANCELED)
-				return 1;
+		result = refreshRequest.Process(true);
+		if (result != B_OK) {
+			if (result != B_CANCELED) {
+				DIE(result, "request for refreshing repository \"%s\" failed",
+					repoName.String());
+			}
+			return 1;
 		}
 	}
 
diff --git a/src/bin/pkgman/command_drop_repo.cpp b/src/bin/pkgman/command_drop_repo.cpp
index e026757b8c..0703fb1011 100644
--- a/src/bin/pkgman/command_drop_repo.cpp
+++ b/src/bin/pkgman/command_drop_repo.cpp
@@ -85,18 +85,13 @@ DropRepoCommand::Execute(int argc, const char* const* argv)
 
 	status_t result;
 	DropRepositoryRequest dropRequest(context, repoName);
-	result = dropRequest.InitCheck();
-	if (result != B_OK)
-		DIE(result, "unable to create request for dropping repository");
-	result = dropRequest.CreateInitialJobs();
-	if (result != B_OK)
-		DIE(result, "unable to create necessary jobs");
-
-	while (BJob* job = dropRequest.PopRunnableJob()) {
-		result = job->Run();
-		delete job;
-		if (result == B_CANCELED)
-			return 1;
+	result = dropRequest.Process(true);
+	if (result != B_OK) {
+		if (result != B_CANCELED) {
+			DIE(result, "request for dropping repository \"%s\" failed",
+				repoName);
+		}
+		return 1;
 	}
 
 	return 0;
diff --git a/src/bin/pkgman/command_refresh.cpp b/src/bin/pkgman/command_refresh.cpp
index 50764c99c6..6023edca6a 100644
--- a/src/bin/pkgman/command_refresh.cpp
+++ b/src/bin/pkgman/command_refresh.cpp
@@ -40,7 +40,6 @@ static const char* const kLongUsage =
 DEFINE_COMMAND(RefreshCommand, "refresh", kShortUsage, kLongUsage)
 
 
-
 int
 RefreshCommand::Execute(int argc, const char* const* argv)
 {
@@ -70,10 +69,6 @@ RefreshCommand::Execute(int argc, const char* const* argv)
 	const char* const* repoArgs = argv + optind;
 	int nameCount = argc - optind;
 
-	DecisionProvider decisionProvider;
-	JobStateListener listener;
-	BContext context(decisionProvider, listener);
-
 	BStringList repositoryNames(20);
 
 	BPackageRoster roster;
@@ -88,6 +83,10 @@ RefreshCommand::Execute(int argc, const char* const* argv)
 		}
 	}
 
+	DecisionProvider decisionProvider;
+	JobStateListener listener;
+	BContext context(decisionProvider, listener);
+
 	status_t result;
 	for (int i = 0; i < repositoryNames.CountStrings(); ++i) {
 		const BString& repoName = repositoryNames.StringAt(i);
@@ -99,20 +98,11 @@ RefreshCommand::Execute(int argc, const char* const* argv)
 			WARN(result, "skipping repository-config '%s'", path.Path());
 			continue;
 		}
-		BRefreshRepositoryRequest refreshRequest(context, repoConfig);
-		result = refreshRequest.InitCheck();
-		if (result != B_OK)
-			DIE(result, "unable to create request for refreshing repository");
-		result = refreshRequest.CreateInitialJobs();
-		if (result != B_OK)
-			DIE(result, "unable to create necessary jobs");
 
-		while (BJob* job = refreshRequest.PopRunnableJob()) {
-			result = job->Run();
-			delete job;
-			if (result != B_OK)
-				return 1;
-		}
+		BRefreshRepositoryRequest refreshRequest(context, repoConfig);
+		result = refreshRequest.Process();
+		if (result != B_OK)
+			DIE(result, "request for refreshing repository failed");
 	}
 
 	return 0;

From 74233e2c8884cbfe4faaea10f37f44b3d7f56dd8 Mon Sep 17 00:00:00 2001
From: Oliver Tappe 
Date: Sat, 20 Apr 2013 15:16:00 +0200
Subject: [PATCH 0442/1170] Re-apply cf0a957 for the build-version of libbe.

* fixes build on non-Haiku platforms
---
 headers/build/os/app/Message.h  |  3 +++
 src/build/libbe/app/Message.cpp | 45 +++++++++++++++++++++++++++++++++
 2 files changed, 48 insertions(+)

diff --git a/headers/build/os/app/Message.h b/headers/build/os/app/Message.h
index 9ec0a35582..5fd4f4c907 100644
--- a/headers/build/os/app/Message.h
+++ b/headers/build/os/app/Message.h
@@ -22,6 +22,7 @@ class BBlockCache;
 class BMessenger;
 class BHandler;
 class BString;
+class BStringList;
 struct entry_ref;
 
 
@@ -105,6 +106,7 @@ class BMessage {
 		status_t		AddPoint(const char *name, BPoint aPoint);
 		status_t		AddString(const char *name, const char *aString);
 		status_t		AddString(const char *name, const BString &aString);
+		status_t		AddStrings(const char *name, const BStringList &list);
 		status_t		AddInt8(const char *name, int8 value);
 		status_t		AddUInt8(const char *name, uint8 value);
 		status_t		AddInt16(const char *name, int16 value);
@@ -140,6 +142,7 @@ class BMessage {
 		status_t		FindString(const char *name, int32 index, const char **string) const;
 		status_t		FindString(const char *name, BString *string) const;
 		status_t		FindString(const char *name, int32 index, BString *string) const;
+		status_t		FindStrings(const char *name, BStringList *list) const;
 		status_t		FindInt8(const char *name, int8 *value) const;
 		status_t		FindInt8(const char *name, int32 index, int8 *value) const;
 		status_t		FindUInt8(const char *name, uint8 *value) const;
diff --git a/src/build/libbe/app/Message.cpp b/src/build/libbe/app/Message.cpp
index 380cb7d3d9..70243596d6 100644
--- a/src/build/libbe/app/Message.cpp
+++ b/src/build/libbe/app/Message.cpp
@@ -25,6 +25,7 @@
 #include 
 #include 
 #include 
+#include 
 
 #include 
 #include 
@@ -1746,6 +1747,20 @@ BMessage::AddString(const char *name, const BString &string)
 }
 
 
+status_t
+BMessage::AddStrings(const char *name, const BStringList &list)
+{
+	int32 count = list.CountStrings();
+	for (int32 i = 0; i < count; i++) {
+		status_t error = AddString(name, list.StringAt(i));
+		if (error != B_OK)
+			return error;
+	}
+
+	return B_OK;
+}
+
+
 status_t
 BMessage::AddPointer(const char *name, const void *pointer)
 {
@@ -1875,6 +1890,36 @@ BMessage::FindString(const char *name, int32 index, BString *string) const
 }
 
 
+status_t
+BMessage::FindStrings(const char *name, BStringList *list) const
+{
+	if (list == NULL)
+		return B_BAD_VALUE;
+
+	list->MakeEmpty();
+
+	// get the number of items
+	type_code type;
+	int32 count;
+	if (GetInfo(name, &type, &count) != B_OK)
+		return B_NAME_NOT_FOUND;
+
+	if (type != B_STRING_TYPE)
+		return B_BAD_DATA;
+
+	for (int32 i = 0; i < count; i++) {
+		BString string;
+		status_t error = FindString(name, i, &string);
+		if (error != B_OK)
+			return error;
+		if (!list->Add(string))
+			return B_NO_MEMORY;
+	}
+
+	return B_OK;
+}
+
+
 status_t
 BMessage::FindPointer(const char *name, void **pointer) const
 {

From bab6caf3e07bf21d88a5dff857f8ccc7b96e9c0e Mon Sep 17 00:00:00 2001
From: Oliver Tappe 
Date: Sat, 20 Apr 2013 15:32:19 +0200
Subject: [PATCH 0443/1170] Another lap of updating base packages:

* binutils has now been split off gcc
* adjusted other packages to new naming scheme
---
 build/jam/OptionalBuildFeatures |  2 +-
 build/jam/OptionalPackages      | 37 ++++++++++++++++++---------------
 2 files changed, 21 insertions(+), 18 deletions(-)

diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures
index 8cbad213b8..46211c7037 100644
--- a/build/jam/OptionalBuildFeatures
+++ b/build/jam/OptionalBuildFeatures
@@ -14,7 +14,7 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSL ] {
 if $(HAIKU_GCC_VERSION[1]) >= 4 {
 	HAIKU_OPENSSL_PACKAGE = openssl-1.0.0e-x86-gcc4-2011-09-08.zip ;
 } else {
-	HAIKU_OPENSSL_PACKAGE = openssl-1.0.0d-3-x86_gcc2.hpkg ;
+	HAIKU_OPENSSL_PACKAGE = openssl-1.0.0d-4-x86_gcc2.hpkg ;
 }
 
 local baseURL = http://haiku-files.org/files/optional-packages ;
diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index be28c41153..2034927962 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -112,7 +112,7 @@ if [ IsOptionalHaikuImagePackageAdded APR ] {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/apr-1.4.2-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/apr-1.4.2-5-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -128,7 +128,7 @@ if [ IsOptionalHaikuImagePackageAdded APR-util ] {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/apr-util-1.3.10-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/apr_util-1.3.10-4-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -467,13 +467,13 @@ if [ IsOptionalHaikuImagePackageAdded Development ] && $(TARGET_ARCH) = x86 {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/autoconf-2.68-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/autoconf-2.68-4-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/automake-1.11.1-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/automake-1.11.1-4-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/libtool-2.4-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/libtool-2.4-4-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
 			$(hpkgBaseURL)/texinfo-4.13a-2-x86_gcc2.hpkg
@@ -488,7 +488,10 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 	# gcc and binutils
 	if $(HAIKU_GCC_VERSION[1]) = 2 {
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/gcc-2.95.3_110711-4-x86_gcc2.hpkg
+			$(hpkgBaseURL)/binutils-2.17_110711-2-x86_gcc2.hpkg
+			: common packages ;
+		InstallOptionalHaikuImagePackage
+			$(hpkgBaseURL)/gcc-2.95.3_110711-5-x86_gcc2.hpkg
 			: common packages ;
 
 		# TODO: remove this when we have a mechanism to switch gcc via PATH
@@ -521,7 +524,7 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 			$(hpkgBaseURL)/bison-2.4.3-2-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/m4-1.4.16-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/m4-1.4.16-4-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
 			$(hpkgBaseURL)/flex-2.5.35-2-x86_gcc2.hpkg
@@ -533,7 +536,7 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 			$(hpkgBaseURL)/mkdepend-1.7-1-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/make-3.82-3-x86_gcc2.hpkg
+			$(hpkgBaseURL)/make-3.82-4-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -613,7 +616,7 @@ if [ IsOptionalHaikuImagePackageAdded Expat ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				$(hpkgBaseURL)/expat-2.0.1-3-x86_gcc2.hpkg
+				$(hpkgBaseURL)/expat-2.0.1-4-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -809,7 +812,7 @@ if [ IsOptionalHaikuImagePackageAdded LibIconv ] {
 				$(baseURL)/libiconv-1.13.1-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				$(hpkgBaseURL)/libiconv-1.13.1-3-x86_gcc2.hpkg
+				$(hpkgBaseURL)/libiconv-1.13.1-4-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -865,7 +868,7 @@ if [ IsOptionalHaikuImagePackageAdded LibXML2 ] {
 				$(baseURL)/libxml2-2.7.8-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				$(hpkgBaseURL)/libxml2-2.7.8-3-x86_gcc2.hpkg
+				$(hpkgBaseURL)/libxml2-2.7.8-4-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -985,7 +988,7 @@ if [ IsOptionalHaikuImagePackageAdded Neon ] {
 				$(baseURL)/neon-0.29.6-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				$(hpkgBaseURL)/neon-0.29.6-3-x86_gcc2.hpkg
+				$(hpkgBaseURL)/neon-0.29.6-4-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1194,7 +1197,7 @@ if [ IsOptionalHaikuImagePackageAdded Perl ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				$(hpkgBaseURL)/perl-5.10.1-3-x86_gcc2.hpkg
+				$(hpkgBaseURL)/perl-5.10.1-4-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1260,7 +1263,7 @@ if [ IsOptionalHaikuImagePackageAdded Sed ] {
 			$(baseURL)/sed-4.2.1-r1a3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/sed-4.2.1-2-x86_gcc2.hpkg
+			$(hpkgBaseURL)/sed-4.2.1-3-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -1276,7 +1279,7 @@ if [ IsOptionalHaikuImagePackageAdded SQLite ] {
 				$(baseURL)/sqlite-3.7.5-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				$(hpkgBaseURL)/sqlite-3.7.5-4-x86_gcc2.hpkg
+				$(hpkgBaseURL)/sqlite-3.7.5-5-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1294,7 +1297,7 @@ if [ IsOptionalHaikuImagePackageAdded Subversion ] {
 				: : true ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				$(hpkgBaseURL)/subversion-1.6.15-3-x86_gcc2.hpkg
+				$(hpkgBaseURL)/subversion-1.6.15-4-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}
@@ -1325,7 +1328,7 @@ if [ IsOptionalHaikuImagePackageAdded Tar ] {
 				$(baseURL)/tar-1.25-r1a3-x86-gcc4-2011-05-24.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				$(hpkgBaseURL)/tar-1.26-2-x86_gcc2.hpkg
+				$(hpkgBaseURL)/tar-1.26-3-x86_gcc2.hpkg
 				: common packages ;
 		}
 	}

From e2678ec0413faa7cdf17c8ae57e4d74a109336cb Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 14:01:32 +0200
Subject: [PATCH 0444/1170] pkgman refresh: Include the repository name in
 error message

---
 src/bin/pkgman/command_refresh.cpp | 6 ++++--
 1 file changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/bin/pkgman/command_refresh.cpp b/src/bin/pkgman/command_refresh.cpp
index 6023edca6a..4eddeae2a0 100644
--- a/src/bin/pkgman/command_refresh.cpp
+++ b/src/bin/pkgman/command_refresh.cpp
@@ -101,8 +101,10 @@ RefreshCommand::Execute(int argc, const char* const* argv)
 
 		BRefreshRepositoryRequest refreshRequest(context, repoConfig);
 		result = refreshRequest.Process();
-		if (result != B_OK)
-			DIE(result, "request for refreshing repository failed");
+		if (result != B_OK) {
+			DIE(result, "request for refreshing repository \"%s\" failed",
+				repoName.String());
+		}
 	}
 
 	return 0;

From 2e3f5000e34297071e630ab70303026715021e31 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 17:15:50 +0200
Subject: [PATCH 0445/1170] package daemon: Fix check in
 Volume::_PackagesEntryCreated()

---
 src/servers/package/Volume.cpp | 12 +++++++++---
 1 file changed, 9 insertions(+), 3 deletions(-)

diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index 80225c4556..0a4ff8d2be 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -1212,10 +1212,16 @@ void
 Volume::_PackagesEntryCreated(const char* name)
 {
 INFORM("Volume::_PackagesEntryCreated(\"%s\")\n", name);
-	// Ignore the event, if we generated it ourselves.
+	// Ignore the event, if the package is already known.
 	Package* package = fPackagesByFileName.Lookup(name);
-	if (package->EntryCreatedIgnoreLevel() > 0) {
-		package->DecrementEntryCreatedIgnoreLevel();
+	if (package != NULL) {
+		if (package->EntryCreatedIgnoreLevel() > 0) {
+			package->DecrementEntryCreatedIgnoreLevel();
+		} else {
+			WARN("node monitoring created event for already known entry "
+				"\"%s\"\n", name);
+		}
+
 		return;
 	}
 

From a3b1c7b96e47e5129c83a5dae6e3b17d1ad06b19 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 17:29:06 +0200
Subject: [PATCH 0446/1170] package daemon: Volume::_WriteActivationFile():
 Init _entry

---
 src/servers/package/Volume.cpp | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index 0a4ff8d2be..9177c911f5 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -1586,9 +1586,8 @@ Volume::_WriteActivationFile(const RelativePath& directoryPath,
 		return error;
 
 	// write the file
-	BEntry activationFileEntry;
 	error = _WriteTextFile(directoryPath, fileName, activationFileContent,
-		activationFileEntry);
+		_entry);
 	if (error != B_OK) {
 		ERROR("Volume::_WriteActivationFile(): failed to write activation "
 			"file \"%s/%s\": %s\n", directoryPath.ToString().String(), fileName,

From be8f5e00f136fdc45f58c4a1c4d802eac9a6e96c Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 21:10:21 +0200
Subject: [PATCH 0447/1170] BPackageInfo: Add CanonicalFileName()

The name of the package file is not part of the package-info.
CanonicalFileName() constructs the name the file should have (not
enforced anywhere (yet)).
---
 headers/os/package/PackageInfo.h |  2 ++
 src/kits/package/PackageInfo.cpp | 11 +++++++++++
 2 files changed, 13 insertions(+)

diff --git a/headers/os/package/PackageInfo.h b/headers/os/package/PackageInfo.h
index 9efaea3028..5b0260c6cb 100644
--- a/headers/os/package/PackageInfo.h
+++ b/headers/os/package/PackageInfo.h
@@ -89,6 +89,8 @@ public:
 								FreshensList() const;
 			const BStringList&	ReplacesList() const;
 
+			BString				CanonicalFileName() const;
+
 			void				SetName(const BString& name);
 			void				SetSummary(const BString& summary);
 			void				SetDescription(const BString& description);
diff --git a/src/kits/package/PackageInfo.cpp b/src/kits/package/PackageInfo.cpp
index 4d14eee0ac..430bef12cf 100644
--- a/src/kits/package/PackageInfo.cpp
+++ b/src/kits/package/PackageInfo.cpp
@@ -1590,6 +1590,17 @@ BPackageInfo::ReplacesList() const
 }
 
 
+BString
+BPackageInfo::CanonicalFileName() const
+{
+	if (InitCheck() != B_OK)
+		return BString();
+
+	return BString().SetToFormat("%s-%s-%s.hpkg", fName.String(),
+		fVersion.ToString().String(), kArchitectureNames[fArchitecture]);
+}
+
+
 void
 BPackageInfo::SetName(const BString& name)
 {

From 4ea7f45bc5d8ac2936c0c498fd3fc0a45f375f19 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 21:12:40 +0200
Subject: [PATCH 0448/1170] BRequest: Change attribute protection from private
 to protected

Particularly fInitStatus is of interest for derived classes.
---
 headers/os/package/Request.h | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/headers/os/package/Request.h b/headers/os/package/Request.h
index 5414201366..71d1ba8ca7 100644
--- a/headers/os/package/Request.h
+++ b/headers/os/package/Request.h
@@ -39,7 +39,7 @@ protected:
 
 			const BContext&		fContext;
 
-private:
+protected:
 			status_t			fInitStatus;
 			JobQueue*			fJobQueue;
 };

From e14b247176d56b1ddaa4a5efa46ca3c60f33a093 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 21:16:17 +0200
Subject: [PATCH 0449/1170] Add StringChecksumAccessor

A ChecksumAccessor implementation for an already known checksum.
---
 headers/private/package/ChecksumAccessors.h | 11 ++++++++
 src/kits/package/ChecksumAccessors.cpp      | 31 ++++++++++++++++++++-
 2 files changed, 41 insertions(+), 1 deletion(-)

diff --git a/headers/private/package/ChecksumAccessors.h b/headers/private/package/ChecksumAccessors.h
index 8872cd5606..ba95aa5d01 100644
--- a/headers/private/package/ChecksumAccessors.h
+++ b/headers/private/package/ChecksumAccessors.h
@@ -49,6 +49,17 @@ private:
 };
 
 
+class StringChecksumAccessor : public ChecksumAccessor {
+public:
+								StringChecksumAccessor(const BString& checksum);
+
+	virtual	status_t			GetChecksum(BString& _checksum) const;
+
+private:
+			BString				fChecksum;
+};
+
+
 }	// namespace BPrivate
 
 }	// namespace BPackageKit
diff --git a/src/kits/package/ChecksumAccessors.cpp b/src/kits/package/ChecksumAccessors.cpp
index 8ec09c9e90..4eca081e7c 100644
--- a/src/kits/package/ChecksumAccessors.cpp
+++ b/src/kits/package/ChecksumAccessors.cpp
@@ -1,9 +1,10 @@
 /*
- * Copyright 2011, Haiku, Inc. All Rights Reserved.
+ * Copyright 2011-2013, Haiku, Inc. All Rights Reserved.
  * Distributed under the terms of the MIT License.
  *
  * Authors:
  *		Oliver Tappe 
+ *		Ingo Weinhold 
  */
 
 
@@ -24,11 +25,17 @@ namespace BPrivate {
 	(nibble >= 10 ? 'a' + nibble - 10 : '0' + nibble)
 
 
+// #pragma mark - ChecksumAccessor
+
+
 ChecksumAccessor::~ChecksumAccessor()
 {
 }
 
 
+// #pragma mark - ChecksumFileChecksumAccessor
+
+
 ChecksumFileChecksumAccessor::ChecksumFileChecksumAccessor(
 	const BEntry& checksumFileEntry)
 	:
@@ -62,6 +69,9 @@ ChecksumFileChecksumAccessor::GetChecksum(BString& checksum) const
 }
 
 
+// #pragma mark - GeneralFileChecksumAccessor
+
+
 GeneralFileChecksumAccessor::GeneralFileChecksumAccessor(
 	const BEntry& fileEntry, bool skipMissingFile)
 	:
@@ -127,6 +137,25 @@ GeneralFileChecksumAccessor::GetChecksum(BString& checksum) const
 }
 
 
+// #pragma mark - StringChecksumAccessor
+
+
+StringChecksumAccessor::StringChecksumAccessor(const BString& checksum)
+	:
+	fChecksum(checksum)
+{
+}
+
+
+status_t
+StringChecksumAccessor::GetChecksum(BString& _checksum) const
+{
+	_checksum = fChecksum;
+	return B_OK;
+}
+
+
+
 }	// namespace BPrivate
 
 }	// namespace BPackageKit

From cca3f3b7431cf5e22fa612b171d04933197af3a9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 21:18:41 +0200
Subject: [PATCH 0450/1170] package daemon: Fix Volume::_WriteActivationFile()

* Wasn't using the toActivate and toDeactivate parameters, but the
  attributes. Thus failed when called from the
  CommitTransactionHandler.
* Volume::_ChangePackageActivation(): Fix debug output.
---
 src/servers/package/Volume.cpp | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/servers/package/Volume.cpp b/src/servers/package/Volume.cpp
index 9177c911f5..8555628e71 100644
--- a/src/servers/package/Volume.cpp
+++ b/src/servers/package/Volume.cpp
@@ -1580,8 +1580,8 @@ Volume::_WriteActivationFile(const RelativePath& directoryPath,
 {
 	// create the content
 	BString activationFileContent;
-	status_t error = _CreateActivationFileContent(fPackagesToBeActivated,
-		fPackagesToBeDeactivated, activationFileContent);
+	status_t error = _CreateActivationFileContent(toActivate, toDeactivate,
+		activationFileContent);
 	if (error != B_OK)
 		return error;
 
@@ -1629,7 +1629,7 @@ void
 Volume::_ChangePackageActivation(const PackageSet& packagesToActivate,
 	const PackageSet& packagesToDeactivate)
 {
-INFORM("Volume::ProcessPendingPackageActivationChanges(): activating %zu, deactivating %zu packages\n",
+INFORM("Volume::_ChangePackageActivation(): activating %zu, deactivating %zu packages\n",
 packagesToActivate.size(), packagesToDeactivate.size());
 
 	// write the temporary package activation file

From 69a53ac5b488d6562ebf75b98f143000ba70d623 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 21:22:34 +0200
Subject: [PATCH 0451/1170] Add DownloadFileRequest

Downloads a file and optionally checks its checksum.
---
 .../build/os/package/DownloadFileRequest.h    |  1 +
 headers/os/package/DownloadFileRequest.h      | 41 +++++++++
 src/build/libpackage/Jamfile                  |  1 +
 src/kits/package/DownloadFileRequest.cpp      | 83 +++++++++++++++++++
 src/kits/package/Jamfile                      |  1 +
 5 files changed, 127 insertions(+)
 create mode 100644 headers/build/os/package/DownloadFileRequest.h
 create mode 100644 headers/os/package/DownloadFileRequest.h
 create mode 100644 src/kits/package/DownloadFileRequest.cpp

diff --git a/headers/build/os/package/DownloadFileRequest.h b/headers/build/os/package/DownloadFileRequest.h
new file mode 100644
index 0000000000..2dd8722084
--- /dev/null
+++ b/headers/build/os/package/DownloadFileRequest.h
@@ -0,0 +1 @@
+#include <../os/package/DownloadFileRequest.h>
diff --git a/headers/os/package/DownloadFileRequest.h b/headers/os/package/DownloadFileRequest.h
new file mode 100644
index 0000000000..cf42d53f28
--- /dev/null
+++ b/headers/os/package/DownloadFileRequest.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ */
+#ifndef _PACKAGE__DOWNLOAD_FILE_REQUEST_H_
+#define _PACKAGE__DOWNLOAD_FILE_REQUEST_H_
+
+
+#include 
+#include 
+
+#include 
+#include 
+
+
+namespace BPackageKit {
+
+
+class DownloadFileRequest : public BRequest {
+	typedef	BRequest				inherited;
+
+public:
+								DownloadFileRequest(const BContext& context,
+									const BString& fileURL,
+									const BEntry& targetEntry,
+									const BString& checksum = BString());
+	virtual						~DownloadFileRequest();
+
+	virtual	status_t			CreateInitialJobs();
+
+private:
+			BString				fFileURL;
+			BEntry				fTargetEntry;
+			BString				fChecksum;
+};
+
+
+}	// namespace BPackageKit
+
+
+#endif // _PACKAGE__DOWNLOAD_FILE_REQUEST_H_
diff --git a/src/build/libpackage/Jamfile b/src/build/libpackage/Jamfile
index 1d99a84d1b..d3f8dfcfc8 100644
--- a/src/build/libpackage/Jamfile
+++ b/src/build/libpackage/Jamfile
@@ -73,6 +73,7 @@ BuildPlatformSharedLibrary libpackage_build.so
 	BlockBufferCacheNoLock.cpp
 	ChecksumAccessors.cpp
 	Context.cpp
+	DownloadFileRequest.cpp
 	DropRepositoryRequest.cpp
 	FetchFileJob.cpp
 	InstallationLocationInfo.cpp
diff --git a/src/kits/package/DownloadFileRequest.cpp b/src/kits/package/DownloadFileRequest.cpp
new file mode 100644
index 0000000000..81b4064447
--- /dev/null
+++ b/src/kits/package/DownloadFileRequest.cpp
@@ -0,0 +1,83 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+
+#include 
+#include 
+
+
+namespace BPackageKit {
+
+
+using namespace BPrivate;
+
+
+DownloadFileRequest::DownloadFileRequest(const BContext& context,
+	const BString& fileURL, const BEntry& targetEntry, const BString& checksum)
+	:
+	inherited(context),
+	fFileURL(fileURL),
+	fTargetEntry(targetEntry),
+	fChecksum(checksum)
+{
+	if (fInitStatus == B_OK) {
+		if (fFileURL.IsEmpty())
+			fInitStatus = B_BAD_VALUE;
+		else
+			fInitStatus = targetEntry.InitCheck();
+	}
+}
+
+
+DownloadFileRequest::~DownloadFileRequest()
+{
+}
+
+
+status_t
+DownloadFileRequest::CreateInitialJobs()
+{
+	status_t error = InitCheck();
+	if (error != B_OK)
+		return B_NO_INIT;
+
+	// create the download job
+	FetchFileJob* fetchJob = new (std::nothrow) FetchFileJob(fContext,
+		BString("Downloading ") << fFileURL, fFileURL, fTargetEntry);
+	if (fetchJob == NULL)
+		return B_NO_MEMORY;
+
+	if ((error = QueueJob(fetchJob)) != B_OK) {
+		delete fetchJob;
+		return error;
+	}
+
+	// create the checksum validation job
+	if (fChecksum.IsEmpty())
+		return B_OK;
+
+	ValidateChecksumJob* validateJob = new (std::nothrow) ValidateChecksumJob(
+		fContext, BString("Validating checksum for ") << fFileURL,
+		new (std::nothrow) StringChecksumAccessor(fChecksum),
+		new (std::nothrow) GeneralFileChecksumAccessor(fTargetEntry, true));
+
+	if (validateJob == NULL)
+		return B_NO_MEMORY;
+
+	if ((error = QueueJob(validateJob)) != B_OK) {
+		delete validateJob;
+		return error;
+	}
+
+	return B_OK;
+}
+
+
+}	// namespace BPackageKit
diff --git a/src/kits/package/Jamfile b/src/kits/package/Jamfile
index 6df66e5cb2..525947eeca 100644
--- a/src/kits/package/Jamfile
+++ b/src/kits/package/Jamfile
@@ -53,6 +53,7 @@ SharedLibrary libpackage.so
 	ChecksumAccessors.cpp
 	Context.cpp
 	DaemonClient.cpp
+	DownloadFileRequest.cpp
 	DropRepositoryRequest.cpp
 	FetchFileJob.cpp
 	InstallationLocationInfo.cpp

From 6a1430716c8746b3a044bb65fb1849e906ae0453 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 21:24:28 +0200
Subject: [PATCH 0452/1170] BDaemonClient: Add support for creating activation
 transactions

* BActivationTransaction:
  - Remove non-trivial constructor.
  - Remove package list parameters from SetTo().
  - Add AddPackageTo{Dea,A}ctivate().
* BDaemonClient:
  - Add CreateTransaction(). It creates a transaction directory and
    initializes a BActivationTransaction. Packages to de-/activate have
    to be added afterwards.
  - Add BCommitTransactionResult::FullErrorMessage().
---
 .../private/package/ActivationTransaction.h   |  19 ++--
 headers/private/package/DaemonClient.h        |  10 ++
 src/kits/package/ActivationTransaction.cpp    |  51 ++++-----
 src/kits/package/DaemonClient.cpp             | 103 ++++++++++++++++++
 4 files changed, 142 insertions(+), 41 deletions(-)

diff --git a/headers/private/package/ActivationTransaction.h b/headers/private/package/ActivationTransaction.h
index 11b5094325..76e311e887 100644
--- a/headers/private/package/ActivationTransaction.h
+++ b/headers/private/package/ActivationTransaction.h
@@ -20,20 +20,13 @@ namespace BPrivate {
 class BActivationTransaction {
 public:
 								BActivationTransaction();
-								BActivationTransaction(
-									BPackageInstallationLocation location,
-									int64 changeCount,
-									const BString& directoryName,
-									const BStringList& packagesToActivate,
-									const BStringList& packagesToDeactivate);
 								~BActivationTransaction();
 
-			status_t			InitCheck() const;
 			status_t			SetTo(BPackageInstallationLocation location,
 									int64 changeCount,
-									const BString& directoryName,
-									const BStringList& packagesToActivate,
-									const BStringList& packagesToDeactivate);
+									const BString& directoryName);
+
+			status_t			InitCheck() const;
 
 			BPackageInstallationLocation Location() const;
 			void				SetLocation(
@@ -47,12 +40,14 @@ public:
 									const BString& directoryName);
 
 			const BStringList&	PackagesToActivate() const;
-			void				SetPackagesToActivate(
+			bool				SetPackagesToActivate(
 									const BStringList& packages);
+			bool				AddPackageToActivate(const BString& package);
 
 			const BStringList&	PackagesToDeactivate() const;
-			void				SetPackagesToDeactivate(
+			bool				SetPackagesToDeactivate(
 									const BStringList& packages);
+			bool				AddPackageToDeactivate(const BString& package);
 
 private:
 			BPackageInstallationLocation fLocation;
diff --git a/headers/private/package/DaemonClient.h b/headers/private/package/DaemonClient.h
index bcad84ad59..339f04bfa3 100644
--- a/headers/private/package/DaemonClient.h
+++ b/headers/private/package/DaemonClient.h
@@ -16,6 +16,9 @@
 #include 
 
 
+class BDirectory;
+
+
 namespace BPackageKit {
 
 
@@ -44,6 +47,11 @@ public:
 									const BActivationTransaction& transaction,
 									BCommitTransactionResult& _result);
 
+			status_t			CreateTransaction(
+									BPackageInstallationLocation location,
+									BActivationTransaction& _transaction,
+									BDirectory& _transactionDirectory);
+
 private:
 			status_t			_InitMessenger();
 			status_t			_ExtractPackageInfoSet(const BMessage& message,
@@ -81,6 +89,8 @@ public:
 			const BString&		ErrorPackage() const;
 									// may be empty, even on error
 
+			BString				FullErrorMessage() const;
+
 			const BString&		OldStateDirectory() const;
 
 private:
diff --git a/src/kits/package/ActivationTransaction.cpp b/src/kits/package/ActivationTransaction.cpp
index 838b071774..813ecf33b3 100644
--- a/src/kits/package/ActivationTransaction.cpp
+++ b/src/kits/package/ActivationTransaction.cpp
@@ -25,20 +25,6 @@ BActivationTransaction::BActivationTransaction()
 }
 
 
-BActivationTransaction::BActivationTransaction(
-	BPackageInstallationLocation location, int64 changeCount,
-	const BString& directoryName, const BStringList& packagesToActivate,
-	const BStringList& packagesToDeactivate)
-	:
-	fLocation(location),
-	fChangeCount(changeCount),
-	fTransactionDirectoryName(directoryName),
-	fPackagesToActivate(packagesToActivate),
-	fPackagesToDeactivate(packagesToDeactivate)
-{
-}
-
-
 BActivationTransaction::~BActivationTransaction()
 {
 }
@@ -57,27 +43,18 @@ BActivationTransaction::InitCheck() const
 
 status_t
 BActivationTransaction::SetTo(BPackageInstallationLocation location,
-	int64 changeCount, const BString& directoryName,
-	const BStringList& packagesToActivate,
-	const BStringList& packagesToDeactivate)
+	int64 changeCount, const BString& directoryName)
 {
 	if (location < 0 || location >= B_PACKAGE_INSTALLATION_LOCATION_ENUM_COUNT
-		|| directoryName.IsEmpty()
-		|| (packagesToActivate.IsEmpty() && packagesToDeactivate.IsEmpty())) {
+		|| directoryName.IsEmpty()) {
 		return B_BAD_VALUE;
 	}
 
 	fLocation = location;
 	fChangeCount = changeCount;
 	fTransactionDirectoryName = directoryName;
-	fPackagesToActivate = packagesToActivate;
-	fPackagesToDeactivate = packagesToDeactivate;
-
-	if (fPackagesToActivate.CountStrings() != packagesToActivate.CountStrings()
-		|| fPackagesToDeactivate.CountStrings()
-			!= packagesToDeactivate.CountStrings()) {
-		return B_NO_MEMORY;
-	}
+	fPackagesToActivate.MakeEmpty();
+	fPackagesToDeactivate.MakeEmpty();
 
 	return B_OK;
 }
@@ -133,10 +110,18 @@ BActivationTransaction::PackagesToActivate() const
 }
 
 
-void
+bool
 BActivationTransaction::SetPackagesToActivate(const BStringList& packages)
 {
 	fPackagesToActivate = packages;
+	return fPackagesToActivate.CountStrings() == packages.CountStrings();
+}
+
+
+bool
+BActivationTransaction::AddPackageToActivate(const BString& package)
+{
+	return fPackagesToActivate.Add(package);
 }
 
 
@@ -147,10 +132,18 @@ BActivationTransaction::PackagesToDeactivate() const
 }
 
 
-void
+bool
 BActivationTransaction::SetPackagesToDeactivate(const BStringList& packages)
 {
 	fPackagesToDeactivate = packages;
+	return fPackagesToDeactivate.CountStrings() == packages.CountStrings();
+}
+
+
+bool
+BActivationTransaction::AddPackageToDeactivate(const BString& package)
+{
+	return fPackagesToDeactivate.Add(package);
 }
 
 
diff --git a/src/kits/package/DaemonClient.cpp b/src/kits/package/DaemonClient.cpp
index 8d2c1bf310..f3446dcf00 100644
--- a/src/kits/package/DaemonClient.cpp
+++ b/src/kits/package/DaemonClient.cpp
@@ -9,10 +9,15 @@
 
 #include 
 
+#include 
+
+#include 
+#include 
 #include 
 #include 
 
 #include 
+#include 
 
 
 namespace BPackageKit {
@@ -103,6 +108,60 @@ BDaemonClient::CommitTransaction(const BActivationTransaction& transaction,
 }
 
 
+status_t
+BDaemonClient::CreateTransaction(BPackageInstallationLocation location,
+	BActivationTransaction& _transaction, BDirectory& _transactionDirectory)
+{
+	// get an info for the location
+	BInstallationLocationInfo info;
+	status_t error = GetInstallationLocationInfo(location, info);
+	if (error != B_OK)
+		return error;
+
+	// open admin directory
+	entry_ref entryRef;
+	entryRef.device = info.PackagesDirectoryRef().device;
+	entryRef.directory = info.PackagesDirectoryRef().node;
+	error = entryRef.set_name(PACKAGES_DIRECTORY_ADMIN_DIRECTORY);
+	if (error != B_OK)
+		return error;
+	
+	BDirectory adminDirectory;
+	error = adminDirectory.SetTo(&entryRef);
+	if (error != B_OK)
+		return error;
+
+	// create a transaction directory
+	int uniqueId = 1;
+	BString directoryName;
+	for (;; uniqueId++) {
+		directoryName.SetToFormat("transaction-%d", uniqueId);
+		if (directoryName.IsEmpty())
+			return B_NO_MEMORY;
+
+		error = adminDirectory.CreateDirectory(directoryName,
+			&_transactionDirectory);
+		if (error == B_OK)
+			break;
+		if (error != B_FILE_EXISTS)
+			return error;
+	}
+
+	// init the transaction
+	error = _transaction.SetTo(location, info.ChangeCount(), directoryName);
+	if (error != B_OK) {
+		BEntry entry;
+		_transactionDirectory.GetEntry(&entry);
+		_transactionDirectory.Unset();
+		if (entry.InitCheck() == B_OK)
+			entry.Remove();
+		return error;
+	}
+
+	return B_OK;
+}
+
+
 status_t
 BDaemonClient::_InitMessenger()
 {
@@ -273,6 +332,50 @@ BDaemonClient::BCommitTransactionResult::ErrorPackage() const
 }
 
 
+BString
+BDaemonClient::BCommitTransactionResult::FullErrorMessage() const
+{
+	if (fError == 0)
+		return "no error";
+
+	const char* errorString;
+	if (fError > 0) {
+		switch ((BDaemonError)fError) {
+			case B_DAEMON_CHANGE_COUNT_MISMATCH:
+				errorString = "transaction out of date";
+				break;
+			case B_DAEMON_BAD_REQUEST:
+				errorString = "invalid transaction";
+				break;
+			case B_DAEMON_NO_SUCH_PACKAGE:
+				errorString = "no such package";
+				break;
+			case B_DAEMON_PACKAGE_ALREADY_EXISTS:
+				errorString = "package already exists";
+				break;
+			case B_DAEMON_OK:
+			default:
+				errorString = "unknown error";
+				break;
+		}
+	} else
+		errorString = strerror(fError);
+		
+	BString result;
+	if (!fErrorMessage.IsEmpty()) {
+		result = fErrorMessage;
+		result << ": ";
+	}
+
+	result << errorString;
+
+	if (!fErrorPackage.IsEmpty())
+		result << ", package: \"" << fErrorPackage << '"';
+
+	return result;
+}
+
+
 const BString&
 BDaemonClient::BCommitTransactionResult::OldStateDirectory() const
 {

From eee120f9871cf6f4a1251be97a6a0dc3a4d91a87 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 21:31:32 +0200
Subject: [PATCH 0453/1170] pkgman install: Complete basic functionality

Download package files to install from the respective repositories and
use BDaemonClient to perform the package de-/activation. Still missing
is the interactive problem solution support.
---
 src/bin/pkgman/command_install.cpp | 169 ++++++++++++++++++++++++++---
 1 file changed, 154 insertions(+), 15 deletions(-)

diff --git a/src/bin/pkgman/command_install.cpp b/src/bin/pkgman/command_install.cpp
index c62a6ffd1e..743f19e978 100644
--- a/src/bin/pkgman/command_install.cpp
+++ b/src/bin/pkgman/command_install.cpp
@@ -11,8 +11,9 @@
 #include 
 #include 
 #include 
-//#include 
 
+#include 
+#include 
 #include 
 #include 
 #include 
@@ -22,8 +23,12 @@
 #include 
 
 #include 
+#include 
+#include 
 
 #include "Command.h"
+#include "DecisionProvider.h"
+#include "JobStateListener.h"
 #include "pkgman.h"
 #include "RepositoryBuilder.h"
 
@@ -32,6 +37,7 @@
 
 
 using namespace BPackageKit;
+using namespace BPackageKit::BPrivate;
 
 
 static const char* const kShortUsage =
@@ -52,6 +58,28 @@ static const char* const kLongUsage =
 DEFINE_COMMAND(InstallCommand, "install", kShortUsage, kLongUsage)
 
 
+struct Repository : public BSolverRepository {
+	Repository()
+		:
+		BSolverRepository()
+	{
+	}
+
+	status_t Init(BPackageRoster& roster, const char* name)
+	{
+		return roster.GetRepositoryConfig(name, &fConfig);
+	}
+
+	const BRepositoryConfig& Config() const
+	{
+		return fConfig;
+	}
+
+private:
+	BRepositoryConfig	fConfig;
+};
+
+
 int
 InstallCommand::Execute(int argc, const char* const* argv)
 {
@@ -121,16 +149,25 @@ InstallCommand::Execute(int argc, const char* const* argv)
 		.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common")
 		.AddToSolver(solver, !installInHome);
 
+	BObjectList installedRepositories(10);
+	if (!installedRepositories.AddItem(&systemRepository)
+		|| !installedRepositories.AddItem(&commonRepository)) {
+		DIE(B_NO_MEMORY, "failed to add installed repositories to list");
+	}
+
 	BSolverRepository homeRepository;
 	if (installInHome) {
 		commonRepository.SetPriority(-2);
 		RepositoryBuilder(homeRepository, "home")
 			.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_HOME, "home")
 			.AddToSolver(solver, true);
+
+		if (!installedRepositories.AddItem(&homeRepository))
+			DIE(B_NO_MEMORY, "failed to add home repository to list");
 	}
 
 	// other repositories
-	BObjectList otherRepositories(10, true);
+	BObjectList otherRepositories(10, true);
 	BPackageRoster roster;
 	BStringList repositoryNames;
 	error = roster.GetRepositoryNames(repositoryNames);
@@ -139,20 +176,20 @@ InstallCommand::Execute(int argc, const char* const* argv)
 
 	int32 repositoryNameCount = repositoryNames.CountStrings();
 	for (int32 i = 0; i < repositoryNameCount; i++) {
-		const BString& name = repositoryNames.StringAt(i);
-		BRepositoryConfig config;
-		error = roster.GetRepositoryConfig(name, &config);
-		if (error != B_OK) {
-			WARN(error, "failed to get config for repository \"%s\". Skipping.",
-				name.String());
-			continue;
-		}
-
-		BSolverRepository* repository = new(std::nothrow) BSolverRepository;
+		Repository* repository = new(std::nothrow) Repository;
 		if (repository == NULL || !otherRepositories.AddItem(repository))
 			DIE(B_NO_MEMORY, "out of memory");
 
-		RepositoryBuilder(*repository, config)
+		const BString& name = repositoryNames.StringAt(i);
+		error = repository->Init(roster, name);
+		if (error != B_OK) {
+			WARN(error, "failed to get config for repository \"%s\". Skipping.",
+				name.String());
+			otherRepositories.RemoveItem(repository, true);
+			continue;
+		}
+
+		RepositoryBuilder(*repository, repository->Config())
 			.AddToSolver(solver, false);
 	}
 
@@ -205,22 +242,124 @@ exit(1);
 	if (error != B_OK)
 		DIE(error, "failed to compute packages to install");
 
-	printf("transaction:\n");
+	printf("The following changes will be made:\n");
 	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
 			i++) {
 		BSolverPackage* package = element->Package();
+
 		switch (element->Type()) {
 			case BSolverResultElement::B_TYPE_INSTALL:
+				if (installedRepositories.HasItem(package->Repository()))
+					continue;
+
 				printf("  install package %s from repository %s\n",
-					package->VersionedName().String(),
+					package->Info().CanonicalFileName().String(),
 					package->Repository()->Name().String());
 				break;
+
 			case BSolverResultElement::B_TYPE_UNINSTALL:
 				printf("  uninstall package %s\n",
 					package->VersionedName().String());
 				break;
 		}
 	}
+// TODO: Print file/download sizes. Unfortunately our package infos don't
+// contain the file size. Which is probably correct. The file size (and possibly
+// other information) should, however, be provided by the repository cache in
+// some way. Extend BPackageInfo? Create a BPackageFileInfo?
+
+	DecisionProvider decisionProvider;
+	if (!decisionProvider.YesNoDecisionNeeded(BString(), "Continue?", "y", "n",
+			"y")) {
+		return 1;
+	}
+
+	// create an activation transaction
+	BDaemonClient daemonClient;
+	BPackageInstallationLocation location = installInHome
+		? B_PACKAGE_INSTALLATION_LOCATION_HOME
+		: B_PACKAGE_INSTALLATION_LOCATION_COMMON;
+	BActivationTransaction transaction;
+	BDirectory transactionDirectory;
+	error = daemonClient.CreateTransaction(location, transaction,
+		transactionDirectory);
+	if (error != B_OK)
+		DIE(error, "failed to create transaction");
+
+	// download the new packages and prepare the transaction
+	JobStateListener listener;
+	BContext context(decisionProvider, listener);
+
+	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
+			i++) {
+		BSolverPackage* package = element->Package();
+
+		switch (element->Type()) {
+			case BSolverResultElement::B_TYPE_INSTALL:
+			{
+				if (installedRepositories.HasItem(package->Repository()))
+					continue;
+
+				// get package URL and target entry
+				Repository* repository
+					= static_cast(package->Repository());
+				BString url = repository->Config().BaseURL();
+				BString fileName(package->Info().CanonicalFileName());
+				if (fileName.IsEmpty())
+					DIE(B_NO_MEMORY, "out of memory");
+				url << '/' << fileName;
+
+				BEntry entry;
+				error = entry.SetTo(&transactionDirectory, fileName);
+				if (error != B_OK)
+					DIE(error, "failed to create package entry");
+
+				// download the package
+				DownloadFileRequest downloadRequest(context, url, entry,
+					package->Info().Checksum());
+				error = downloadRequest.Process();
+				if (error != B_OK)
+					DIE(error, "failed to download package");
+
+				// add package to transaction
+				if (!transaction.AddPackageToActivate(
+						package->Info().CanonicalFileName())) {
+					DIE(B_NO_MEMORY,
+						"failed to add package to activate to transaction");
+				}
+				break;
+			}
+
+			case BSolverResultElement::B_TYPE_UNINSTALL:
+				// add package to transaction
+				if (!transaction.AddPackageToDeactivate(
+						package->Info().CanonicalFileName())) {
+					DIE(B_NO_MEMORY,
+						"failed to add package to deactivate to transaction");
+				}
+				break;
+		}
+	}
+
+	// commit the transaction
+	BDaemonClient::BCommitTransactionResult transactionResult;
+	error = daemonClient.CommitTransaction(transaction, transactionResult);
+	if (error != B_OK) {
+		fprintf(stderr, "*** failed to commit transaction: %s\n",
+			transactionResult.FullErrorMessage().String());
+		exit(1);
+	}
+
+	printf("Installation done. Old activation state backed up in \"%s\"\n",
+		transactionResult.OldStateDirectory().String());
+
+	printf("Cleaning up ...\n");
+	BEntry transactionDirectoryEntry;
+	if ((error = transactionDirectory.GetEntry(&transactionDirectoryEntry))
+			!= B_OK
+		|| (error = transactionDirectoryEntry.Remove()) != B_OK) {
+		WARN(error, "failed to remove transaction directory");
+	}
 
 	return 0;
 }

From 7c092d4d865eb53029c28fb5b1ddfbbada85899f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 01:44:21 +0200
Subject: [PATCH 0454/1170] Add build profile action update-packages

Equivalent to "jam  && jam @... ",
i.e. it makes sure all hpkgs that are supposed to be in the image are
rebuilt respectively downloaded and copied to the image. It doesn't
remove old packages nor the activation files -- that still has to be
done manually.
---
 build/jam/ImageRules   | 3 +++
 build/jam/MiscRules    | 6 ++++++
 build/jam/PackageRules | 2 ++
 3 files changed, 11 insertions(+)

diff --git a/build/jam/ImageRules b/build/jam/ImageRules
index 2420a1e934..c3cc52893a 100644
--- a/build/jam/ImageRules
+++ b/build/jam/ImageRules
@@ -928,6 +928,9 @@ rule InstallOptionalHaikuImagePackage url : dirTokens : isCDPackage
 	local archiveFile = [ DownloadFile $(package) : $(url) ] ;
 
 	if $(package:S) = .hpkg {
+		if $(HAIKU_UPDATE_ALL_PACKAGES) {
+			HAIKU_INCLUDE_IN_IMAGE on $(archiveFile) = 1 ;
+		}
 		AddFilesToHaikuImage $(dirTokens) : $(archiveFile) ;
 	} else if ( $(isCDPackage) = true || $(isCDPackage) = 1 )
 		&& $(HAIKU_CD_NAME) {
diff --git a/build/jam/MiscRules b/build/jam/MiscRules
index 326f0b90d1..034efeb1e9 100644
--- a/build/jam/MiscRules
+++ b/build/jam/MiscRules
@@ -407,6 +407,12 @@ rule DefineBuildProfile name : type : path {
 			HAIKU_INCLUDE_IN_PACKAGES = 1 ;
 		}
 
+		case "update-packages" : {
+			JAM_TARGETS = $(buildTarget) ;
+			SetUpdateHaikuImageOnly 1 ;
+			HAIKU_UPDATE_ALL_PACKAGES = 1 ;
+		}
+
 		case "mount" : {
 			if $(type) in "install" "cd-image" {
 				Exit "Build action \"mount\" not supported for profile type"
diff --git a/build/jam/PackageRules b/build/jam/PackageRules
index 86e3ed7847..00af4501b2 100644
--- a/build/jam/PackageRules
+++ b/build/jam/PackageRules
@@ -279,6 +279,8 @@ rule HaikuPackage package
 		HAIKU_CONTAINER_UPDATE_ONLY on $(package) = 1 ;
 		HAIKU_CONTAINER_INHERIT_UPDATE_VARIABLE on $(package)
 			= HAIKU_INCLUDE_IN_IMAGE ;
+	} else if $(HAIKU_UPDATE_ALL_PACKAGES) {
+		HAIKU_INCLUDE_IN_IMAGE on $(package) = 1 ;
 	}
 
 	HAIKU_CONTAINER_ALWAYS_CREATE_DIRECTORIES on $(package) = 1 ;

From adc49c411a101e1372d77d95c3473cdbd5dace06 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sat, 20 Apr 2013 21:47:35 +0200
Subject: [PATCH 0455/1170] pkgman install: better out-of-memory error messages

---
 src/bin/pkgman/command_install.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/bin/pkgman/command_install.cpp b/src/bin/pkgman/command_install.cpp
index 743f19e978..0e1c3e0ea2 100644
--- a/src/bin/pkgman/command_install.cpp
+++ b/src/bin/pkgman/command_install.cpp
@@ -178,7 +178,7 @@ InstallCommand::Execute(int argc, const char* const* argv)
 	for (int32 i = 0; i < repositoryNameCount; i++) {
 		Repository* repository = new(std::nothrow) Repository;
 		if (repository == NULL || !otherRepositories.AddItem(repository))
-			DIE(B_NO_MEMORY, "out of memory");
+			DIE(B_NO_MEMORY, "failed to create/add repository object");
 
 		const BString& name = repositoryNames.StringAt(i);
 		error = repository->Init(roster, name);
@@ -306,7 +306,7 @@ exit(1);
 				BString url = repository->Config().BaseURL();
 				BString fileName(package->Info().CanonicalFileName());
 				if (fileName.IsEmpty())
-					DIE(B_NO_MEMORY, "out of memory");
+					DIE(B_NO_MEMORY, "failed to allocate file name");
 				url << '/' << fileName;
 
 				BEntry entry;

From ec41ff587ff27f05dd852cd58a91bcb70043be41 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 00:36:31 +0200
Subject: [PATCH 0456/1170] pkgman install: Refresh repositories first

---
 src/bin/pkgman/command_install.cpp | 29 +++++++++++++++++++++--------
 1 file changed, 21 insertions(+), 8 deletions(-)

diff --git a/src/bin/pkgman/command_install.cpp b/src/bin/pkgman/command_install.cpp
index 0e1c3e0ea2..b89dd0ecf9 100644
--- a/src/bin/pkgman/command_install.cpp
+++ b/src/bin/pkgman/command_install.cpp
@@ -15,6 +15,7 @@
 #include 
 #include 
 #include 
+#include 
 #include 
 #include 
 #include 
@@ -65,8 +66,22 @@ struct Repository : public BSolverRepository {
 	{
 	}
 
-	status_t Init(BPackageRoster& roster, const char* name)
+	status_t Init(BPackageRoster& roster, BContext& context, const char* name)
 	{
+		// get the repository config
+		status_t error = roster.GetRepositoryConfig(name, &fConfig);
+		if (error != B_OK)
+			return error;
+
+		// refresh
+		BRefreshRepositoryRequest refreshRequest(context, fConfig);
+		error = refreshRequest.Process();
+		if (error != B_OK) {
+			WARN(error, "refreshing repository \"%s\" failed", name);
+			return B_OK;
+		}
+
+		// re-get the config
 		return roster.GetRepositoryConfig(name, &fConfig);
 	}
 
@@ -119,8 +134,6 @@ InstallCommand::Execute(int argc, const char* const* argv)
 	int packageCount = argc - optind;
 	const char* const* packages = argv + optind;
 
-// TODO: Refresh repositories.
-
 	// create the solver
 	BSolver* solver;
 	status_t error = BSolver::Create(solver);
@@ -167,6 +180,10 @@ InstallCommand::Execute(int argc, const char* const* argv)
 	}
 
 	// other repositories
+	DecisionProvider decisionProvider;
+	JobStateListener listener;
+	BContext context(decisionProvider, listener);
+
 	BObjectList otherRepositories(10, true);
 	BPackageRoster roster;
 	BStringList repositoryNames;
@@ -181,7 +198,7 @@ InstallCommand::Execute(int argc, const char* const* argv)
 			DIE(B_NO_MEMORY, "failed to create/add repository object");
 
 		const BString& name = repositoryNames.StringAt(i);
-		error = repository->Init(roster, name);
+		error = repository->Init(roster, context, name);
 		if (error != B_OK) {
 			WARN(error, "failed to get config for repository \"%s\". Skipping.",
 				name.String());
@@ -268,7 +285,6 @@ exit(1);
 // other information) should, however, be provided by the repository cache in
 // some way. Extend BPackageInfo? Create a BPackageFileInfo?
 
-	DecisionProvider decisionProvider;
 	if (!decisionProvider.YesNoDecisionNeeded(BString(), "Continue?", "y", "n",
 			"y")) {
 		return 1;
@@ -287,9 +303,6 @@ exit(1);
 		DIE(error, "failed to create transaction");
 
 	// download the new packages and prepare the transaction
-	JobStateListener listener;
-	BContext context(decisionProvider, listener);
-
 	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
 			i++) {
 		BSolverPackage* package = element->Package();

From 8e6c3631a3e6deca3ca008bbce20bf30ec616d63 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 02:46:26 +0200
Subject: [PATCH 0457/1170] BSolver/LibsolvSolver: Add problem solution
 selection support

... and re-solving.
---
 headers/os/package/solver/Solver.h        |   6 +
 src/kits/package/solver/LibsolvSolver.cpp | 137 ++++++++++++++++++----
 src/kits/package/solver/LibsolvSolver.h   |  10 +-
 3 files changed, 129 insertions(+), 24 deletions(-)

diff --git a/headers/os/package/solver/Solver.h b/headers/os/package/solver/Solver.h
index 90c0045281..f72afff27d 100644
--- a/headers/os/package/solver/Solver.h
+++ b/headers/os/package/solver/Solver.h
@@ -17,6 +17,7 @@ class BSolverPackage;
 class BSolverPackageSpecifier;
 class BSolverPackageSpecifierList;
 class BSolverProblem;
+class BSolverProblemSolution;
 class BSolverRepository;
 class BSolverResult;
 
@@ -58,6 +59,11 @@ public:
 	virtual	int32				CountProblems() const = 0;
 	virtual	BSolverProblem*		ProblemAt(int32 index) const = 0;
 
+	virtual	status_t			SelectProblemSolution(
+									BSolverProblem* problem,
+									const BSolverProblemSolution* solution) = 0;
+	virtual	status_t			SolveAgain() = 0;
+
 	virtual	status_t			GetResult(BSolverResult& _result) = 0;
 
 protected:
diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index 460befd544..2f02a2770d 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -118,7 +118,8 @@ struct LibsolvSolver::Problem : public BSolverProblem {
 		const BPackageResolvableExpression& dependency)
 		:
 		BSolverProblem(type, sourcePackage, targetPackage, dependency),
-		fId(id)
+		fId(id),
+		fSelectedSolution(NULL)
 	{
 	}
 
@@ -127,13 +128,24 @@ struct LibsolvSolver::Problem : public BSolverProblem {
 		return fId;
 	}
 
+	const Solution* SelectedSolution() const
+	{
+		return fSelectedSolution;
+	}
+
+	void SetSelectedSolution(const Solution* solution)
+	{
+		fSelectedSolution = solution;
+	}
+
 private:
-	::Id	fId;
+	::Id			fId;
+	const Solution*	fSelectedSolution;
 };
 
 
 struct LibsolvSolver::Solution : public BSolverProblemSolution {
-	Solution(::Id id, Problem* problem)
+	Solution(::Id id, LibsolvSolver::Problem* problem)
 		:
 		BSolverProblemSolution(),
 		fId(id),
@@ -146,9 +158,14 @@ struct LibsolvSolver::Solution : public BSolverProblemSolution {
 		return fId;
 	}
 
+	LibsolvSolver::Problem* Problem() const
+	{
+		return fProblem;
+	}
+
 private:
-	::Id		fId;
-	Problem*	fProblem;
+	::Id					fId;
+	LibsolvSolver::Problem*	fProblem;
 };
 
 
@@ -159,6 +176,7 @@ LibsolvSolver::LibsolvSolver()
 	:
 	fPool(NULL),
 	fSolver(NULL),
+	fJobs(NULL),
 	fRepositoryInfos(10, true),
 	fInstalledRepository(NULL),
 	fSolvablePackages(),
@@ -299,7 +317,9 @@ LibsolvSolver::Install(const BSolverPackageSpecifierList& packages,
 		return error;
 
 	// add the packages to install to the job queue
-	SolvQueue jobs;
+	error = _InitJobQueue();
+	if (error != B_OK)
+		return error;
 
 	int32 packageCount = packages.CountSpecifiers();
 	for (int32 i = 0; i < packageCount; i++) {
@@ -317,7 +337,7 @@ LibsolvSolver::Install(const BSolverPackageSpecifierList& packages,
 					return B_BAD_VALUE;
 				}
 
-				queue_push2(&jobs, SOLVER_SOLVABLE,
+				queue_push2(fJobs, SOLVER_SOLVABLE,
 					solvable - fPool->solvables);
 				break;
 			}
@@ -359,15 +379,15 @@ LibsolvSolver::Install(const BSolverPackageSpecifierList& packages,
 #endif
 
 				for (int j = 0; j < matchingPackages.count; j++)
-					queue_push(&jobs, matchingPackages.elements[j]);
+					queue_push(fJobs, matchingPackages.elements[j]);
 			}
 		}
 	}
 
 	// set jobs' solver mode and solve
-	_SetJobsSolverMode(jobs, SOLVER_INSTALL);
+	_SetJobsSolverMode(*fJobs, SOLVER_INSTALL);
 
-	return _Solve(jobs);
+	return _Solve(false);
 }
 
 
@@ -383,13 +403,56 @@ LibsolvSolver::VerifyInstallation()
 		return error;
 
 	// add the verify job to the job queue
-	SolvQueue jobs;
-	queue_push2(&jobs, SOLVER_SOLVABLE_ALL, 0);
+	error = _InitJobQueue();
+	if (error != B_OK)
+		return error;
+
+	queue_push2(fJobs, SOLVER_SOLVABLE_ALL, 0);
 
 	// set jobs' solver mode and solve
-	_SetJobsSolverMode(jobs, SOLVER_VERIFY);
+	_SetJobsSolverMode(*fJobs, SOLVER_VERIFY);
 
-	return _Solve(jobs);
+	return _Solve(false);
+}
+
+
+status_t
+LibsolvSolver::SelectProblemSolution(BSolverProblem* _problem,
+	const BSolverProblemSolution* _solution)
+{
+	if (_problem == NULL)
+		return B_BAD_VALUE;
+
+	Problem* problem = static_cast(_problem);
+	if (_solution == NULL) {
+		problem->SetSelectedSolution(NULL);
+		return B_OK;
+	}
+
+	const Solution* solution = static_cast(_solution);
+	if (solution->Problem() != problem)
+		return B_BAD_VALUE;
+
+	problem->SetSelectedSolution(solution);
+	return B_OK;
+}
+
+
+status_t
+LibsolvSolver::SolveAgain()
+{
+	if (fSolver == NULL || fJobs == NULL)
+		return B_BAD_VALUE;
+
+	// iterate through all problems and propagate the selected solutions
+	int32 problemCount = fProblems.CountItems();
+	for (int32 i = 0; i < problemCount; i++) {
+		Problem* problem = fProblems.ItemAt(i);
+		if (const Solution* solution = problem->SelectedSolution())
+			solver_take_solution(fSolver, problem->Id(), solution->Id(), fJobs);
+	}
+
+	return _Solve(true);
 }
 
 
@@ -518,6 +581,16 @@ LibsolvSolver::_InitPool()
 }
 
 
+status_t
+LibsolvSolver::_InitJobQueue()
+{
+	_CleanupJobQueue();
+
+	fJobs = new(std::nothrow) SolvQueue;
+	return fJobs != NULL ? B_OK : B_NO_MEMORY;;
+}
+
+
 void
 LibsolvSolver::_Cleanup()
 {
@@ -532,8 +605,8 @@ LibsolvSolver::_Cleanup()
 void
 LibsolvSolver::_CleanupPool()
 {
-	// clean up solver data
-	_CleanupSolver();
+	// clean up jobs and solver data
+	_CleanupJobQueue();
 
 	// clean up our data structures that depend on/refer to libsolv pool data
 	fSolvablePackages.clear();
@@ -551,6 +624,16 @@ LibsolvSolver::_CleanupPool()
 }
 
 
+void
+LibsolvSolver::_CleanupJobQueue()
+{
+	_CleanupSolver();
+
+	delete fJobs;
+	fJobs = NULL;
+}
+
+
 void
 LibsolvSolver::_CleanupSolver()
 {
@@ -1055,16 +1138,24 @@ LibsolvSolver::_GetResolvableExpression(Id id,
 
 
 status_t
-LibsolvSolver::_Solve(Queue& jobs)
+LibsolvSolver::_Solve(bool solveAgain)
 {
-	_CleanupSolver();
+	if (fJobs == NULL)
+		return B_BAD_VALUE;
 
-	// create the solver and solve
-	fSolver = solver_create(fPool);
-	solver_set_flag(fSolver, SOLVER_FLAG_SPLITPROVIDES, 1);
-	solver_set_flag(fSolver, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
+	if (solveAgain) {
+		if (fSolver == NULL)
+			return B_BAD_VALUE;
+	} else {
+		_CleanupSolver();
 
-	int problemCount = solver_solve(fSolver, &jobs);
+		// create the solver and solve
+		fSolver = solver_create(fPool);
+		solver_set_flag(fSolver, SOLVER_FLAG_SPLITPROVIDES, 1);
+		solver_set_flag(fSolver, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
+	}
+
+	int problemCount = solver_solve(fSolver, fJobs);
 
 	// get the problems (if any)
 	fProblems.MakeEmpty();
diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h
index 09c6dbacfc..a4dcdd727d 100644
--- a/src/kits/package/solver/LibsolvSolver.h
+++ b/src/kits/package/solver/LibsolvSolver.h
@@ -48,6 +48,11 @@ public:
 	virtual	int32				CountProblems() const;
 	virtual	BSolverProblem*		ProblemAt(int32 index) const;
 
+	virtual	status_t			SelectProblemSolution(
+									BSolverProblem* problem,
+									const BSolverProblemSolution* solution);
+	virtual	status_t			SolveAgain();
+
 	virtual	status_t			GetResult(BSolverResult& _result);
 
 private:
@@ -64,8 +69,10 @@ private:
 
 private:
 			status_t			_InitPool();
+			status_t			_InitJobQueue();
 			void				_Cleanup();
 			void				_CleanupPool();
+			void				_CleanupJobQueue();
 			void				_CleanupSolver();
 
 			bool				_HaveRepositoriesChanged() const;
@@ -89,12 +96,13 @@ private:
 									BPackageResolvableExpression& _expression)
 									const;
 
-			status_t			_Solve(Queue& jobs);
+			status_t			_Solve(bool solveAgain);
 			void				_SetJobsSolverMode(Queue& jobs, int solverMode);
 
 private:
 			Pool*				fPool;
 			Solver*				fSolver;
+			SolvQueue*			fJobs;
 			RepositoryInfoList	fRepositoryInfos;
 			RepositoryInfo*		fInstalledRepository;
 			SolvableMap			fSolvablePackages;

From 2f028e9a2dc4b33ecac66d8fd491244a02d0f677 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 02:47:51 +0200
Subject: [PATCH 0458/1170] pkgman install: Add problem solution selection
 support

---
 src/bin/pkgman/command_install.cpp | 82 +++++++++++++++++++++++++-----
 1 file changed, 68 insertions(+), 14 deletions(-)

diff --git a/src/bin/pkgman/command_install.cpp b/src/bin/pkgman/command_install.cpp
index b89dd0ecf9..0554cea1b8 100644
--- a/src/bin/pkgman/command_install.cpp
+++ b/src/bin/pkgman/command_install.cpp
@@ -233,24 +233,60 @@ InstallCommand::Execute(int argc, const char* const* argv)
 
 		int32 problemCount = solver->CountProblems();
 		for (int32 i = 0; i < problemCount; i++) {
+			// print problem and possible solutions
 			BSolverProblem* problem = solver->ProblemAt(i);
-			printf("  %" B_PRId32 ": %s\n", i + 1,
+			printf("problem %" B_PRId32 ": %s\n", i + 1,
 				problem->ToString().String());
 
 			int32 solutionCount = problem->CountSolutions();
 			for (int32 k = 0; k < solutionCount; k++) {
 				const BSolverProblemSolution* solution = problem->SolutionAt(k);
-				printf("    solution %" B_PRId32 ":\n", k + 1);
+				printf("  solution %" B_PRId32 ":\n", k + 1);
 				int32 elementCount = solution->CountElements();
 				for (int32 l = 0; l < elementCount; l++) {
 					const BSolverProblemSolutionElement* element
 						= solution->ElementAt(l);
-					printf("      - %s\n", element->ToString().String());
+					printf("    - %s\n", element->ToString().String());
 				}
 			}
+
+			// let the user choose a solution
+			printf("Please select a solution, skip the problem for now or "
+				"quit.\n");
+			for (;;) {
+				if (solutionCount > 1)
+					printf("select [1...%" B_PRId32 "/s/q]: ", solutionCount);
+				else
+					printf("select [1/s/q]: ");
+	
+				char buffer[32];
+				if (fgets(buffer, sizeof(buffer), stdin) == NULL
+					|| strcmp(buffer, "q\n") == 0) {
+					exit(1);
+				}
+
+				if (strcmp(buffer, "s\n") == 0)
+					break;
+
+				char* end;
+				long selected = strtol(buffer, &end, 0);
+				if (end == buffer || *end != '\n' || selected < 1
+					|| selected > solutionCount) {
+					printf("*** invalid input\n");
+					continue;
+				}
+
+				error = solver->SelectProblemSolution(problem,
+					problem->SolutionAt(selected - 1));
+				if (error != B_OK)
+					DIE(error, "failed to set solution");
+				break;
+			}
 		}
-// TODO: Allow the user to select solutions!
-exit(1);
+
+		error = solver->SolveAgain();
+		if (error != B_OK)
+			DIE(error, "failed to compute packages to install");
 	}
 
 	// print result
@@ -259,27 +295,45 @@ exit(1);
 	if (error != B_OK)
 		DIE(error, "failed to compute packages to install");
 
-	printf("The following changes will be made:\n");
+	BObjectList packagesToActivate;
+	BObjectList packagesToDeactivate;
+
 	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
 			i++) {
 		BSolverPackage* package = element->Package();
 
 		switch (element->Type()) {
 			case BSolverResultElement::B_TYPE_INSTALL:
-				if (installedRepositories.HasItem(package->Repository()))
-					continue;
-
-				printf("  install package %s from repository %s\n",
-					package->Info().CanonicalFileName().String(),
-					package->Repository()->Name().String());
+				if (!installedRepositories.HasItem(package->Repository())) {
+					if (!packagesToActivate.AddItem(package))
+						DIE(B_NO_MEMORY, "failed to add package to activate");
+				}
 				break;
 
 			case BSolverResultElement::B_TYPE_UNINSTALL:
-				printf("  uninstall package %s\n",
-					package->VersionedName().String());
+				if (!packagesToDeactivate.AddItem(package))
+					DIE(B_NO_MEMORY, "failed to add package to deactivate");
 				break;
 		}
 	}
+
+	if (packagesToActivate.IsEmpty() && packagesToDeactivate.IsEmpty()) {
+		printf("Nothing to do.\n");
+		exit(0);
+	}
+
+	printf("The following changes will be made:\n");
+	for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i);
+		i++) {
+		printf("  install package %s from repository %s\n",
+			package->Info().CanonicalFileName().String(),
+			package->Repository()->Name().String());
+	}
+
+	for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i);
+		i++) {
+		printf("  uninstall package %s\n", package->VersionedName().String());
+	}
 // TODO: Print file/download sizes. Unfortunately our package infos don't
 // contain the file size. Which is probably correct. The file size (and possibly
 // other information) should, however, be provided by the repository cache in

From 7466fa2d4901461dea3fc89a9229e0e04707124a Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 10:36:19 +0200
Subject: [PATCH 0459/1170] pkgman install: Simplify transaction creation

---
 src/bin/pkgman/command_install.cpp | 78 +++++++++++++-----------------
 1 file changed, 34 insertions(+), 44 deletions(-)

diff --git a/src/bin/pkgman/command_install.cpp b/src/bin/pkgman/command_install.cpp
index 0554cea1b8..1bcbeff777 100644
--- a/src/bin/pkgman/command_install.cpp
+++ b/src/bin/pkgman/command_install.cpp
@@ -357,54 +357,44 @@ InstallCommand::Execute(int argc, const char* const* argv)
 		DIE(error, "failed to create transaction");
 
 	// download the new packages and prepare the transaction
-	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
-			i++) {
-		BSolverPackage* package = element->Package();
+	for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i);
+		i++) {
+		// get package URL and target entry
+		Repository* repository
+			= static_cast(package->Repository());
+		BString url = repository->Config().BaseURL();
+		BString fileName(package->Info().CanonicalFileName());
+		if (fileName.IsEmpty())
+			DIE(B_NO_MEMORY, "failed to allocate file name");
+		url << '/' << fileName;
 
-		switch (element->Type()) {
-			case BSolverResultElement::B_TYPE_INSTALL:
-			{
-				if (installedRepositories.HasItem(package->Repository()))
-					continue;
+		BEntry entry;
+		error = entry.SetTo(&transactionDirectory, fileName);
+		if (error != B_OK)
+			DIE(error, "failed to create package entry");
 
-				// get package URL and target entry
-				Repository* repository
-					= static_cast(package->Repository());
-				BString url = repository->Config().BaseURL();
-				BString fileName(package->Info().CanonicalFileName());
-				if (fileName.IsEmpty())
-					DIE(B_NO_MEMORY, "failed to allocate file name");
-				url << '/' << fileName;
+		// download the package
+		DownloadFileRequest downloadRequest(context, url, entry,
+			package->Info().Checksum());
+		error = downloadRequest.Process();
+		if (error != B_OK)
+			DIE(error, "failed to download package");
 
-				BEntry entry;
-				error = entry.SetTo(&transactionDirectory, fileName);
-				if (error != B_OK)
-					DIE(error, "failed to create package entry");
+		// add package to transaction
+		if (!transaction.AddPackageToActivate(
+				package->Info().CanonicalFileName())) {
+			DIE(B_NO_MEMORY,
+				"failed to add package to activate to transaction");
+		}
+	}
 
-				// download the package
-				DownloadFileRequest downloadRequest(context, url, entry,
-					package->Info().Checksum());
-				error = downloadRequest.Process();
-				if (error != B_OK)
-					DIE(error, "failed to download package");
-
-				// add package to transaction
-				if (!transaction.AddPackageToActivate(
-						package->Info().CanonicalFileName())) {
-					DIE(B_NO_MEMORY,
-						"failed to add package to activate to transaction");
-				}
-				break;
-			}
-
-			case BSolverResultElement::B_TYPE_UNINSTALL:
-				// add package to transaction
-				if (!transaction.AddPackageToDeactivate(
-						package->Info().CanonicalFileName())) {
-					DIE(B_NO_MEMORY,
-						"failed to add package to deactivate to transaction");
-				}
-				break;
+	for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i);
+		i++) {
+		// add package to transaction
+		if (!transaction.AddPackageToDeactivate(
+				package->Info().CanonicalFileName())) {
+			DIE(B_NO_MEMORY,
+				"failed to add package to deactivate to transaction");
 		}
 	}
 

From c128275ede0f0441de54a0f0c8bab9af7ea7460d Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 12:29:41 +0200
Subject: [PATCH 0460/1170] : Fix conflict with
 BPackageKit::BPrivate

... when "using BPackageKit::BPrivate".
---
 headers/os/support/Archivable.h | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/headers/os/support/Archivable.h b/headers/os/support/Archivable.h
index 076a2a8ace..88fe3b8e62 100644
--- a/headers/os/support/Archivable.h
+++ b/headers/os/support/Archivable.h
@@ -21,8 +21,8 @@ namespace Archiving {
 }
 }
 
-using BPrivate::Archiving::BArchiveManager;
-using BPrivate::Archiving::BUnarchiveManager;
+using ::BPrivate::Archiving::BArchiveManager;
+using ::BPrivate::Archiving::BUnarchiveManager;
 
 
 class BArchivable {

From 3ac0de3b1fac18912d6cb7758b502468e3802ee9 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 12:31:29 +0200
Subject: [PATCH 0461/1170] pkgman: Refactoring -> PackageManager

Move common and reusable functionality from "search" and "install" to
new PackageManager class.
---
 src/bin/pkgman/Jamfile             |   1 +
 src/bin/pkgman/PackageManager.cpp  | 396 +++++++++++++++++++++++++++++
 src/bin/pkgman/PackageManager.h    |  94 +++++++
 src/bin/pkgman/command_install.cpp | 339 +-----------------------
 src/bin/pkgman/command_search.cpp  |  75 +-----
 5 files changed, 505 insertions(+), 400 deletions(-)
 create mode 100644 src/bin/pkgman/PackageManager.cpp
 create mode 100644 src/bin/pkgman/PackageManager.h

diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile
index cb8328a9f2..4669d214f2 100644
--- a/src/bin/pkgman/Jamfile
+++ b/src/bin/pkgman/Jamfile
@@ -14,6 +14,7 @@ BinCommand pkgman :
 	DecisionProvider.cpp
 	JobStateListener.cpp
 	PackageInfoErrorListener.cpp
+	PackageManager.cpp
 	pkgman.cpp
 	RepositoryBuilder.cpp
 	:
diff --git a/src/bin/pkgman/PackageManager.cpp b/src/bin/pkgman/PackageManager.cpp
new file mode 100644
index 0000000000..e099995bfc
--- /dev/null
+++ b/src/bin/pkgman/PackageManager.cpp
@@ -0,0 +1,396 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include "PackageManager.h"
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include 
+#include 
+
+#include "pkgman.h"
+#include "RepositoryBuilder.h"
+
+
+using namespace BPackageKit::BPrivate;
+
+
+// #pragma mark - Repository
+
+
+PackageManager::Repository::Repository()
+	:
+	BSolverRepository()
+{
+}
+
+
+status_t
+PackageManager::Repository::Init(BPackageRoster& roster, BContext& context,
+	const char* name)
+{
+	// get the repository config
+	status_t error = roster.GetRepositoryConfig(name, &fConfig);
+	if (error != B_OK)
+		return error;
+
+	// refresh
+	BRefreshRepositoryRequest refreshRequest(context, fConfig);
+	error = refreshRequest.Process();
+	if (error != B_OK) {
+		WARN(error, "refreshing repository \"%s\" failed", name);
+		return B_OK;
+	}
+
+	// re-get the config
+	return roster.GetRepositoryConfig(name, &fConfig);
+}
+
+
+const BRepositoryConfig&
+PackageManager::Repository::Config() const
+{
+	return fConfig;
+}
+
+
+// #pragma mark - Solver
+
+
+PackageManager::PackageManager(BPackageInstallationLocation location,
+	bool addInstalledRepositories, bool addOtherRepositories)
+	:
+	fLocation(location),
+	fSolver(NULL),
+	fSystemRepository(),
+	fCommonRepository(),
+	fHomeRepository(),
+	fInstalledRepositories(10),
+	fOtherRepositories(10, true),
+	fDecisionProvider(),
+	fJobStateListener(),
+	fContext(fDecisionProvider, fJobStateListener)
+{
+	// create the solver
+	status_t error = BSolver::Create(fSolver);
+	if (error != B_OK)
+		DIE(error, "failed to create solver");
+
+	// add installation location repositories
+	if (addInstalledRepositories) {
+		// We add only the repository of our actual installation location as the
+		// "installed" repository. The repositories for the more general
+		// installation locations are added as regular repositories, but with
+		// better priorities than the actual (remote) repositories. This
+		// prevents the solver from showing conflicts when a package in a more
+		// specific installation location overrides a package in a more general
+		// one. Instead any requirement that is already installed in a more
+		// general installation location will turn up as to be installed as
+		// well. But we can easily filter those out.
+		RepositoryBuilder(fSystemRepository, "system")
+			.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, "system")
+			.AddToSolver(fSolver, false);
+		fSystemRepository.SetPriority(-1);
+
+		bool installInHome = location == B_PACKAGE_INSTALLATION_LOCATION_HOME;
+		RepositoryBuilder(fCommonRepository, "common")
+			.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common")
+			.AddToSolver(fSolver, !installInHome);
+	
+		if (!fInstalledRepositories.AddItem(&fSystemRepository)
+			|| !fInstalledRepositories.AddItem(&fCommonRepository)) {
+			DIE(B_NO_MEMORY, "failed to add installed repositories to list");
+		}
+	
+		if (installInHome) {
+			fCommonRepository.SetPriority(-2);
+			RepositoryBuilder(fHomeRepository, "home")
+				.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_HOME, "home")
+				.AddToSolver(fSolver, true);
+	
+			if (!fInstalledRepositories.AddItem(&fHomeRepository))
+				DIE(B_NO_MEMORY, "failed to add home repository to list");
+		}
+	}
+
+	// add other repositories
+	if (addOtherRepositories) {
+		BPackageRoster roster;
+		BStringList repositoryNames;
+		error = roster.GetRepositoryNames(repositoryNames);
+		if (error != B_OK)
+			WARN(error, "failed to get repository names");
+	
+		int32 repositoryNameCount = repositoryNames.CountStrings();
+		for (int32 i = 0; i < repositoryNameCount; i++) {
+			Repository* repository = new(std::nothrow) Repository;
+			if (repository == NULL || !fOtherRepositories.AddItem(repository))
+				DIE(B_NO_MEMORY, "failed to create/add repository object");
+	
+			const BString& name = repositoryNames.StringAt(i);
+			error = repository->Init(roster, fContext, name);
+			if (error != B_OK) {
+				WARN(error,
+					"failed to get config for repository \"%s\". Skipping.",
+					name.String());
+				fOtherRepositories.RemoveItem(repository, true);
+				continue;
+			}
+	
+			RepositoryBuilder(*repository, repository->Config())
+				.AddToSolver(fSolver, false);
+		}
+	}
+}
+
+
+PackageManager::~PackageManager()
+{
+}
+
+
+void
+PackageManager::Install(const char* const* packages, int packageCount)
+{
+	// solve
+	BSolverPackageSpecifierList packagesToInstall;
+	for (int i = 0; i < packageCount; i++) {
+		if (!packagesToInstall.AppendSpecifier(packages[i]))
+			DIE(B_NO_MEMORY, "failed to add specified package");
+	}
+
+	const BSolverPackageSpecifier* unmatchedSpecifier;
+	status_t error = fSolver->Install(packagesToInstall, &unmatchedSpecifier);
+	if (error != B_OK) {
+		if (unmatchedSpecifier != NULL) {
+			DIE(error, "failed to find a match for \"%s\"",
+				unmatchedSpecifier->SelectString().String());
+		} else
+			DIE(error, "failed to compute packages to install");
+	}
+
+	_HandleProblems();
+
+	// install/uninstall packages
+	_AnalyzeResult();
+	_PrintResult();
+	_ApplyPackageChanges();
+}
+
+
+void
+PackageManager::_HandleProblems()
+{
+	while (fSolver->HasProblems()) {
+		printf("Encountered problems:\n");
+
+		int32 problemCount = fSolver->CountProblems();
+		for (int32 i = 0; i < problemCount; i++) {
+			// print problem and possible solutions
+			BSolverProblem* problem = fSolver->ProblemAt(i);
+			printf("problem %" B_PRId32 ": %s\n", i + 1,
+				problem->ToString().String());
+
+			int32 solutionCount = problem->CountSolutions();
+			for (int32 k = 0; k < solutionCount; k++) {
+				const BSolverProblemSolution* solution = problem->SolutionAt(k);
+				printf("  solution %" B_PRId32 ":\n", k + 1);
+				int32 elementCount = solution->CountElements();
+				for (int32 l = 0; l < elementCount; l++) {
+					const BSolverProblemSolutionElement* element
+						= solution->ElementAt(l);
+					printf("    - %s\n", element->ToString().String());
+				}
+			}
+
+			// let the user choose a solution
+			printf("Please select a solution, skip the problem for now or "
+				"quit.\n");
+			for (;;) {
+				if (solutionCount > 1)
+					printf("select [1...%" B_PRId32 "/s/q]: ", solutionCount);
+				else
+					printf("select [1/s/q]: ");
+	
+				char buffer[32];
+				if (fgets(buffer, sizeof(buffer), stdin) == NULL
+					|| strcmp(buffer, "q\n") == 0) {
+					exit(1);
+				}
+
+				if (strcmp(buffer, "s\n") == 0)
+					break;
+
+				char* end;
+				long selected = strtol(buffer, &end, 0);
+				if (end == buffer || *end != '\n' || selected < 1
+					|| selected > solutionCount) {
+					printf("*** invalid input\n");
+					continue;
+				}
+
+				status_t error = fSolver->SelectProblemSolution(problem,
+					problem->SolutionAt(selected - 1));
+				if (error != B_OK)
+					DIE(error, "failed to set solution");
+				break;
+			}
+		}
+
+		status_t error = fSolver->SolveAgain();
+		if (error != B_OK)
+			DIE(error, "failed to compute packages to install");
+	}
+}
+
+
+void
+PackageManager::_AnalyzeResult()
+{
+	BSolverResult result;
+	status_t error = fSolver->GetResult(result);
+	if (error != B_OK)
+		DIE(error, "failed to compute packages to install");
+
+	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
+			i++) {
+		BSolverPackage* package = element->Package();
+
+		switch (element->Type()) {
+			case BSolverResultElement::B_TYPE_INSTALL:
+				if (!fInstalledRepositories.HasItem(package->Repository())) {
+					if (!fPackagesToActivate.AddItem(package))
+						DIE(B_NO_MEMORY, "failed to add package to activate");
+				}
+				break;
+
+			case BSolverResultElement::B_TYPE_UNINSTALL:
+				if (!fPackagesToDeactivate.AddItem(package))
+					DIE(B_NO_MEMORY, "failed to add package to deactivate");
+				break;
+		}
+	}
+
+	if (fPackagesToActivate.IsEmpty() && fPackagesToDeactivate.IsEmpty()) {
+		printf("Nothing to do.\n");
+		exit(0);
+	}
+}
+
+
+void
+PackageManager::_PrintResult()
+{
+	printf("The following changes will be made:\n");
+	for (int32 i = 0; BSolverPackage* package = fPackagesToActivate.ItemAt(i);
+		i++) {
+		printf("  install package %s from repository %s\n",
+			package->Info().CanonicalFileName().String(),
+			package->Repository()->Name().String());
+	}
+
+	for (int32 i = 0; BSolverPackage* package = fPackagesToDeactivate.ItemAt(i);
+		i++) {
+		printf("  uninstall package %s\n", package->VersionedName().String());
+	}
+// TODO: Print file/download sizes. Unfortunately our package infos don't
+// contain the file size. Which is probably correct. The file size (and possibly
+// other information) should, however, be provided by the repository cache in
+// some way. Extend BPackageInfo? Create a BPackageFileInfo?
+
+	if (!fDecisionProvider.YesNoDecisionNeeded(BString(), "Continue?", "y", "n",
+			"y")) {
+		exit(1);
+	}
+}
+
+
+void
+PackageManager::_ApplyPackageChanges()
+{
+	// create an activation transaction
+	BDaemonClient daemonClient;
+	BActivationTransaction transaction;
+	BDirectory transactionDirectory;
+	status_t error = daemonClient.CreateTransaction(fLocation, transaction,
+		transactionDirectory);
+	if (error != B_OK)
+		DIE(error, "failed to create transaction");
+
+	// download the new packages and prepare the transaction
+	for (int32 i = 0; BSolverPackage* package = fPackagesToActivate.ItemAt(i);
+		i++) {
+		// get package URL and target entry
+		Repository* repository
+			= static_cast(package->Repository());
+		BString url = repository->Config().BaseURL();
+		BString fileName(package->Info().CanonicalFileName());
+		if (fileName.IsEmpty())
+			DIE(B_NO_MEMORY, "failed to allocate file name");
+		url << '/' << fileName;
+
+		BEntry entry;
+		error = entry.SetTo(&transactionDirectory, fileName);
+		if (error != B_OK)
+			DIE(error, "failed to create package entry");
+
+		// download the package
+		DownloadFileRequest downloadRequest(fContext, url, entry,
+			package->Info().Checksum());
+		error = downloadRequest.Process();
+		if (error != B_OK)
+			DIE(error, "failed to download package");
+
+		// add package to transaction
+		if (!transaction.AddPackageToActivate(
+				package->Info().CanonicalFileName())) {
+			DIE(B_NO_MEMORY,
+				"failed to add package to activate to transaction");
+		}
+	}
+
+	for (int32 i = 0; BSolverPackage* package = fPackagesToDeactivate.ItemAt(i);
+		i++) {
+		// add package to transaction
+		if (!transaction.AddPackageToDeactivate(
+				package->Info().CanonicalFileName())) {
+			DIE(B_NO_MEMORY,
+				"failed to add package to deactivate to transaction");
+		}
+	}
+
+	// commit the transaction
+	BDaemonClient::BCommitTransactionResult transactionResult;
+	error = daemonClient.CommitTransaction(transaction, transactionResult);
+	if (error != B_OK) {
+		fprintf(stderr, "*** failed to commit transaction: %s\n",
+			transactionResult.FullErrorMessage().String());
+		exit(1);
+	}
+
+	printf("Installation done. Old activation state backed up in \"%s\"\n",
+		transactionResult.OldStateDirectory().String());
+
+	printf("Cleaning up ...\n");
+	BEntry transactionDirectoryEntry;
+	if ((error = transactionDirectory.GetEntry(&transactionDirectoryEntry))
+			!= B_OK
+		|| (error = transactionDirectoryEntry.Remove()) != B_OK) {
+		WARN(error, "failed to remove transaction directory");
+	}
+}
diff --git a/src/bin/pkgman/PackageManager.h b/src/bin/pkgman/PackageManager.h
new file mode 100644
index 0000000000..7a8ebd050c
--- /dev/null
+++ b/src/bin/pkgman/PackageManager.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+#ifndef PACKAGE_MANAGER_H
+#define PACKAGE_MANAGER_H
+
+
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+#include 
+
+#include "DecisionProvider.h"
+#include "JobStateListener.h"
+
+
+using namespace BPackageKit;
+
+
+class PackageManager {
+public:
+			struct Repository;
+			typedef BObjectList RepositoryList;
+
+public:
+								PackageManager(
+									BPackageInstallationLocation location,
+									bool addInstalledRepositories,
+									bool addOtherRepositories);
+								~PackageManager();
+
+			BSolver*			Solver() const
+									{ return fSolver; }
+
+			const BSolverRepository* SystemRepository() const
+									{ return &fSystemRepository; }
+			const BSolverRepository* CommonRepository() const
+									{ return &fCommonRepository; }
+			const BSolverRepository* HomeRepository() const
+									{ return &fHomeRepository; }
+			const BObjectList& InstalledRepositories() const
+									{ return fInstalledRepositories; }
+			const RepositoryList& OtherRepositories() const
+									{ return fOtherRepositories; }
+
+			void				Install(const char* const* packages,
+									int packageCount);
+
+private:
+			typedef BObjectList PackageList;
+
+private:
+			void				_HandleProblems();
+			void				_AnalyzeResult();
+			void				_PrintResult();
+			void				_ApplyPackageChanges();
+
+private:
+			BPackageInstallationLocation fLocation;
+			BSolver*			fSolver;
+			BSolverRepository	fSystemRepository;
+			BSolverRepository	fCommonRepository;
+			BSolverRepository	fHomeRepository;
+			BObjectList fInstalledRepositories;
+			RepositoryList		fOtherRepositories;
+			DecisionProvider	fDecisionProvider;
+			JobStateListener	fJobStateListener;
+			BContext			fContext;
+			PackageList			fPackagesToActivate;
+			PackageList			fPackagesToDeactivate;
+};
+
+
+struct PackageManager::Repository : public BSolverRepository {
+								Repository();
+
+			status_t			Init(BPackageRoster& roster, BContext& context,
+									const char* name);
+
+			const BRepositoryConfig& Config() const;
+
+private:
+			BRepositoryConfig	fConfig;
+};
+
+
+#endif	// PACKAGE_MANAGER_H
diff --git a/src/bin/pkgman/command_install.cpp b/src/bin/pkgman/command_install.cpp
index 1bcbeff777..da9c77ff1a 100644
--- a/src/bin/pkgman/command_install.cpp
+++ b/src/bin/pkgman/command_install.cpp
@@ -7,31 +7,13 @@
  */
 
 
-#include 
 #include 
 #include 
 #include 
 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-#include 
-
-#include 
-#include 
-#include 
-
 #include "Command.h"
-#include "DecisionProvider.h"
-#include "JobStateListener.h"
 #include "pkgman.h"
-#include "RepositoryBuilder.h"
+#include "PackageManager.h"
 
 
 // TODO: internationalization!
@@ -59,42 +41,6 @@ static const char* const kLongUsage =
 DEFINE_COMMAND(InstallCommand, "install", kShortUsage, kLongUsage)
 
 
-struct Repository : public BSolverRepository {
-	Repository()
-		:
-		BSolverRepository()
-	{
-	}
-
-	status_t Init(BPackageRoster& roster, BContext& context, const char* name)
-	{
-		// get the repository config
-		status_t error = roster.GetRepositoryConfig(name, &fConfig);
-		if (error != B_OK)
-			return error;
-
-		// refresh
-		BRefreshRepositoryRequest refreshRequest(context, fConfig);
-		error = refreshRequest.Process();
-		if (error != B_OK) {
-			WARN(error, "refreshing repository \"%s\" failed", name);
-			return B_OK;
-		}
-
-		// re-get the config
-		return roster.GetRepositoryConfig(name, &fConfig);
-	}
-
-	const BRepositoryConfig& Config() const
-	{
-		return fConfig;
-	}
-
-private:
-	BRepositoryConfig	fConfig;
-};
-
-
 int
 InstallCommand::Execute(int argc, const char* const* argv)
 {
@@ -134,289 +80,12 @@ InstallCommand::Execute(int argc, const char* const* argv)
 	int packageCount = argc - optind;
 	const char* const* packages = argv + optind;
 
-	// create the solver
-	BSolver* solver;
-	status_t error = BSolver::Create(solver);
-	if (error != B_OK)
-		DIE(error, "failed to create solver");
-
-	// add repositories
-
-	// We add only the repository of our actual installation location as the
-	// "installed" repository. The repositories for the more general
-	// installation locations are added as regular repositories, but with better
-	// priorities than the actual (remote) repositories. This prevents the solver
-	// from showing conflicts when a package in a more specific installation
-	// location overrides a package in a more general one. Instead any
-	// requirement that is already installed in a more general installation
-	// location will turn up as to be installed as well. But we can easily
-	// filter those out.
-	BSolverRepository systemRepository;
-	RepositoryBuilder(systemRepository, "system")
-		.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, "system")
-		.AddToSolver(solver, false);
-	systemRepository.SetPriority(-1);
-
-	BSolverRepository commonRepository;
-	RepositoryBuilder(commonRepository, "common")
-		.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common")
-		.AddToSolver(solver, !installInHome);
-
-	BObjectList installedRepositories(10);
-	if (!installedRepositories.AddItem(&systemRepository)
-		|| !installedRepositories.AddItem(&commonRepository)) {
-		DIE(B_NO_MEMORY, "failed to add installed repositories to list");
-	}
-
-	BSolverRepository homeRepository;
-	if (installInHome) {
-		commonRepository.SetPriority(-2);
-		RepositoryBuilder(homeRepository, "home")
-			.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_HOME, "home")
-			.AddToSolver(solver, true);
-
-		if (!installedRepositories.AddItem(&homeRepository))
-			DIE(B_NO_MEMORY, "failed to add home repository to list");
-	}
-
-	// other repositories
-	DecisionProvider decisionProvider;
-	JobStateListener listener;
-	BContext context(decisionProvider, listener);
-
-	BObjectList otherRepositories(10, true);
-	BPackageRoster roster;
-	BStringList repositoryNames;
-	error = roster.GetRepositoryNames(repositoryNames);
-	if (error != B_OK)
-		WARN(error, "failed to get repository names");
-
-	int32 repositoryNameCount = repositoryNames.CountStrings();
-	for (int32 i = 0; i < repositoryNameCount; i++) {
-		Repository* repository = new(std::nothrow) Repository;
-		if (repository == NULL || !otherRepositories.AddItem(repository))
-			DIE(B_NO_MEMORY, "failed to create/add repository object");
-
-		const BString& name = repositoryNames.StringAt(i);
-		error = repository->Init(roster, context, name);
-		if (error != B_OK) {
-			WARN(error, "failed to get config for repository \"%s\". Skipping.",
-				name.String());
-			otherRepositories.RemoveItem(repository, true);
-			continue;
-		}
-
-		RepositoryBuilder(*repository, repository->Config())
-			.AddToSolver(solver, false);
-	}
-
-	// solve
-	BSolverPackageSpecifierList packagesToInstall;
-	for (int i = 0; i < packageCount; i++) {
-		if (!packagesToInstall.AppendSpecifier(packages[i]))
-			DIE(B_NO_MEMORY, "failed to add specified package");
-	}
-
-	const BSolverPackageSpecifier* unmatchedSpecifier;
-	error = solver->Install(packagesToInstall, &unmatchedSpecifier);
-	if (error != B_OK) {
-		if (unmatchedSpecifier != NULL) {
-			DIE(error, "failed to find a match for \"%s\"",
-				unmatchedSpecifier->SelectString().String());
-		} else
-			DIE(error, "failed to compute packages to install");
-	}
-
-	// deal with problems
-	while (solver->HasProblems()) {
-		printf("Encountered problems:\n");
-
-		int32 problemCount = solver->CountProblems();
-		for (int32 i = 0; i < problemCount; i++) {
-			// print problem and possible solutions
-			BSolverProblem* problem = solver->ProblemAt(i);
-			printf("problem %" B_PRId32 ": %s\n", i + 1,
-				problem->ToString().String());
-
-			int32 solutionCount = problem->CountSolutions();
-			for (int32 k = 0; k < solutionCount; k++) {
-				const BSolverProblemSolution* solution = problem->SolutionAt(k);
-				printf("  solution %" B_PRId32 ":\n", k + 1);
-				int32 elementCount = solution->CountElements();
-				for (int32 l = 0; l < elementCount; l++) {
-					const BSolverProblemSolutionElement* element
-						= solution->ElementAt(l);
-					printf("    - %s\n", element->ToString().String());
-				}
-			}
-
-			// let the user choose a solution
-			printf("Please select a solution, skip the problem for now or "
-				"quit.\n");
-			for (;;) {
-				if (solutionCount > 1)
-					printf("select [1...%" B_PRId32 "/s/q]: ", solutionCount);
-				else
-					printf("select [1/s/q]: ");
-	
-				char buffer[32];
-				if (fgets(buffer, sizeof(buffer), stdin) == NULL
-					|| strcmp(buffer, "q\n") == 0) {
-					exit(1);
-				}
-
-				if (strcmp(buffer, "s\n") == 0)
-					break;
-
-				char* end;
-				long selected = strtol(buffer, &end, 0);
-				if (end == buffer || *end != '\n' || selected < 1
-					|| selected > solutionCount) {
-					printf("*** invalid input\n");
-					continue;
-				}
-
-				error = solver->SelectProblemSolution(problem,
-					problem->SolutionAt(selected - 1));
-				if (error != B_OK)
-					DIE(error, "failed to set solution");
-				break;
-			}
-		}
-
-		error = solver->SolveAgain();
-		if (error != B_OK)
-			DIE(error, "failed to compute packages to install");
-	}
-
-	// print result
-	BSolverResult result;
-	error = solver->GetResult(result);
-	if (error != B_OK)
-		DIE(error, "failed to compute packages to install");
-
-	BObjectList packagesToActivate;
-	BObjectList packagesToDeactivate;
-
-	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
-			i++) {
-		BSolverPackage* package = element->Package();
-
-		switch (element->Type()) {
-			case BSolverResultElement::B_TYPE_INSTALL:
-				if (!installedRepositories.HasItem(package->Repository())) {
-					if (!packagesToActivate.AddItem(package))
-						DIE(B_NO_MEMORY, "failed to add package to activate");
-				}
-				break;
-
-			case BSolverResultElement::B_TYPE_UNINSTALL:
-				if (!packagesToDeactivate.AddItem(package))
-					DIE(B_NO_MEMORY, "failed to add package to deactivate");
-				break;
-		}
-	}
-
-	if (packagesToActivate.IsEmpty() && packagesToDeactivate.IsEmpty()) {
-		printf("Nothing to do.\n");
-		exit(0);
-	}
-
-	printf("The following changes will be made:\n");
-	for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i);
-		i++) {
-		printf("  install package %s from repository %s\n",
-			package->Info().CanonicalFileName().String(),
-			package->Repository()->Name().String());
-	}
-
-	for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i);
-		i++) {
-		printf("  uninstall package %s\n", package->VersionedName().String());
-	}
-// TODO: Print file/download sizes. Unfortunately our package infos don't
-// contain the file size. Which is probably correct. The file size (and possibly
-// other information) should, however, be provided by the repository cache in
-// some way. Extend BPackageInfo? Create a BPackageFileInfo?
-
-	if (!decisionProvider.YesNoDecisionNeeded(BString(), "Continue?", "y", "n",
-			"y")) {
-		return 1;
-	}
-
-	// create an activation transaction
-	BDaemonClient daemonClient;
+	// perform the installation
 	BPackageInstallationLocation location = installInHome
 		? B_PACKAGE_INSTALLATION_LOCATION_HOME
 		: B_PACKAGE_INSTALLATION_LOCATION_COMMON;
-	BActivationTransaction transaction;
-	BDirectory transactionDirectory;
-	error = daemonClient.CreateTransaction(location, transaction,
-		transactionDirectory);
-	if (error != B_OK)
-		DIE(error, "failed to create transaction");
-
-	// download the new packages and prepare the transaction
-	for (int32 i = 0; BSolverPackage* package = packagesToActivate.ItemAt(i);
-		i++) {
-		// get package URL and target entry
-		Repository* repository
-			= static_cast(package->Repository());
-		BString url = repository->Config().BaseURL();
-		BString fileName(package->Info().CanonicalFileName());
-		if (fileName.IsEmpty())
-			DIE(B_NO_MEMORY, "failed to allocate file name");
-		url << '/' << fileName;
-
-		BEntry entry;
-		error = entry.SetTo(&transactionDirectory, fileName);
-		if (error != B_OK)
-			DIE(error, "failed to create package entry");
-
-		// download the package
-		DownloadFileRequest downloadRequest(context, url, entry,
-			package->Info().Checksum());
-		error = downloadRequest.Process();
-		if (error != B_OK)
-			DIE(error, "failed to download package");
-
-		// add package to transaction
-		if (!transaction.AddPackageToActivate(
-				package->Info().CanonicalFileName())) {
-			DIE(B_NO_MEMORY,
-				"failed to add package to activate to transaction");
-		}
-	}
-
-	for (int32 i = 0; BSolverPackage* package = packagesToDeactivate.ItemAt(i);
-		i++) {
-		// add package to transaction
-		if (!transaction.AddPackageToDeactivate(
-				package->Info().CanonicalFileName())) {
-			DIE(B_NO_MEMORY,
-				"failed to add package to deactivate to transaction");
-		}
-	}
-
-	// commit the transaction
-	BDaemonClient::BCommitTransactionResult transactionResult;
-	error = daemonClient.CommitTransaction(transaction, transactionResult);
-	if (error != B_OK) {
-		fprintf(stderr, "*** failed to commit transaction: %s\n",
-			transactionResult.FullErrorMessage().String());
-		exit(1);
-	}
-
-	printf("Installation done. Old activation state backed up in \"%s\"\n",
-		transactionResult.OldStateDirectory().String());
-
-	printf("Cleaning up ...\n");
-	BEntry transactionDirectoryEntry;
-	if ((error = transactionDirectory.GetEntry(&transactionDirectoryEntry))
-			!= B_OK
-		|| (error = transactionDirectoryEntry.Remove()) != B_OK) {
-		WARN(error, "failed to remove transaction directory");
-	}
+	PackageManager packageManager(location, true, true);
+	packageManager.Install(packages, packageCount);
 
 	return 0;
 }
diff --git a/src/bin/pkgman/command_search.cpp b/src/bin/pkgman/command_search.cpp
index f65db3eefc..9d2a72b6c0 100644
--- a/src/bin/pkgman/command_search.cpp
+++ b/src/bin/pkgman/command_search.cpp
@@ -14,14 +14,13 @@
 #include 
 #include 
 
-#include 
-#include 
+#include 
 
-#include 
+#include 
 
 #include "Command.h"
+#include "PackageManager.h"
 #include "pkgman.h"
-#include "RepositoryBuilder.h"
 
 
 // TODO: internationalization!
@@ -32,9 +31,6 @@
 using namespace BPackageKit;
 
 
-typedef std::map PackagePathMap;
-
-
 static const char* const kShortUsage =
 	"  %command% \n"
 	"    Searches for packages matching .\n";
@@ -113,64 +109,13 @@ SearchCommand::Execute(int argc, const char* const* argv)
 	const char* searchString = argv[optind++];
 
 	// create the solver
-	BSolver* solver;
-	status_t error = BSolver::Create(solver);
-	if (error != B_OK)
-		DIE(error, "failed to create solver");
-
-	// add repositories
-
-	// installed
-	BSolverRepository systemRepository;
-	BSolverRepository commonRepository;
-	BSolverRepository homeRepository;
-	if (!uninstalledOnly) {
-		RepositoryBuilder(systemRepository, "system")
-			.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_SYSTEM, "system")
-			.AddToSolver(solver, false);
-		RepositoryBuilder(commonRepository, "common")
-			.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_COMMON, "common")
-			.AddToSolver(solver, false);
-//		RepositoryBuilder(homeRepository, "home")
-//			.AddPackages(B_PACKAGE_INSTALLATION_LOCATION_HOME, "home")
-//			.AddToSolver(solver, false);
-	}
-
-	// not installed
-	BObjectList uninstalledRepositories(10, true);
-
-	if (!installedOnly) {
-		BPackageRoster roster;
-		BStringList repositoryNames;
-		error = roster.GetRepositoryNames(repositoryNames);
-		if (error != B_OK)
-			WARN(error, "failed to get repository names");
-
-		int32 repositoryNameCount = repositoryNames.CountStrings();
-		for (int32 i = 0; i < repositoryNameCount; i++) {
-			const BString& name = repositoryNames.StringAt(i);
-			BRepositoryConfig config;
-			error = roster.GetRepositoryConfig(name, &config);
-			if (error != B_OK) {
-				WARN(error, "failed to get config for repository \"%s\". "
-					"Skipping.", name.String());
-				continue;
-			}
-
-			BSolverRepository* repository = new(std::nothrow) BSolverRepository;
-			if (repository == NULL
-				|| !uninstalledRepositories.AddItem(repository)) {
-				DIE(B_NO_MEMORY, "out of memory");
-			}
-
-			RepositoryBuilder(*repository, config)
-				.AddToSolver(solver, false);
-		}
-	}
+	PackageManager packageManager(B_PACKAGE_INSTALLATION_LOCATION_COMMON,
+		!uninstalledOnly, !installedOnly);
+// TODO: Use B_PACKAGE_INSTALLATION_LOCATION_HOME once we actually mount it.
 
 	// search
 	BObjectList packages;
-	error = solver->FindPackages(searchString,
+	status_t error = packageManager.Solver()->FindPackages(searchString,
 		BSolver::B_FIND_CASE_INSENSITIVE | BSolver::B_FIND_IN_NAME
 			| BSolver::B_FIND_IN_SUMMARY | BSolver::B_FIND_IN_DESCRIPTION
 			| BSolver::B_FIND_IN_PROVIDES,
@@ -230,11 +175,11 @@ SearchCommand::Execute(int argc, const char* const* argv)
 		BSolverPackage* package = packages.ItemAt(i);
 
 		const char* installed = "";
-		if (package->Repository() == &systemRepository)
+		if (package->Repository() == packageManager.SystemRepository())
 			installed = "system";
-		else if (package->Repository() == &commonRepository)
+		else if (package->Repository() == packageManager.CommonRepository())
 			installed = "common";
-		else if (package->Repository() == &homeRepository)
+		else if (package->Repository() == packageManager.HomeRepository())
 			installed = "home";
 
 		printf("%-*s  %-*s  %-*.*s\n",

From de62d76176c323928d2b97bc667f39850727aa1f Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 12:48:39 +0200
Subject: [PATCH 0462/1170] BSolver/LibsolvSolver: Add Uninstall()

Also fix incorrect check in LibsolvSolver::GetResult().
---
 headers/os/package/solver/Solver.h        |   7 +-
 src/kits/package/solver/LibsolvSolver.cpp | 119 ++++++++++++++++++----
 src/kits/package/solver/LibsolvSolver.h   |  10 +-
 3 files changed, 109 insertions(+), 27 deletions(-)

diff --git a/headers/os/package/solver/Solver.h b/headers/os/package/solver/Solver.h
index f72afff27d..975b008e19 100644
--- a/headers/os/package/solver/Solver.h
+++ b/headers/os/package/solver/Solver.h
@@ -48,8 +48,11 @@ public:
 									BObjectList& _packages) = 0;
 
 	virtual	status_t			Install(
-									const BSolverPackageSpecifierList&
-										packages,
+									const BSolverPackageSpecifierList& packages,
+									const BSolverPackageSpecifier** _unmatched
+										= NULL) = 0;
+	virtual	status_t			Uninstall(
+									const BSolverPackageSpecifierList& packages,
 									const BSolverPackageSpecifier** _unmatched
 										= NULL) = 0;
 	virtual	status_t			VerifyInstallation() = 0;
diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index 2f02a2770d..92c98e081d 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -387,7 +387,82 @@ LibsolvSolver::Install(const BSolverPackageSpecifierList& packages,
 	// set jobs' solver mode and solve
 	_SetJobsSolverMode(*fJobs, SOLVER_INSTALL);
 
-	return _Solve(false);
+	_InitSolver();
+	return _Solve();
+}
+
+
+status_t
+LibsolvSolver::Uninstall(const BSolverPackageSpecifierList& packages,
+	const BSolverPackageSpecifier** _unmatched)
+{
+	if (_unmatched != NULL)
+		*_unmatched = NULL;
+
+	if (fInstalledRepository == NULL || packages.IsEmpty())
+		return B_BAD_VALUE;
+
+	// add repositories to pool
+	status_t error = _AddRepositories();
+	if (error != B_OK)
+		return error;
+
+	// add the packages to uninstall to the job queue
+	error = _InitJobQueue();
+	if (error != B_OK)
+		return error;
+
+	int32 packageCount = packages.CountSpecifiers();
+	for (int32 i = 0; i < packageCount; i++) {
+		const BSolverPackageSpecifier& specifier = *packages.SpecifierAt(i);
+		switch (specifier.Type()) {
+			case BSolverPackageSpecifier::B_UNSPECIFIED:
+				return B_BAD_VALUE;
+
+			case BSolverPackageSpecifier::B_PACKAGE:
+			{
+				BSolverPackage* package = specifier.Package();
+				Solvable* solvable;
+				if (package == NULL
+					|| (solvable = _GetSolvable(package)) == NULL
+					|| package->Repository()
+						!= fInstalledRepository->Repository()) {
+					return B_BAD_VALUE;
+				}
+
+				queue_push2(fJobs, SOLVER_SOLVABLE,
+					solvable - fPool->solvables);
+				break;
+			}
+			
+			case BSolverPackageSpecifier::B_SELECT_STRING:
+			{
+				// find matching packages
+				SolvQueue matchingPackages;
+		
+				int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB
+					| SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL
+					| SELECTION_INSTALLED_ONLY;
+				/*int matchFlags =*/ selection_make(fPool, &matchingPackages,
+					specifier.SelectString().String(), flags);
+				if (matchingPackages.count == 0) {
+					if (_unmatched != NULL)
+						*_unmatched = &specifier;
+					return B_NAME_NOT_FOUND;
+				}
+
+				for (int j = 0; j < matchingPackages.count; j++)
+					queue_push(fJobs, matchingPackages.elements[j]);
+			}
+		}
+	}
+
+	// set jobs' solver mode and solve
+	_SetJobsSolverMode(*fJobs, SOLVER_ERASE);
+
+	_InitSolver();
+	solver_set_flag(fSolver, SOLVER_FLAG_ALLOW_UNINSTALL, 1);
+	return _Solve();
 }
 
 
@@ -412,7 +487,8 @@ LibsolvSolver::VerifyInstallation()
 	// set jobs' solver mode and solve
 	_SetJobsSolverMode(*fJobs, SOLVER_VERIFY);
 
-	return _Solve(false);
+	_InitSolver();
+	return _Solve();
 }
 
 
@@ -452,7 +528,7 @@ LibsolvSolver::SolveAgain()
 			solver_take_solution(fSolver, problem->Id(), solution->Id(), fJobs);
 	}
 
-	return _Solve(true);
+	return _Solve();
 }
 
 
@@ -505,11 +581,11 @@ LibsolvSolver::GetResult(BSolverResult& _result)
 				if (package == NULL)
 					return B_ERROR;
 
-				status_t error = _result.AppendElement(
-					BSolverResultElement(BSolverResultElement::B_TYPE_UNINSTALL,
-						package));
-				if (error != B_OK)
-					return error;
+				if (!_result.AppendElement(
+						BSolverResultElement(
+							BSolverResultElement::B_TYPE_UNINSTALL, package))) {
+					return B_NO_MEMORY;
+				}
 				break;
 			}
 
@@ -591,6 +667,17 @@ LibsolvSolver::_InitJobQueue()
 }
 
 
+void
+LibsolvSolver::_InitSolver()
+{
+	_CleanupSolver();
+
+	fSolver = solver_create(fPool);
+	solver_set_flag(fSolver, SOLVER_FLAG_SPLITPROVIDES, 1);
+	solver_set_flag(fSolver, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
+}
+
+
 void
 LibsolvSolver::_Cleanup()
 {
@@ -1138,23 +1225,11 @@ LibsolvSolver::_GetResolvableExpression(Id id,
 
 
 status_t
-LibsolvSolver::_Solve(bool solveAgain)
+LibsolvSolver::_Solve()
 {
-	if (fJobs == NULL)
+	if (fJobs == NULL || fSolver == NULL)
 		return B_BAD_VALUE;
 
-	if (solveAgain) {
-		if (fSolver == NULL)
-			return B_BAD_VALUE;
-	} else {
-		_CleanupSolver();
-
-		// create the solver and solve
-		fSolver = solver_create(fPool);
-		solver_set_flag(fSolver, SOLVER_FLAG_SPLITPROVIDES, 1);
-		solver_set_flag(fSolver, SOLVER_FLAG_BEST_OBEY_POLICY, 1);
-	}
-
 	int problemCount = solver_solve(fSolver, fJobs);
 
 	// get the problems (if any)
diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h
index a4dcdd727d..348be9e6ec 100644
--- a/src/kits/package/solver/LibsolvSolver.h
+++ b/src/kits/package/solver/LibsolvSolver.h
@@ -39,8 +39,11 @@ public:
 									BObjectList& _packages);
 
 	virtual	status_t			Install(
-									const BSolverPackageSpecifierList&
-										packages,
+									const BSolverPackageSpecifierList& packages,
+									const BSolverPackageSpecifier** _unmatched
+										= NULL);
+	virtual	status_t			Uninstall(
+									const BSolverPackageSpecifierList& packages,
 									const BSolverPackageSpecifier** _unmatched
 										= NULL);
 	virtual	status_t			VerifyInstallation();
@@ -70,6 +73,7 @@ private:
 private:
 			status_t			_InitPool();
 			status_t			_InitJobQueue();
+			void				_InitSolver();
 			void				_Cleanup();
 			void				_CleanupPool();
 			void				_CleanupJobQueue();
@@ -96,7 +100,7 @@ private:
 									BPackageResolvableExpression& _expression)
 									const;
 
-			status_t			_Solve(bool solveAgain);
+			status_t			_Solve();
 			void				_SetJobsSolverMode(Queue& jobs, int solverMode);
 
 private:

From 8ba41d628c0ba3fd9f694562dc8b494fbfc220f7 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 12:50:31 +0200
Subject: [PATCH 0463/1170] pkgman install: Fix typo in usage text

---
 src/bin/pkgman/command_install.cpp | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/bin/pkgman/command_install.cpp b/src/bin/pkgman/command_install.cpp
index da9c77ff1a..a1f49c73d8 100644
--- a/src/bin/pkgman/command_install.cpp
+++ b/src/bin/pkgman/command_install.cpp
@@ -33,7 +33,7 @@ static const char* const kLongUsage =
 	"\n"
 	"Options:\n"
 	"  -H, --home\n"
-	"    Install the packages in the user's home directory. Default is to.\n"
+	"    Install the packages in the user's home directory. Default is to\n"
 	"    install in the common directory.\n"
 	"\n";
 

From df2685d885f3b940bc04b1cf5f39511ce6750ddf Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 12:52:06 +0200
Subject: [PATCH 0464/1170] pkgman: Add "uninstall" command

---
 src/bin/pkgman/Jamfile               |  1 +
 src/bin/pkgman/PackageManager.cpp    | 34 ++++++++++-
 src/bin/pkgman/PackageManager.h      |  2 +
 src/bin/pkgman/command_uninstall.cpp | 91 ++++++++++++++++++++++++++++
 4 files changed, 126 insertions(+), 2 deletions(-)
 create mode 100644 src/bin/pkgman/command_uninstall.cpp

diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile
index 4669d214f2..de3d08c07e 100644
--- a/src/bin/pkgman/Jamfile
+++ b/src/bin/pkgman/Jamfile
@@ -11,6 +11,7 @@ BinCommand pkgman :
 	command_refresh.cpp
 	command_resolve_dependencies.cpp
 	command_search.cpp
+	command_uninstall.cpp
 	DecisionProvider.cpp
 	JobStateListener.cpp
 	PackageInfoErrorListener.cpp
diff --git a/src/bin/pkgman/PackageManager.cpp b/src/bin/pkgman/PackageManager.cpp
index e099995bfc..f587451f32 100644
--- a/src/bin/pkgman/PackageManager.cpp
+++ b/src/bin/pkgman/PackageManager.cpp
@@ -193,6 +193,36 @@ PackageManager::Install(const char* const* packages, int packageCount)
 }
 
 
+void
+PackageManager::Uninstall(const char* const* packages, int packageCount)
+{
+	// solve
+	BSolverPackageSpecifierList packagesToUninstall;
+	for (int i = 0; i < packageCount; i++) {
+		if (!packagesToUninstall.AppendSpecifier(packages[i]))
+			DIE(B_NO_MEMORY, "failed to add specified package");
+	}
+
+	const BSolverPackageSpecifier* unmatchedSpecifier;
+	status_t error = fSolver->Uninstall(packagesToUninstall,
+		&unmatchedSpecifier);
+	if (error != B_OK) {
+		if (unmatchedSpecifier != NULL) {
+			DIE(error, "failed to find a match for \"%s\"",
+				unmatchedSpecifier->SelectString().String());
+		} else
+			DIE(error, "failed to compute packages to uninstall");
+	}
+
+	_HandleProblems();
+
+	// install/uninstall packages
+	_AnalyzeResult();
+	_PrintResult();
+	_ApplyPackageChanges();
+}
+
+
 void
 PackageManager::_HandleProblems()
 {
@@ -254,7 +284,7 @@ PackageManager::_HandleProblems()
 
 		status_t error = fSolver->SolveAgain();
 		if (error != B_OK)
-			DIE(error, "failed to compute packages to install");
+			DIE(error, "failed to recompute packages to un/-install");
 	}
 }
 
@@ -265,7 +295,7 @@ PackageManager::_AnalyzeResult()
 	BSolverResult result;
 	status_t error = fSolver->GetResult(result);
 	if (error != B_OK)
-		DIE(error, "failed to compute packages to install");
+		DIE(error, "failed to compute packages to un/-install");
 
 	for (int32 i = 0; const BSolverResultElement* element = result.ElementAt(i);
 			i++) {
diff --git a/src/bin/pkgman/PackageManager.h b/src/bin/pkgman/PackageManager.h
index 7a8ebd050c..ca9b3a0c7e 100644
--- a/src/bin/pkgman/PackageManager.h
+++ b/src/bin/pkgman/PackageManager.h
@@ -52,6 +52,8 @@ public:
 
 			void				Install(const char* const* packages,
 									int packageCount);
+			void				Uninstall(const char* const* packages,
+									int packageCount);
 
 private:
 			typedef BObjectList PackageList;
diff --git a/src/bin/pkgman/command_uninstall.cpp b/src/bin/pkgman/command_uninstall.cpp
new file mode 100644
index 0000000000..5743603e73
--- /dev/null
+++ b/src/bin/pkgman/command_uninstall.cpp
@@ -0,0 +1,91 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+#include 
+#include 
+
+#include "Command.h"
+#include "pkgman.h"
+#include "PackageManager.h"
+
+
+// TODO: internationalization!
+
+
+using namespace BPackageKit;
+using namespace BPackageKit::BPrivate;
+
+
+static const char* const kShortUsage =
+	"  %command%  ...\n"
+	"    Uninstalls one or more packages.\n";
+
+static const char* const kLongUsage =
+	"Usage: %program% %command%  ...\n"
+	"Uninstalls the specified packages.\n"
+	"\n"
+	"Options:\n"
+	"  -H, --home\n"
+	"    Uninstall the packages from the user's home directory. Default is to\n"
+	"    uninstall from the common directory.\n"
+	"\n";
+
+
+DEFINE_COMMAND(UninstallCommand, "uninstall", kShortUsage, kLongUsage)
+
+
+int
+UninstallCommand::Execute(int argc, const char* const* argv)
+{
+	bool uninstallFromHome = false;
+
+	while (true) {
+		static struct option sLongOptions[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ "home", no_argument, 0, 'H' },
+			{ 0, 0, 0, 0 }
+		};
+
+		opterr = 0; // don't print errors
+		int c = getopt_long(argc, (char**)argv, "hu", sLongOptions, NULL);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'h':
+				PrintUsageAndExit(false);
+				break;
+
+			case 'H':
+				uninstallFromHome = true;
+				break;
+
+			default:
+				PrintUsageAndExit(true);
+				break;
+		}
+	}
+
+	// The remaining arguments are the packages to be uninstalled.
+	if (argc < optind + 1)
+		PrintUsageAndExit(true);
+
+	int packageCount = argc - optind;
+	const char* const* packages = argv + optind;
+
+	// perform the installation
+	BPackageInstallationLocation location = uninstallFromHome
+		? B_PACKAGE_INSTALLATION_LOCATION_HOME
+		: B_PACKAGE_INSTALLATION_LOCATION_COMMON;
+	PackageManager packageManager(location, true, true);
+	packageManager.Uninstall(packages, packageCount);
+
+	return 0;
+}

From 458a86aacb49b152f65b810140295477d49f2f31 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 13:11:53 +0200
Subject: [PATCH 0465/1170] pkgman: Organize commands by category

---
 src/bin/pkgman/Command.cpp                    | 16 +++++++-
 src/bin/pkgman/Command.h                      | 13 ++++--
 src/bin/pkgman/command_add_repo.cpp           |  3 +-
 src/bin/pkgman/command_drop_repo.cpp          |  3 +-
 src/bin/pkgman/command_install.cpp            |  3 +-
 src/bin/pkgman/command_list_repos.cpp         |  3 +-
 src/bin/pkgman/command_refresh.cpp            |  3 +-
 .../pkgman/command_resolve_dependencies.cpp   |  2 +-
 src/bin/pkgman/command_search.cpp             |  3 +-
 src/bin/pkgman/command_uninstall.cpp          |  3 +-
 src/bin/pkgman/pkgman.cpp                     | 40 +++++++++++++++----
 src/bin/pkgman/pkgman.h                       |  7 ++++
 12 files changed, 77 insertions(+), 22 deletions(-)

diff --git a/src/bin/pkgman/Command.cpp b/src/bin/pkgman/Command.cpp
index 31c4b48c8f..b00921bb27 100644
--- a/src/bin/pkgman/Command.cpp
+++ b/src/bin/pkgman/Command.cpp
@@ -23,11 +23,12 @@ compare_commands_by_name(const Command* a, const Command* b)
 
 
 Command::Command(const BString& name, const BString& shortUsage,
-	const BString& longUsage)
+	const BString& longUsage, const BString& category)
 	:
 	fName(name),
 	fShortUsage(shortUsage),
-	fLongUsage(longUsage)
+	fLongUsage(longUsage),
+	fCategory(category)
 {
 	fShortUsage.ReplaceAll("%command%", fName);
 	fLongUsage.ReplaceAll("%command%", fName);
@@ -100,6 +101,17 @@ CommandManager::GetCommands(const char* prefix, CommandList& _commands)
 }
 
 
+void
+CommandManager::GetCommandsForCategory(const char* category,
+	CommandList& _commands)
+{
+	for (int32 i = 0; Command* command = fCommands.ItemAt(i); i++) {
+		if (command->Category() == category)
+			_commands.AddItem(command);
+	}
+}
+
+
 CommandManager::CommandManager()
 	:
 	fCommands(20, true)
diff --git a/src/bin/pkgman/Command.h b/src/bin/pkgman/Command.h
index 4d9c6ccc23..d1a53776f6 100644
--- a/src/bin/pkgman/Command.h
+++ b/src/bin/pkgman/Command.h
@@ -17,14 +17,16 @@ class Command {
 public:
 								Command(const BString& name,
 									const BString& shortUsage,
-									const BString& longUsage);
+									const BString& longUsage,
+									const BString& category);
 	virtual						~Command();
 
 			void				Init(const char* programName);
 
 			const BString&		Name() const		{ return fName; }
 			const BString&		ShortUsage() const	{ return fShortUsage; }
-			const BString&		LongUsage() const	{ return fName; }
+			const BString&		LongUsage() const	{ return fLongUsage; }
+			const BString&		Category() const	{ return fCategory; }
 
 			void				PrintUsage(bool error) const;
 			void				PrintUsageAndExit(bool error) const;
@@ -35,6 +37,7 @@ private:
 			BString				fName;
 			BString				fShortUsage;
 			BString				fLongUsage;
+			BString				fCategory;
 };
 
 
@@ -52,6 +55,8 @@ public:
 									{ return fCommands; }
 			void				GetCommands(const char* prefix,
 									CommandList& _commands);
+			void				GetCommandsForCategory(const char* category,
+									CommandList& _commands);
 
 private:
 								CommandManager();
@@ -70,11 +75,11 @@ struct CommandRegistrar {
 };
 
 
-#define DEFINE_COMMAND(className, name, shortUsage, longUsage)	\
+#define DEFINE_COMMAND(className, name, shortUsage, longUsage, category)	\
 	struct className : Command {								\
 		className()												\
 			:													\
-			Command(name, shortUsage, longUsage)				\
+			Command(name, shortUsage, longUsage, category)		\
 		{														\
 		}														\
 																\
diff --git a/src/bin/pkgman/command_add_repo.cpp b/src/bin/pkgman/command_add_repo.cpp
index 798ae6a780..6605f3900b 100644
--- a/src/bin/pkgman/command_add_repo.cpp
+++ b/src/bin/pkgman/command_add_repo.cpp
@@ -38,7 +38,8 @@ static const char* const kLongUsage =
 	"\n";
 
 
-DEFINE_COMMAND(AddRepoCommand, "add-repo", kShortUsage, kLongUsage)
+DEFINE_COMMAND(AddRepoCommand, "add-repo", kShortUsage, kLongUsage,
+	kCommandCategoryRepositories)
 
 
 int
diff --git a/src/bin/pkgman/command_drop_repo.cpp b/src/bin/pkgman/command_drop_repo.cpp
index 0703fb1011..9c4988a8bf 100644
--- a/src/bin/pkgman/command_drop_repo.cpp
+++ b/src/bin/pkgman/command_drop_repo.cpp
@@ -36,7 +36,8 @@ static const char* const kLongUsage =
 	"\n";
 
 
-DEFINE_COMMAND(DropRepoCommand, "drop-repo", kShortUsage, kLongUsage)
+DEFINE_COMMAND(DropRepoCommand, "drop-repo", kShortUsage, kLongUsage,
+	kCommandCategoryRepositories)
 
 
 int
diff --git a/src/bin/pkgman/command_install.cpp b/src/bin/pkgman/command_install.cpp
index a1f49c73d8..b0e3134856 100644
--- a/src/bin/pkgman/command_install.cpp
+++ b/src/bin/pkgman/command_install.cpp
@@ -38,7 +38,8 @@ static const char* const kLongUsage =
 	"\n";
 
 
-DEFINE_COMMAND(InstallCommand, "install", kShortUsage, kLongUsage)
+DEFINE_COMMAND(InstallCommand, "install", kShortUsage, kLongUsage,
+	kCommandCategoryPackages)
 
 
 int
diff --git a/src/bin/pkgman/command_list_repos.cpp b/src/bin/pkgman/command_list_repos.cpp
index e0465121ac..b4e5ac3891 100644
--- a/src/bin/pkgman/command_list_repos.cpp
+++ b/src/bin/pkgman/command_list_repos.cpp
@@ -42,7 +42,8 @@ static const char* const kLongUsage =
 	"\n";
 
 
-DEFINE_COMMAND(ListReposCommand, "list-repos", kShortUsage, kLongUsage)
+DEFINE_COMMAND(ListReposCommand, "list-repos", kShortUsage, kLongUsage,
+	kCommandCategoryRepositories)
 
 
 int
diff --git a/src/bin/pkgman/command_refresh.cpp b/src/bin/pkgman/command_refresh.cpp
index 4eddeae2a0..20fbb13639 100644
--- a/src/bin/pkgman/command_refresh.cpp
+++ b/src/bin/pkgman/command_refresh.cpp
@@ -37,7 +37,8 @@ static const char* const kLongUsage =
 	"\n";
 
 
-DEFINE_COMMAND(RefreshCommand, "refresh", kShortUsage, kLongUsage)
+DEFINE_COMMAND(RefreshCommand, "refresh", kShortUsage, kLongUsage,
+	kCommandCategoryRepositories)
 
 
 int
diff --git a/src/bin/pkgman/command_resolve_dependencies.cpp b/src/bin/pkgman/command_resolve_dependencies.cpp
index 575719a570..f9b425696a 100644
--- a/src/bin/pkgman/command_resolve_dependencies.cpp
+++ b/src/bin/pkgman/command_resolve_dependencies.cpp
@@ -55,7 +55,7 @@ static const char* const kLongUsage =
 
 
 DEFINE_COMMAND(ResolveDependenciesCommand, "resolve-dependencies", kShortUsage,
-	kLongUsage)
+	kLongUsage, kCommandCategoryOther)
 
 
 static void
diff --git a/src/bin/pkgman/command_search.cpp b/src/bin/pkgman/command_search.cpp
index 9d2a72b6c0..2dc9d4a82a 100644
--- a/src/bin/pkgman/command_search.cpp
+++ b/src/bin/pkgman/command_search.cpp
@@ -47,7 +47,8 @@ static const char* const kLongUsage =
 	"\n";
 
 
-DEFINE_COMMAND(SearchCommand, "search", kShortUsage, kLongUsage)
+DEFINE_COMMAND(SearchCommand, "search", kShortUsage, kLongUsage,
+	kCommandCategoryPackages)
 
 
 static int
diff --git a/src/bin/pkgman/command_uninstall.cpp b/src/bin/pkgman/command_uninstall.cpp
index 5743603e73..0aa4305a43 100644
--- a/src/bin/pkgman/command_uninstall.cpp
+++ b/src/bin/pkgman/command_uninstall.cpp
@@ -38,7 +38,8 @@ static const char* const kLongUsage =
 	"\n";
 
 
-DEFINE_COMMAND(UninstallCommand, "uninstall", kShortUsage, kLongUsage)
+DEFINE_COMMAND(UninstallCommand, "uninstall", kShortUsage, kLongUsage,
+	kCommandCategoryPackages)
 
 
 int
diff --git a/src/bin/pkgman/pkgman.cpp b/src/bin/pkgman/pkgman.cpp
index eddf6fbbf3..d0843ae328 100644
--- a/src/bin/pkgman/pkgman.cpp
+++ b/src/bin/pkgman/pkgman.cpp
@@ -18,27 +18,51 @@ extern const char* __progname;
 const char* kProgramName = __progname;
 
 
+const BString kCommandCategoryPackages("packages");
+const BString kCommandCategoryRepositories("repositories");
+const BString kCommandCategoryOther("other");
+
+
 static const char* const kUsage =
 	"Usage: %s  \n"
-	"Manages packages and package repository.\n"
+	"Manages packages and package repositories.\n"
 	"\n"
-	"Commands:\n"
+	"Package management commands:\n"
+	"%s"
+	"Repository management commands:\n"
+	"%s"
+	"Other commands:\n"
 	"%s"
 	"Common Options:\n"
-	"  -h, --help   - Print this usage info.\n"
+	"  -h, --help   - Print usage info.\n"
 ;
 
 
+static BString
+get_commands_usage_for_category(const char* category)
+{
+	BString commandsUsage;
+	CommandList commands;
+	CommandManager::Default()->GetCommandsForCategory(category, commands);
+	for (int32 i = 0; Command* command = commands.ItemAt(i); i++)
+		commandsUsage << command->ShortUsage() << '\n';
+	return commandsUsage;
+}
+
+
 void
 print_usage_and_exit(bool error)
 {
-	BString commandsUsage;
-	const CommandList& commands = CommandManager::Default()->Commands();
-	for (int32 i = 0; Command* command = commands.ItemAt(i); i++)
-		commandsUsage << command->ShortUsage() << '\n';
+	BString packageCommandsUsage
+		= get_commands_usage_for_category(kCommandCategoryPackages);
+	BString repositoryCommandsUsage
+		= get_commands_usage_for_category(kCommandCategoryRepositories);
+	BString otherCommandsUsage
+		= get_commands_usage_for_category(kCommandCategoryOther);
 
     fprintf(error ? stderr : stdout, kUsage, kProgramName,
-    	commandsUsage.String());
+    	packageCommandsUsage.String(), repositoryCommandsUsage.String(),
+    	otherCommandsUsage.String());
 
     exit(error ? 1 : 0);
 }
diff --git a/src/bin/pkgman/pkgman.h b/src/bin/pkgman/pkgman.h
index eb308853c0..c061fd9d39 100644
--- a/src/bin/pkgman/pkgman.h
+++ b/src/bin/pkgman/pkgman.h
@@ -10,6 +10,8 @@
 #include 
 #include 
 
+#include 
+
 
 extern const char* kProgramName;
 
@@ -36,4 +38,9 @@ do {																\
 void	print_usage_and_exit(bool error);
 
 
+extern const BString kCommandCategoryPackages;
+extern const BString kCommandCategoryRepositories;
+extern const BString kCommandCategoryOther;
+
+
 #endif	// PKGMAN_H

From 212c636f4181a2b3a05fbfaa45e016b6c2e3aaa6 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 13:55:38 +0200
Subject: [PATCH 0466/1170] BSolver/LibsolvSolver: Add Update()

---
 headers/os/package/solver/Solver.h        |   5 +
 src/kits/package/solver/LibsolvSolver.cpp | 242 ++++++++++++----------
 src/kits/package/solver/LibsolvSolver.h   |  12 +-
 3 files changed, 144 insertions(+), 115 deletions(-)

diff --git a/headers/os/package/solver/Solver.h b/headers/os/package/solver/Solver.h
index 975b008e19..ce1ae93283 100644
--- a/headers/os/package/solver/Solver.h
+++ b/headers/os/package/solver/Solver.h
@@ -55,6 +55,11 @@ public:
 									const BSolverPackageSpecifierList& packages,
 									const BSolverPackageSpecifier** _unmatched
 										= NULL) = 0;
+	virtual	status_t			Update(
+									const BSolverPackageSpecifierList& packages,
+									bool installNotYetInstalled,
+									const BSolverPackageSpecifier** _unmatched
+										= NULL) = 0;
 	virtual	status_t			VerifyInstallation() = 0;
 
 			bool				HasProblems() const
diff --git a/src/kits/package/solver/LibsolvSolver.cpp b/src/kits/package/solver/LibsolvSolver.cpp
index 92c98e081d..399ac6c62f 100644
--- a/src/kits/package/solver/LibsolvSolver.cpp
+++ b/src/kits/package/solver/LibsolvSolver.cpp
@@ -321,71 +321,12 @@ LibsolvSolver::Install(const BSolverPackageSpecifierList& packages,
 	if (error != B_OK)
 		return error;
 
-	int32 packageCount = packages.CountSpecifiers();
-	for (int32 i = 0; i < packageCount; i++) {
-		const BSolverPackageSpecifier& specifier = *packages.SpecifierAt(i);
-		switch (specifier.Type()) {
-			case BSolverPackageSpecifier::B_UNSPECIFIED:
-				return B_BAD_VALUE;
-
-			case BSolverPackageSpecifier::B_PACKAGE:
-			{
-				BSolverPackage* package = specifier.Package();
-				Solvable* solvable;
-				if (package == NULL
-					|| (solvable = _GetSolvable(package)) == NULL) {
-					return B_BAD_VALUE;
-				}
-
-				queue_push2(fJobs, SOLVER_SOLVABLE,
-					solvable - fPool->solvables);
-				break;
-			}
-			
-			case BSolverPackageSpecifier::B_SELECT_STRING:
-			{
-				// find matching packages
-				SolvQueue matchingPackages;
-		
-				int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB
-					| SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL;
-				/*int matchFlags =*/ selection_make(fPool, &matchingPackages,
-					specifier.SelectString().String(), flags);
-				if (matchingPackages.count == 0) {
-					if (_unmatched != NULL)
-						*_unmatched = &specifier;
-					return B_NAME_NOT_FOUND;
-				}
-// TODO: We might want to add support for restricting to certain repositories.
-#if 0		
-				// restrict to the matching repository
-				if (BSolverRepository* repository = specifier.Repository()) {
-					RepositoryInfo* repositoryInfo
-						= _GetRepositoryInfo(repository);
-					if (repositoryInfo == NULL)
-						return B_BAD_VALUE;
-
-					SolvQueue repoFilter;
-					queue_push2(&repoFilter,
-						SOLVER_SOLVABLE_REPO
-							/* | SOLVER_SETREPO | SOLVER_SETVENDOR*/,
-						repositoryInfo->SolvRepo()->repoid);
-
-					selection_filter(fPool, &matchingPackages, &repoFilter);
-
-					if (matchingPackages.count == 0)
-						return B_NAME_NOT_FOUND;
-				}
-#endif
-
-				for (int j = 0; j < matchingPackages.count; j++)
-					queue_push(fJobs, matchingPackages.elements[j]);
-			}
-		}
-	}
+	error = _AddSpecifiedPackages(packages, _unmatched, 0);
+	if (error != B_OK)
+		return error;
 
 	// set jobs' solver mode and solve
-	_SetJobsSolverMode(*fJobs, SOLVER_INSTALL);
+	_SetJobsSolverMode(SOLVER_INSTALL);
 
 	_InitSolver();
 	return _Solve();
@@ -412,56 +353,61 @@ LibsolvSolver::Uninstall(const BSolverPackageSpecifierList& packages,
 	if (error != B_OK)
 		return error;
 
-	int32 packageCount = packages.CountSpecifiers();
-	for (int32 i = 0; i < packageCount; i++) {
-		const BSolverPackageSpecifier& specifier = *packages.SpecifierAt(i);
-		switch (specifier.Type()) {
-			case BSolverPackageSpecifier::B_UNSPECIFIED:
-				return B_BAD_VALUE;
+	error = _AddSpecifiedPackages(packages, _unmatched,
+		SELECTION_INSTALLED_ONLY);
+	if (error != B_OK)
+		return error;
 
-			case BSolverPackageSpecifier::B_PACKAGE:
-			{
-				BSolverPackage* package = specifier.Package();
-				Solvable* solvable;
-				if (package == NULL
-					|| (solvable = _GetSolvable(package)) == NULL
-					|| package->Repository()
-						!= fInstalledRepository->Repository()) {
-					return B_BAD_VALUE;
-				}
+	// set jobs' solver mode and solve
+	_SetJobsSolverMode(SOLVER_ERASE);
 
-				queue_push2(fJobs, SOLVER_SOLVABLE,
-					solvable - fPool->solvables);
-				break;
-			}
-			
-			case BSolverPackageSpecifier::B_SELECT_STRING:
-			{
-				// find matching packages
-				SolvQueue matchingPackages;
-		
-				int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB
-					| SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL
-					| SELECTION_INSTALLED_ONLY;
-				/*int matchFlags =*/ selection_make(fPool, &matchingPackages,
-					specifier.SelectString().String(), flags);
-				if (matchingPackages.count == 0) {
-					if (_unmatched != NULL)
-						*_unmatched = &specifier;
-					return B_NAME_NOT_FOUND;
-				}
+	_InitSolver();
+	solver_set_flag(fSolver, SOLVER_FLAG_ALLOW_UNINSTALL, 1);
+	return _Solve();
+}
 
-				for (int j = 0; j < matchingPackages.count; j++)
-					queue_push(fJobs, matchingPackages.elements[j]);
+
+status_t
+LibsolvSolver::Update(const BSolverPackageSpecifierList& packages,
+	bool installNotYetInstalled, const BSolverPackageSpecifier** _unmatched)
+{
+	if (_unmatched != NULL)
+		*_unmatched = NULL;
+
+	// add repositories to pool
+	status_t error = _AddRepositories();
+	if (error != B_OK)
+		return error;
+
+	// add the packages to update to the job queue -- if none are specified,
+	// update all
+	error = _InitJobQueue();
+	if (error != B_OK)
+		return error;
+
+	if (packages.IsEmpty()) {
+		queue_push2(fJobs, SOLVER_SOLVABLE_ALL, 0);
+	} else {
+		error = _AddSpecifiedPackages(packages, _unmatched, 0);
+		if (error != B_OK)
+			return error;
+	}
+
+	// set jobs' solver mode and solve
+	_SetJobsSolverMode(SOLVER_UPDATE);
+
+	if (installNotYetInstalled) {
+		for (int i = 0; i < fJobs->count; i += 2) {
+			// change solver mode to SOLVER_INSTALL for empty update jobs
+			if (pool_isemptyupdatejob(fPool, fJobs->elements[i],
+					fJobs->elements[i + 1])) {
+				fJobs->elements[i] &= ~SOLVER_JOBMASK;
+				fJobs->elements[i] |= SOLVER_INSTALL;
 			}
 		}
 	}
 
-	// set jobs' solver mode and solve
-	_SetJobsSolverMode(*fJobs, SOLVER_ERASE);
-
 	_InitSolver();
-	solver_set_flag(fSolver, SOLVER_FLAG_ALLOW_UNINSTALL, 1);
 	return _Solve();
 }
 
@@ -485,7 +431,7 @@ LibsolvSolver::VerifyInstallation()
 	queue_push2(fJobs, SOLVER_SOLVABLE_ALL, 0);
 
 	// set jobs' solver mode and solve
-	_SetJobsSolverMode(*fJobs, SOLVER_VERIFY);
+	_SetJobsSolverMode(SOLVER_VERIFY);
 
 	_InitSolver();
 	return _Solve();
@@ -836,6 +782,79 @@ LibsolvSolver::_GetSolvable(BSolverPackage* package) const
 }
 
 
+status_t
+LibsolvSolver::_AddSpecifiedPackages(
+	const BSolverPackageSpecifierList& packages,
+	const BSolverPackageSpecifier** _unmatched, int additionalFlags)
+{
+	int32 packageCount = packages.CountSpecifiers();
+	for (int32 i = 0; i < packageCount; i++) {
+		const BSolverPackageSpecifier& specifier = *packages.SpecifierAt(i);
+		switch (specifier.Type()) {
+			case BSolverPackageSpecifier::B_UNSPECIFIED:
+				return B_BAD_VALUE;
+
+			case BSolverPackageSpecifier::B_PACKAGE:
+			{
+				BSolverPackage* package = specifier.Package();
+				Solvable* solvable;
+				if (package == NULL
+					|| (solvable = _GetSolvable(package)) == NULL) {
+					return B_BAD_VALUE;
+				}
+
+				queue_push2(fJobs, SOLVER_SOLVABLE,
+					solvable - fPool->solvables);
+				break;
+			}
+			
+			case BSolverPackageSpecifier::B_SELECT_STRING:
+			{
+				// find matching packages
+				SolvQueue matchingPackages;
+		
+				int flags = SELECTION_NAME | SELECTION_PROVIDES | SELECTION_GLOB
+					| SELECTION_CANON | SELECTION_DOTARCH | SELECTION_REL
+					| additionalFlags;
+				/*int matchFlags =*/ selection_make(fPool, &matchingPackages,
+					specifier.SelectString().String(), flags);
+				if (matchingPackages.count == 0) {
+					if (_unmatched != NULL)
+						*_unmatched = &specifier;
+					return B_NAME_NOT_FOUND;
+				}
+// TODO: We might want to add support for restricting to certain repositories.
+#if 0		
+				// restrict to the matching repository
+				if (BSolverRepository* repository = specifier.Repository()) {
+					RepositoryInfo* repositoryInfo
+						= _GetRepositoryInfo(repository);
+					if (repositoryInfo == NULL)
+						return B_BAD_VALUE;
+
+					SolvQueue repoFilter;
+					queue_push2(&repoFilter,
+						SOLVER_SOLVABLE_REPO
+							/* | SOLVER_SETREPO | SOLVER_SETVENDOR*/,
+						repositoryInfo->SolvRepo()->repoid);
+
+					selection_filter(fPool, &matchingPackages, &repoFilter);
+
+					if (matchingPackages.count == 0)
+						return B_NAME_NOT_FOUND;
+				}
+#endif
+
+				for (int j = 0; j < matchingPackages.count; j++)
+					queue_push(fJobs, matchingPackages.elements[j]);
+			}
+		}
+	}
+
+	return B_OK;
+}
+
+
 status_t
 LibsolvSolver::_AddProblem(Id problemId)
 {
@@ -1246,13 +1265,8 @@ LibsolvSolver::_Solve()
 
 
 void
-LibsolvSolver::_SetJobsSolverMode(Queue& jobs, int solverMode)
+LibsolvSolver::_SetJobsSolverMode(int solverMode)
 {
-	for (int i = 0; i < jobs.count; i += 2) {
-		jobs.elements[i] |= solverMode;
-//		if (cleandeps)
-//			jobs.elements[i] |= SOLVER_CLEANDEPS;
-//		if (forcebest)
-//			jobs.elements[i] |= SOLVER_FORCEBEST;
-	}
+	for (int i = 0; i < fJobs->count; i += 2)
+		fJobs->elements[i] |= solverMode;
 }
diff --git a/src/kits/package/solver/LibsolvSolver.h b/src/kits/package/solver/LibsolvSolver.h
index 348be9e6ec..2f61739bec 100644
--- a/src/kits/package/solver/LibsolvSolver.h
+++ b/src/kits/package/solver/LibsolvSolver.h
@@ -46,6 +46,11 @@ public:
 									const BSolverPackageSpecifierList& packages,
 									const BSolverPackageSpecifier** _unmatched
 										= NULL);
+	virtual	status_t			Update(
+									const BSolverPackageSpecifierList& packages,
+									bool installNotYetInstalled,
+									const BSolverPackageSpecifier** _unmatched
+										= NULL);
 	virtual	status_t			VerifyInstallation();
 
 	virtual	int32				CountProblems() const;
@@ -87,6 +92,11 @@ private:
 			BSolverPackage*		_GetPackage(Id solvableId) const;
 			Solvable*			_GetSolvable(BSolverPackage* package) const;
 
+			status_t			_AddSpecifiedPackages(
+									const BSolverPackageSpecifierList& packages,
+									const BSolverPackageSpecifier** _unmatched,
+									int additionalFlags);
+
 			status_t			_AddProblem(Id problemId);
 			status_t			_AddSolution(Problem* problem, Id solutionId);
 			status_t			_AddSolutionElement(Solution* solution,
@@ -101,7 +111,7 @@ private:
 									const;
 
 			status_t			_Solve();
-			void				_SetJobsSolverMode(Queue& jobs, int solverMode);
+			void				_SetJobsSolverMode(int solverMode);
 
 private:
 			Pool*				fPool;

From a5999f6ff7fbadb4f8cc94f5e4283dacbf231a59 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Sun, 21 Apr 2013 13:56:21 +0200
Subject: [PATCH 0467/1170] pkgman: Add "update" command

---
 src/bin/pkgman/Jamfile            |  1 +
 src/bin/pkgman/PackageManager.cpp | 30 +++++++++++
 src/bin/pkgman/PackageManager.h   |  2 +
 src/bin/pkgman/command_update.cpp | 90 +++++++++++++++++++++++++++++++
 4 files changed, 123 insertions(+)
 create mode 100644 src/bin/pkgman/command_update.cpp

diff --git a/src/bin/pkgman/Jamfile b/src/bin/pkgman/Jamfile
index de3d08c07e..e57ee9a370 100644
--- a/src/bin/pkgman/Jamfile
+++ b/src/bin/pkgman/Jamfile
@@ -8,6 +8,7 @@ BinCommand pkgman :
 	command_drop_repo.cpp
 	command_install.cpp
 	command_list_repos.cpp
+	command_update.cpp
 	command_refresh.cpp
 	command_resolve_dependencies.cpp
 	command_search.cpp
diff --git a/src/bin/pkgman/PackageManager.cpp b/src/bin/pkgman/PackageManager.cpp
index f587451f32..833d6ce56d 100644
--- a/src/bin/pkgman/PackageManager.cpp
+++ b/src/bin/pkgman/PackageManager.cpp
@@ -223,6 +223,36 @@ PackageManager::Uninstall(const char* const* packages, int packageCount)
 }
 
 
+void
+PackageManager::Update(const char* const* packages, int packageCount)
+{
+	// solve
+	BSolverPackageSpecifierList packagesToUpdate;
+	for (int i = 0; i < packageCount; i++) {
+		if (!packagesToUpdate.AppendSpecifier(packages[i]))
+			DIE(B_NO_MEMORY, "failed to add specified package");
+	}
+
+	const BSolverPackageSpecifier* unmatchedSpecifier;
+	status_t error = fSolver->Update(packagesToUpdate, true,
+		&unmatchedSpecifier);
+	if (error != B_OK) {
+		if (unmatchedSpecifier != NULL) {
+			DIE(error, "failed to find a match for \"%s\"",
+				unmatchedSpecifier->SelectString().String());
+		} else
+			DIE(error, "failed to compute packages to update");
+	}
+
+	_HandleProblems();
+
+	// install/uninstall packages
+	_AnalyzeResult();
+	_PrintResult();
+	_ApplyPackageChanges();
+}
+
+
 void
 PackageManager::_HandleProblems()
 {
diff --git a/src/bin/pkgman/PackageManager.h b/src/bin/pkgman/PackageManager.h
index ca9b3a0c7e..c212fb314b 100644
--- a/src/bin/pkgman/PackageManager.h
+++ b/src/bin/pkgman/PackageManager.h
@@ -54,6 +54,8 @@ public:
 									int packageCount);
 			void				Uninstall(const char* const* packages,
 									int packageCount);
+			void				Update(const char* const* packages,
+									int packageCount);
 
 private:
 			typedef BObjectList PackageList;
diff --git a/src/bin/pkgman/command_update.cpp b/src/bin/pkgman/command_update.cpp
new file mode 100644
index 0000000000..91d6a5b04a
--- /dev/null
+++ b/src/bin/pkgman/command_update.cpp
@@ -0,0 +1,90 @@
+/*
+ * Copyright 2013, Haiku, Inc. All Rights Reserved.
+ * Distributed under the terms of the MIT License.
+ *
+ * Authors:
+ *		Ingo Weinhold 
+ */
+
+
+#include 
+#include 
+#include 
+
+#include "Command.h"
+#include "pkgman.h"
+#include "PackageManager.h"
+
+
+// TODO: internationalization!
+
+
+using namespace BPackageKit;
+using namespace BPackageKit::BPrivate;
+
+
+static const char* const kShortUsage =
+	"  %command% [  ... ]\n"
+	"    Updates the specified or all packages.\n";
+
+static const char* const kLongUsage =
+	"Usage: %program% %command% [  ... ]\n"
+	"Updates the specified packages. If no packages are given, all packages\n"
+	"in the installation location are updated.\n"
+	"\n"
+	"Options:\n"
+	"  -H, --home\n"
+	"    Update the packages in the user's home directory. Default is to\n"
+	"    update in the common directory.\n"
+	"\n";
+
+
+DEFINE_COMMAND(UpdateCommand, "update", kShortUsage, kLongUsage,
+	kCommandCategoryPackages)
+
+
+int
+UpdateCommand::Execute(int argc, const char* const* argv)
+{
+	bool installInHome = false;
+
+	while (true) {
+		static struct option sLongOptions[] = {
+			{ "help", no_argument, 0, 'h' },
+			{ "home", no_argument, 0, 'H' },
+			{ 0, 0, 0, 0 }
+		};
+
+		opterr = 0; // don't print errors
+		int c = getopt_long(argc, (char**)argv, "hu", sLongOptions, NULL);
+		if (c == -1)
+			break;
+
+		switch (c) {
+			case 'h':
+				PrintUsageAndExit(false);
+				break;
+
+			case 'H':
+				installInHome = true;
+				break;
+
+			default:
+				PrintUsageAndExit(true);
+				break;
+		}
+	}
+
+	// The remaining arguments, if any, are the packages to be installed.
+	int packageCount = argc - optind;
+	const char* const* packages = argv + optind;
+
+	// perform the update
+	BPackageInstallationLocation location = installInHome
+		? B_PACKAGE_INSTALLATION_LOCATION_HOME
+		: B_PACKAGE_INSTALLATION_LOCATION_COMMON;
+	PackageManager packageManager(location, true, true);
+	packageManager.Update(packages, packageCount);
+
+	return 0;
+}

From 5c01289f68d67772de21aa97655f420a0044b50e Mon Sep 17 00:00:00 2001
From: Oliver Tappe 
Date: Sun, 21 Apr 2013 23:22:19 +0200
Subject: [PATCH 0468/1170] Adjust configure script to changed compiler version

---
 configure | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/configure b/configure
index 33ea08fa7b..76af9f2983 100755
--- a/configure
+++ b/configure
@@ -311,7 +311,7 @@ HOST_GCC_OBJCOPY=`gcc -print-prog-name=objcopy`
 SFDISK_BINARY=sfdisk
 HOST_SFDISK=$SFDISK_BINARY
 
-haikuRequiredLegacyGCCVersion="2.95.3-110711"
+haikuRequiredLegacyGCCVersion="2.95.3-haiku-130421"
 export haikuRequiredLegacyGCCVersion
 	# version of legacy gcc required to build haiku
 

From 4b303759d29f2ec2aa8ffb04c239bc071b4b3c7a Mon Sep 17 00:00:00 2001
From: Oliver Tappe 
Date: Mon, 22 Apr 2013 00:50:01 +0200
Subject: [PATCH 0469/1170] Update prerequired packages with current versions.

---
 build/jam/OptionalPackages | 14 +++++++-------
 1 file changed, 7 insertions(+), 7 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 2034927962..a9c6cbd73d 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -467,16 +467,16 @@ if [ IsOptionalHaikuImagePackageAdded Development ] && $(TARGET_ARCH) = x86 {
 			: : true ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/autoconf-2.68-4-x86_gcc2.hpkg
+			$(hpkgBaseURL)/autoconf-2.69-3-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/automake-1.11.1-4-x86_gcc2.hpkg
+			$(hpkgBaseURL)/automake-1.13.1-3-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
 			$(hpkgBaseURL)/libtool-2.4-4-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/texinfo-4.13a-2-x86_gcc2.hpkg
+			$(hpkgBaseURL)/texinfo-4.13a-4-x86_gcc2.hpkg
 			: common packages ;
 	}
 }
@@ -488,10 +488,10 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 	# gcc and binutils
 	if $(HAIKU_GCC_VERSION[1]) = 2 {
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/binutils-2.17_110711-2-x86_gcc2.hpkg
+			$(hpkgBaseURL)/binutils-2.17_130421-1-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/gcc-2.95.3_110711-5-x86_gcc2.hpkg
+			$(hpkgBaseURL)/gcc-2.95.3_130421-1-x86_gcc2.hpkg
 			: common packages ;
 
 		# TODO: remove this when we have a mechanism to switch gcc via PATH
@@ -521,13 +521,13 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 			$(baseURL)/make-3.82-r1a3-x86-gcc4-2011-05-23.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/bison-2.4.3-2-x86_gcc2.hpkg
+			$(hpkgBaseURL)/bison-2.4.3-4-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
 			$(hpkgBaseURL)/m4-1.4.16-4-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/flex-2.5.35-2-x86_gcc2.hpkg
+			$(hpkgBaseURL)/flex-2.5.35-4-x86_gcc2.hpkg
 			: common packages ;
 		InstallOptionalHaikuImagePackage
 			$(hpkgBaseURL)/jam-2.5-1-x86_gcc2.hpkg

From 86b3c7a4168ea52eb05587f83b6985b1ee9249af Mon Sep 17 00:00:00 2001
From: Oliver Tappe 
Date: Mon, 22 Apr 2013 00:56:02 +0200
Subject: [PATCH 0470/1170] Drop symlink common/develop/tools/current

* drop the symlink itself (system development tools are now symlinked
  from /boot/common/bin directly)
* remove that symlink from PATH
---
 build/jam/OptionalPackages        | 5 -----
 data/system/boot/SetupEnvironment | 8 ++------
 src/bin/bash/config-top.h         | 3 +--
 3 files changed, 3 insertions(+), 13 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index a9c6cbd73d..3d697c7b35 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -493,11 +493,6 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ]
 		InstallOptionalHaikuImagePackage
 			$(hpkgBaseURL)/gcc-2.95.3_130421-1-x86_gcc2.hpkg
 			: common packages ;
-
-		# TODO: remove this when we have a mechanism to switch gcc via PATH
-		AddSymlinkToHaikuImage common settings develop tools
-			: /boot/common/develop/tools/gcc-2.95.3-110711
-			: current ;
 	}
 
 	if $(HAIKU_GCC_VERSION[1]) = 4 {
diff --git a/data/system/boot/SetupEnvironment b/data/system/boot/SetupEnvironment
index ad0a1584a6..08198c1775 100644
--- a/data/system/boot/SetupEnvironment
+++ b/data/system/boot/SetupEnvironment
@@ -8,9 +8,6 @@ export LC_CTYPE="en_US.UTF-8"
 
 BUILDHOME=/boot/system/develop
 
-#TODO: fix this or drop it!
-BETOOLS="/boot/common/settings/develop/tools/current/bin"
-
 case `uname -m` in
 BePC|Intel|unknown)
 	BE_HOST_CPU=x86
@@ -29,7 +26,6 @@ BH=$BUILDHOME/headers
 BEINCLUDES="$BH;$BH/be;$BH/posix;$BH/glibc;$BH/cpp;$BH/be/app;$BH/be/device;$BH/be/interface;$BH/be/locale;$BH/be/media;$BH/be/midi;$BH/be/midi2;$BH/be/net;$BH/be/kernel;$BH/be/storage;$BH/be/support;$BH/be/game;$BH/be/opengl;$BH/be/drivers;$BH/gnu;$BH/be/mail;$BH/be/translation;$BH/be/devel;$BH/be/add-ons/graphics;$BH/be/be_apps/Deskbar;$BH/be/be_apps/NetPositive;$BH/be/be_apps/Tracker"
 
 export BUILDHOME
-export BETOOLS
 export BELIBRARIES
 export BEINCLUDES
 export BE_HOST_CPU
@@ -44,11 +40,11 @@ export BE_DEFAULT_CPLUS_FLAGS=""
 
 if [ "$SAFEMODE" != "yes" ]
 then
-	export PATH=.:$HOME/config/non-packaged/bin:$HOME/config/bin:/boot/common/non-packaged/bin:/boot/common/bin:/bin:/boot/apps:/boot/preferences:/boot/system/apps:/boot/system/preferences:$BETOOLS
+	export PATH=.:$HOME/config/non-packaged/bin:$HOME/config/bin:/boot/common/non-packaged/bin:/boot/common/bin:/bin:/boot/apps:/boot/preferences:/boot/system/apps:/boot/system/preferences
 	export LIBRARY_PATH="%A/lib:$HOME/config/non-packaged/lib:$HOME/config/lib:/boot/common/non-packaged/lib:/boot/common/lib:/boot/system/lib"
 	export ADDON_PATH="%A/add-ons:$HOME/config/non-packaged/add-ons:$HOME/config/add-ons:/boot/common/non-packaged/add-ons:/boot/common/add-ons:/boot/system/add-ons"
 else
-	export PATH=.:/bin:/boot/apps:/boot/system/apps:/boot/system/preferences:$BETOOLS
+	export PATH=.:/bin:/boot/apps:/boot/system/apps:/boot/system/preferences
 	export LIBRARY_PATH="%A/lib:/boot/system/lib"
 	export ADDON_PATH="%A/add-ons:/boot/system/add-ons"
 fi
diff --git a/src/bin/bash/config-top.h b/src/bin/bash/config-top.h
index 9b7d17e905..66c4676c73 100644
--- a/src/bin/bash/config-top.h
+++ b/src/bin/bash/config-top.h
@@ -56,8 +56,7 @@
 #define DEFAULT_PATH_VALUE \
   ".:/boot/home/config/bin:/bin:/boot/apps:/boot/preferences" \
   ":/boot/system/apps" \
-  ":/boot/system/preferences" \
-  ":/boot/common/settings/develop/tools/current/bin"
+  ":/boot/system/preferences" 
 #endif
 
 /* The value for PATH when invoking `command -p'.  This is only used when

From 083234daa2c6473bc11c03a46e8a8a5d73ca9000 Mon Sep 17 00:00:00 2001
From: Oliver Tappe 
Date: Mon, 22 Apr 2013 01:00:36 +0200
Subject: [PATCH 0471/1170] Drop legacy scripts 'cc' and 'c++'

* no longer put compiler wrappers onto image
* removed corresponding environment variables
---
 build/jam/HaikuPackages           | 4 ++--
 data/system/boot/SetupEnvironment | 8 --------
 2 files changed, 2 insertions(+), 10 deletions(-)

diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages
index 896cdcd288..cae0a186b8 100644
--- a/build/jam/HaikuPackages
+++ b/build/jam/HaikuPackages
@@ -401,8 +401,8 @@ AddFilesToPackage $(developDirTokens) lib : libposix_error_mapper.a ;
 
 # ABI independent stuff
 
-# scripts: cc and c++ wrapper, freetype-config, setgcc
-local scripts = cc c++ freetype-config setgcc ;
+# scripts: freetype-config, setgcc
+local scripts = freetype-config setgcc ;
 SEARCH on $(scripts) = [ FDirName $(HAIKU_TOP) data bin ] ;
 AddFilesToPackage bin : $(scripts) ;
 
diff --git a/data/system/boot/SetupEnvironment b/data/system/boot/SetupEnvironment
index 08198c1775..b4da8e6bd0 100644
--- a/data/system/boot/SetupEnvironment
+++ b/data/system/boot/SetupEnvironment
@@ -30,14 +30,6 @@ export BELIBRARIES
 export BEINCLUDES
 export BE_HOST_CPU
 
-# for the "cc" and "ld" shell scripts
-
-export BE_C_COMPILER=gcc
-export BE_CPLUS_COMPILER="g++"
-export BE_LINKER=ld
-export BE_DEFAULT_C_FLAGS=""
-export BE_DEFAULT_CPLUS_FLAGS=""
-
 if [ "$SAFEMODE" != "yes" ]
 then
 	export PATH=.:$HOME/config/non-packaged/bin:$HOME/config/bin:/boot/common/non-packaged/bin:/boot/common/bin:/bin:/boot/apps:/boot/preferences:/boot/system/apps:/boot/system/preferences

From 5be84d5f004d43bc5f245d6fa19b1327c8ee0fbe Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 22 Apr 2013 13:50:44 +0200
Subject: [PATCH 0472/1170] Update yasm package

---
 build/jam/OptionalPackages | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 3d697c7b35..e1809736ec 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -1608,7 +1608,7 @@ if [ IsOptionalHaikuImagePackageAdded Yasm ] {
 			$(baseURL)/yasm-1.1.0-r1a3-x86-gcc4-2011-05-24.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			$(hpkgBaseURL)/yasm-1.1.0-1-x86_gcc2.hpkg
+			$(hpkgBaseURL)/yasm-1.2.0-2-x86_gcc2.hpkg
 			: common packages ;
 	}
 }

From 237127fbe4071abea20f3e5005f5a1e549f12788 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 22 Apr 2013 18:05:40 +0200
Subject: [PATCH 0473/1170] Fix _user_entry_ref_to_path() in chroot

* Add "bool kernel" parameter to vfs_entry_ref_to_path(), so it can be
  specified for which I/O context the entry ref shall be translated.
* _user_entry_ref_to_path(): Use the calling team's I/O context instead
  of the kernel's. Fixes the bug that in a chroot the syscall would
  return a path for outside the chroot.
---
 headers/private/kernel/vfs.h                              | 2 +-
 src/add-ons/kernel/file_systems/packagefs/Volume.cpp      | 2 +-
 src/system/kernel/device_manager/legacy_drivers.cpp       | 2 +-
 .../kernel/disk_device_manager/KDiskDeviceManager.cpp     | 4 ++--
 src/system/kernel/fs/vfs.cpp                              | 8 ++++----
 src/system/kernel/module.cpp                              | 4 ++--
 src/tools/fs_shell/vfs.cpp                                | 4 ++--
 7 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/headers/private/kernel/vfs.h b/headers/private/kernel/vfs.h
index cdde48d47c..ed9bb66d51 100644
--- a/headers/private/kernel/vfs.h
+++ b/headers/private/kernel/vfs.h
@@ -119,7 +119,7 @@ status_t	vfs_stat_node_ref(dev_t device, ino_t inode, struct stat *stat);
 status_t	vfs_get_vnode_name(struct vnode *vnode, char *name,
 				size_t nameSize);
 status_t	vfs_entry_ref_to_path(dev_t device, ino_t inode, const char *leaf,
-				char *path, size_t pathLength);
+				bool kernel, char *path, size_t pathLength);
 status_t	vfs_get_cwd(dev_t *_mountID, ino_t *_vnodeID);
 void		vfs_unlock_vnode_if_locked(struct file_descriptor *descriptor);
 status_t	vfs_unmount(dev_t mountID, uint32 flags);
diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
index 426d851f3d..8fdc491b01 100644
--- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
+++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp
@@ -162,7 +162,7 @@ struct Volume::PackagesDirectory {
 			RETURN_ERROR(normalizedPath.InitCheck());
 
 		char* normalizedPathBuffer = normalizedPath.LockBuffer();
-		error = vfs_entry_ref_to_path(fDeviceID, fNodeID, NULL,
+		error = vfs_entry_ref_to_path(fDeviceID, fNodeID, NULL, true,
 			normalizedPathBuffer, normalizedPath.BufferSize());
 		if (error != B_OK)
 			RETURN_ERROR(error);
diff --git a/src/system/kernel/device_manager/legacy_drivers.cpp b/src/system/kernel/device_manager/legacy_drivers.cpp
index 0738a21555..dc7362f3cc 100644
--- a/src/system/kernel/device_manager/legacy_drivers.cpp
+++ b/src/system/kernel/device_manager/legacy_drivers.cpp
@@ -1086,7 +1086,7 @@ DirectoryWatcher::EventOccurred(NotificationService& service,
 
 	KPath path(B_PATH_NAME_LENGTH + 1);
 	if (path.InitCheck() != B_OK || vfs_entry_ref_to_path(device, directory,
-			name, path.LockBuffer(), path.BufferSize()) != B_OK)
+			name, true, path.LockBuffer(), path.BufferSize()) != B_OK)
 		return;
 
 	path.UnlockBuffer();
diff --git a/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp b/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp
index 3916f1ae24..b77aaa061f 100644
--- a/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp
+++ b/src/system/kernel/disk_device_manager/KDiskDeviceManager.cpp
@@ -201,8 +201,8 @@ public:
 			KPath path(B_PATH_NAME_LENGTH + 1);
 			if (path.InitCheck() != B_OK
 				|| vfs_entry_ref_to_path(event->device, event->directory,
-						event->name, path.LockBuffer(),
-				path.BufferSize()) != B_OK) {
+					event->name, true, path.LockBuffer(),
+					path.BufferSize()) != B_OK) {
 				delete event;
 				return B_ERROR;
 			}
diff --git a/src/system/kernel/fs/vfs.cpp b/src/system/kernel/fs/vfs.cpp
index cf2eb6dc96..0106ff708e 100644
--- a/src/system/kernel/fs/vfs.cpp
+++ b/src/system/kernel/fs/vfs.cpp
@@ -4664,7 +4664,7 @@ vfs_get_vnode_name(struct vnode* vnode, char* name, size_t nameSize)
 
 status_t
 vfs_entry_ref_to_path(dev_t device, ino_t inode, const char* leaf,
-	char* path, size_t pathLength)
+	bool kernel, char* path, size_t pathLength)
 {
 	struct vnode* vnode;
 	status_t status;
@@ -4677,7 +4677,7 @@ vfs_entry_ref_to_path(dev_t device, ino_t inode, const char* leaf,
 	if (leaf && (strcmp(leaf, ".") == 0 || strcmp(leaf, "..") == 0)) {
 		// special cases "." and "..": we can directly get the vnode of the
 		// referenced directory
-		status = entry_ref_to_vnode(device, inode, leaf, false, true, &vnode);
+		status = entry_ref_to_vnode(device, inode, leaf, false, kernel, &vnode);
 		leaf = NULL;
 	} else
 		status = get_vnode(device, inode, &vnode, true, false);
@@ -4685,7 +4685,7 @@ vfs_entry_ref_to_path(dev_t device, ino_t inode, const char* leaf,
 		return status;
 
 	// get the directory path
-	status = dir_vnode_to_path(vnode, path, pathLength, true);
+	status = dir_vnode_to_path(vnode, path, pathLength, kernel);
 	put_vnode(vnode);
 		// we don't need the vnode anymore
 	if (status != B_OK)
@@ -8708,7 +8708,7 @@ _user_entry_ref_to_path(dev_t device, ino_t inode, const char* leaf,
 	}
 
 	status_t status = vfs_entry_ref_to_path(device, inode, leaf,
-		path.LockBuffer(), path.BufferSize());
+		false, path.LockBuffer(), path.BufferSize());
 	if (status != B_OK)
 		return status;
 
diff --git a/src/system/kernel/module.cpp b/src/system/kernel/module.cpp
index 7a02d10af2..a0ed7fd90c 100644
--- a/src/system/kernel/module.cpp
+++ b/src/system/kernel/module.cpp
@@ -1412,7 +1412,7 @@ ModuleNotificationService::_AddModuleNode(dev_t device, ino_t node, int fd,
 	KPath path;
 	status = path.InitCheck();
 	if (status == B_OK) {
-		status = vfs_entry_ref_to_path(device, directory, name,
+		status = vfs_entry_ref_to_path(device, directory, name, true,
 			path.LockBuffer(), path.BufferSize());
 	}
 	if (status != B_OK)
@@ -1583,7 +1583,7 @@ ModuleNotificationService::_Notify(int32 opcode, dev_t device, ino_t directory,
 	if (name != NULL) {
 		// we have an entry ref
 		if (pathBuffer.InitCheck() != B_OK
-			|| vfs_entry_ref_to_path(device, directory, name,
+			|| vfs_entry_ref_to_path(device, directory, name, true,
 				pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK)
 			return;
 
diff --git a/src/tools/fs_shell/vfs.cpp b/src/tools/fs_shell/vfs.cpp
index 8bc875ec52..b179269d1b 100644
--- a/src/tools/fs_shell/vfs.cpp
+++ b/src/tools/fs_shell/vfs.cpp
@@ -2690,7 +2690,7 @@ vfs_get_vnode_name(void *_vnode, char *name, fssh_size_t nameSize)
 
 fssh_status_t
 vfs_entry_ref_to_path(fssh_dev_t device, fssh_ino_t inode, const char *leaf,
-	char *path, fssh_size_t pathLength)
+	bool kernel, char *path, fssh_size_t pathLength)
 {
 	struct vnode *vnode;
 	fssh_status_t status;
@@ -5691,7 +5691,7 @@ fssh_status_t
 _kern_entry_ref_to_path(fssh_dev_t device, fssh_ino_t inode, const char *leaf,
 	char* path, fssh_size_t pathLength)
 {
-	return vfs_entry_ref_to_path(device, inode, leaf, path, pathLength);
+	return vfs_entry_ref_to_path(device, inode, leaf, true, path, pathLength);
 }
 
 

From ef40a60ae86e3496a2c874a6a6b351ab3c2566d3 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 22 Apr 2013 19:09:41 +0200
Subject: [PATCH 0474/1170] Update Vision package

---
 build/jam/OptionalPackages | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index e1809736ec..e4cf2a1b5a 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -1449,7 +1449,7 @@ if [ IsOptionalHaikuImagePackageAdded Vision ] {
 				$(baseURL)/vision-908-r1a3-x86-gcc4-2011-06-07.zip ;
 		} else {
 			InstallOptionalHaikuImagePackage
-				$(hpkgBaseURL)/vision-908-1-x86_gcc2.hpkg
+				$(hpkgBaseURL)/vision-908-2-x86_gcc2.hpkg
 				: common packages ;
 		}
 		AddSymlinkToHaikuImage home config settings deskbar Applications

From dbcaf9ee61fdc79bd664dab45ff3fecbac2fd965 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 22 Apr 2013 20:35:41 +0200
Subject: [PATCH 0475/1170] Update WQY-MicroHei package

---
 build/jam/OptionalPackages | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index e4cf2a1b5a..d4dbbf293e 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -1570,7 +1570,7 @@ if [ IsOptionalHaikuImagePackageAdded wpa_supplicant ] {
 # WQY-MicroHei
 if [ IsOptionalHaikuImagePackageAdded WQY-MicroHei ] {
 	InstallOptionalHaikuImagePackage
-		$(hpkgBaseURL)/wqy-microhei-0.2.0-beta-1-x86_gcc2.hpkg
+		$(hpkgBaseURL)/wqy_microhei-0.2.0~beta-2-any.hpkg
 		: common packages ;
 }
 

From d6a80eb12240d2234e4009cbb382d84b780f71d5 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 22 Apr 2013 21:58:17 +0200
Subject: [PATCH 0476/1170] Add private headers to haiku_devel package

Also include the freebsd_network and freebsd_wlan headers. Their final
location and which of them to include in the first place might need some
adjustments.
---
 build/jam/HaikuPackages | 9 +++++++++
 1 file changed, 9 insertions(+)

diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages
index cae0a186b8..544cc22122 100644
--- a/build/jam/HaikuPackages
+++ b/build/jam/HaikuPackages
@@ -412,6 +412,15 @@ AddHeaderDirectoryToPackage glibc ;
 AddHeaderDirectoryToPackage os ;
 AddHeaderDirectoryToPackage posix ;
 
+# private headers
+AddHeaderDirectoryToPackage private ;
+CopyDirectoryToPackage develop headers private libs compat
+	: [ FDirName $(HAIKU_TOP) src libs compat freebsd_network ]
+	: : -x *.c -x *.cpp -x *.awk -x Jamfile -x miidevs ;
+CopyDirectoryToPackage develop headers private libs compat
+	: [ FDirName $(HAIKU_TOP) src libs compat freebsd_wlan ]
+	: : -x *.c -x Jamfile ;
+
 # create be -> os symlink for now
 AddSymlinkToPackage $(developDirTokens) headers : os : be ;
 

From 60ac56d3fa689794789a2fc73abe08cafb23b4f7 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 22 Apr 2013 22:29:06 +0200
Subject: [PATCH 0477/1170] Update wpa_supplicant package

---
 build/jam/OptionalPackages | 3 ++-
 1 file changed, 2 insertions(+), 1 deletion(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index d4dbbf293e..2deb9d6ed9 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -1562,7 +1562,8 @@ if [ IsOptionalHaikuImagePackageAdded wpa_supplicant ] {
 			$(baseURL)/wpa_supplicant-0.7.3-x86-gcc4-2011-10-05.zip ;
 	} else {
 		InstallOptionalHaikuImagePackage
-			$(baseURL)/wpa_supplicant-0.7.3-x86-gcc2-2011-10-05.zip ;
+			$(hpkgBaseURL)/wpa_supplicant-0.7.3-2-x86_gcc2.hpkg
+			: system packages ;
 	}
 }
 

From 15565a06d446918906f0b0329efe486838cd3148 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Mon, 22 Apr 2013 23:57:28 +0200
Subject: [PATCH 0478/1170] Repackaged WonderBrush zip as HPKG

---
 build/jam/OptionalPackages | 11 +++++------
 1 file changed, 5 insertions(+), 6 deletions(-)

diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 2deb9d6ed9..11bf1629a1 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -1543,12 +1543,11 @@ if [ IsOptionalHaikuImagePackageAdded WonderBrush ] {
 	} else if $(HAIKU_GCC_VERSION[1]) >= 4 {
 		Echo "No optional package WonderBrush available for gcc4" ;
 	} else {
-# TODO: Package as HPKG!
-#		InstallOptionalHaikuImagePackage
-#			$(baseURL)/WonderBrush-2.1.2-x86-gcc2-2008-11-08.zip
-#			: common apps ;
-#		AddSymlinkToHaikuImage home config settings deskbar Applications
-#			: /boot/apps/WonderBrush/WonderBrush ;
+		InstallOptionalHaikuImagePackage
+			$(hpkgBaseURL)/wonderbrush-2.1.2-1-x86_gcc2.hpkg
+			: common packages ;
+		AddSymlinkToHaikuImage home config settings deskbar Applications
+			: /boot/common/apps/WonderBrush/WonderBrush ;
 	}
 }
 

From 78d1b920ed6c3994fe5c9d36abeff56b0b7da8f4 Mon Sep 17 00:00:00 2001
From: Oliver Tappe 
Date: Tue, 23 Apr 2013 13:31:02 +0200
Subject: [PATCH 0479/1170] Adjust pkgman to consider symlinks to both
 package-infos and packages.

---
 src/bin/pkgman/RepositoryBuilder.cpp | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/bin/pkgman/RepositoryBuilder.cpp b/src/bin/pkgman/RepositoryBuilder.cpp
index be765ee4d9..d056d6e356 100644
--- a/src/bin/pkgman/RepositoryBuilder.cpp
+++ b/src/bin/pkgman/RepositoryBuilder.cpp
@@ -86,7 +86,7 @@ RepositoryBuilder::AddPackage(const char* path, BSolverPackage** _package)
 		// a package info file (supposedly)
 		PackageInfoErrorListener errorListener(
 			"Error: failed to read package info");
-		error = packageInfo.ReadFromConfigFile(BEntry(path),
+		error = packageInfo.ReadFromConfigFile(BEntry(path, true),
 			&errorListener);
 	}
 
@@ -144,7 +144,7 @@ RepositoryBuilder::AddPackagesDirectory(const char* path)
 			DIE(errno, "failed to construct path");
 
 		struct stat st;
-		if (lstat(entryPath.Path(), &st) != 0)
+		if (stat(entryPath.Path(), &st) != 0)
 			DIE(errno, "failed to stat() %s", entryPath.Path());
 
 		if (!S_ISREG(st.st_mode))

From 89804230e16cd49bf6c506e1315553035e63c6ea Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 23 Apr 2013 19:49:21 +0200
Subject: [PATCH 0480/1170] Override File actions to be whitespace-safe

---
 build/jam/OverriddenJamRules | 6 ++++++
 1 file changed, 6 insertions(+)

diff --git a/build/jam/OverriddenJamRules b/build/jam/OverriddenJamRules
index 5aee80234d..190e66f557 100644
--- a/build/jam/OverriddenJamRules
+++ b/build/jam/OverriddenJamRules
@@ -692,3 +692,9 @@ rule SubInclude
 	# restore SUBDIR_TOKENS
 	SUBDIR_TOKENS = $(oldSubDirTokens) ;
 }
+
+
+actions File
+{
+	$(CP) "$(>)" "$(<)"
+}

From 0d452c8f34013b611a54c746a71c05e28796eae2 Mon Sep 17 00:00:00 2001
From: Ingo Weinhold 
Date: Tue, 23 Apr 2013 19:53:25 +0200
Subject: [PATCH 0481/1170] Remove the TrackerNewTemplates optional package

Instead add the files to the tree and generate the resulting files on
the fly. This also avoids the undesired attributes the files in the
package had.
---
 build/jam/HaikuImage                          |   9 ++
 build/jam/OptionalPackages                    |  10 --
 build/jam/ReleaseBuildProfiles                |   3 +-
 src/data/Jamfile                              |   1 +
 src/data/settings/Jamfile                     |   3 +
 .../settings/tracker_new_templates/C++ header |  17 +++
 .../settings/tracker_new_templates/C++ source |   6 +
 .../settings/tracker_new_templates/Jamfile    |  18 +++
 .../settings/tracker_new_templates/makefile   | 125 ++++++++++++++++++
 .../settings/tracker_new_templates/text file  |   0
 10 files changed, 180 insertions(+), 12 deletions(-)
 create mode 100644 src/data/settings/Jamfile
 create mode 100644 src/data/settings/tracker_new_templates/C++ header
 create mode 100644 src/data/settings/tracker_new_templates/C++ source
 create mode 100644 src/data/settings/tracker_new_templates/Jamfile
 create mode 100644 src/data/settings/tracker_new_templates/makefile
 create mode 100644 src/data/settings/tracker_new_templates/text file

diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage
index 799cc0c13b..580bdb670b 100644
--- a/build/jam/HaikuImage
+++ b/build/jam/HaikuImage
@@ -265,6 +265,15 @@ AddDirectoryToHaikuImage home config boot launch ;
 AddFilesToHaikuImage home config settings Mail ProviderInfo :
 	$(HAIKU_PROVIDER_INFOS) ;
 
+# Add Tracker New Templates
+AddFilesToHaikuImage home config settings Tracker "Tracker New Templates"
+	:
+	"C++ header"
+	"C++ source"
+	"makefile"
+	"text file"
+;
+
 local etcDir = [ FDirName $(HAIKU_TOP) data etc ] ;
 local etcFiles = inputrc profile ;
 etcFiles = $(etcFiles:G=etc) ;
diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages
index 11bf1629a1..dcdd55eda9 100644
--- a/build/jam/OptionalPackages
+++ b/build/jam/OptionalPackages
@@ -73,7 +73,6 @@
 #	TagLib					- id3 tag library
 #	Tar						- archiving utility
 #	TimGMSoundFont			- a good quality General MIDI Sound Font
-#	TrackerNewTemplates		- template files for Tracker's New menu
 #	Transmission			- a fast, easy, and free BitTorrent Client
 #	UserlandFS				- aids native file system development (like FUSE)
 #	Vim						- Vi IMproved. Highly configurable text editor
@@ -1338,15 +1337,6 @@ if [ IsOptionalHaikuImagePackageAdded TimGMSoundFont ] {
 }
 
 
-# TrackerNewTemplates
-if [ IsOptionalHaikuImagePackageAdded TrackerNewTemplates ] {
-	InstallOptionalHaikuImagePackage
-		$(baseURL)/TrackerNewTemplates-2010-04-26.zip
-		: home config settings Tracker "Tracker New Templates"
-	;
-}
-
-
 # Transmission
 if [ IsOptionalHaikuImagePackageAdded Transmission ] {
 	if $(TARGET_ARCH) != x86 {
diff --git a/build/jam/ReleaseBuildProfiles b/build/jam/ReleaseBuildProfiles
index 2958c676ad..a4111b2df8 100644
--- a/build/jam/ReleaseBuildProfiles
+++ b/build/jam/ReleaseBuildProfiles
@@ -19,8 +19,7 @@ switch $(HAIKU_BUILD_PROFILE) {
 		HAIKU_IMAGE_SIZE = 750 ;
 		HAIKU_STRIP_DEBUG_FROM_OPTIONAL_PACKAGES = 1 ;
 
-		AddOptionalHaikuImagePackages TimGMSoundFont TrackerNewTemplates
-			WQY-MicroHei ;
+		AddOptionalHaikuImagePackages TimGMSoundFont WQY-MicroHei ;
 		AddOptionalHaikuImagePackages BePDF Pe Vision
 			WebPositive WonderBrush ;
 		AddOptionalHaikuImagePackages CVS Development Git Mercurial
diff --git a/src/data/Jamfile b/src/data/Jamfile
index 8be659eb29..ff8475313b 100644
--- a/src/data/Jamfile
+++ b/src/data/Jamfile
@@ -2,3 +2,4 @@ SubDir HAIKU_TOP src data ;
 
 HaikuSubInclude etc ;
 HaikuSubInclude keymaps ;
+HaikuSubInclude settings ;
diff --git a/src/data/settings/Jamfile b/src/data/settings/Jamfile
new file mode 100644
index 0000000000..c550b4280c
--- /dev/null
+++ b/src/data/settings/Jamfile
@@ -0,0 +1,3 @@
+SubDir HAIKU_TOP src data settings ;
+
+HaikuSubInclude tracker_new_templates ;
diff --git a/src/data/settings/tracker_new_templates/C++ header b/src/data/settings/tracker_new_templates/C++ header
new file mode 100644
index 0000000000..5abbba7563
--- /dev/null
+++ b/src/data/settings/tracker_new_templates/C++ header	
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2010 Your Name 
+ * All rights reserved. Distributed under the terms of the MIT license.
+ */
+#ifndef _H
+#define _H
+
+#include 
+
+class {
+public:
+								
+private:
+
+};
+
+#endif // _H
diff --git a/src/data/settings/tracker_new_templates/C++ source b/src/data/settings/tracker_new_templates/C++ source
new file mode 100644
index 0000000000..382c05c26d
--- /dev/null
+++ b/src/data/settings/tracker_new_templates/C++ source	
@@ -0,0 +1,6 @@
+/*
+ * Copyright 2010 Your Name 
+ * All rights reserved. Distributed under the terms of the MIT license.
+ */
+#include ".h"
+
diff --git a/src/data/settings/tracker_new_templates/Jamfile b/src/data/settings/tracker_new_templates/Jamfile
new file mode 100644
index 0000000000..6fd17aaafd
--- /dev/null
+++ b/src/data/settings/tracker_new_templates/Jamfile
@@ -0,0 +1,18 @@
+SubDir HAIKU_TOP src data settings tracker_new_templates ;
+
+
+rule PrepareTrackerNewTemplates source : mimeType
+{
+	local source = [ FGristFiles $(source) ] ;
+	local target = $(source:G=tracker-new-templates) ;
+	MakeLocateCommonPlatform $(target) ;
+	File $(target) : $(source) ;
+	TARGET_EXECUTABLE_MIME_TYPE on $(target) = $(mimeType) ;
+	SetType $(target) ;
+}
+
+
+PrepareTrackerNewTemplates "C++ header" : text/x-source-code ;
+PrepareTrackerNewTemplates "C++ source" : text/x-source-code ;
+PrepareTrackerNewTemplates "makefile" : text/x-makefile ;
+PrepareTrackerNewTemplates "text file" : text/plain ;
diff --git a/src/data/settings/tracker_new_templates/makefile b/src/data/settings/tracker_new_templates/makefile
new file mode 100644
index 0000000000..e50b2b05f4
--- /dev/null
+++ b/src/data/settings/tracker_new_templates/makefile
@@ -0,0 +1,125 @@
+## BeOS Generic Makefile v2.3 ##
+
+## Fill in this file to specify the project being created, and the referenced
+## makefile-engine will do all of the hard work for you.  This handles both
+## Intel and PowerPC builds of the BeOS and Haiku.
+
+## Application Specific Settings ---------------------------------------------
+
+# specify the name of the binary
+NAME= 
+
+# specify the type of binary
+#	APP:	Application
+#	SHARED:	Shared library or add-on
+#	STATIC:	Static library archive
+#	DRIVER: Kernel Driver
+TYPE= 
+
+#	add support for new Pe and Eddie features
+#	to fill in generic makefile
+
+#%{
+# @src->@ 
+
+#	specify the source files to use
+#	full paths or paths relative to the makefile can be included
+# 	all files, regardless of directory, will have their object
+#	files created in the common object directory.
+#	Note that this means this makefile will not work correctly
+#	if two source files with the same name (source.c or source.cpp)
+#	are included from different directories.  Also note that spaces
+#	in folder names do not work well with this makefile.
+SRCS= 
+
+#	specify the resource definition files to use
+#	full path or a relative path to the resource file can be used.
+RDEFS= 
+	
+#	specify the resource files to use. 
+#	full path or a relative path to the resource file can be used.
+#	both RDEFS and RSRCS can be defined in the same makefile.
+RSRCS= 
+
+# @<-src@ 
+#%}
+
+#	end support for Pe and Eddie
+
+#	specify additional libraries to link against
+#	there are two acceptable forms of library specifications
+#	-	if your library follows the naming pattern of:
+#		libXXX.so or libXXX.a you can simply specify XXX
+#		library: libbe.so entry: be
+#		
+#	- 	if your library does not follow the standard library
+#		naming scheme you need to specify the path to the library
+#		and it's name
+#		library: my_lib.a entry: my_lib.a or path/my_lib.a
+LIBS= 
+
+#	specify additional paths to directories following the standard
+#	libXXX.so or libXXX.a naming scheme.  You can specify full paths
+#	or paths relative to the makefile.  The paths included may not
+#	be recursive, so include all of the paths where libraries can
+#	be found.  Directories where source files are found are
+#	automatically included.
+LIBPATHS= 
+
+#	additional paths to look for system headers
+#	thes use the form: #include 
+# source file directories are NOT auto-included here +SYSTEM_INCLUDE_PATHS = + +# additional paths to look for local headers +# thes use the form: #include "header" +# source file directories are automatically included +LOCAL_INCLUDE_PATHS = + +# specify the level of optimization that you desire +# NONE, SOME, FULL +OPTIMIZE= + +# specify any preprocessor symbols to be defined. The symbols will not +# have their values set automatically; you must supply the value (if any) +# to use. For example, setting DEFINES to "DEBUG=1" will cause the +# compiler option "-DDEBUG=1" to be used. Setting DEFINES to "DEBUG" +# would pass "-DDEBUG" on the compiler's command line. +DEFINES= + +# specify special warning levels +# if unspecified default warnings will be used +# NONE = supress all warnings +# ALL = enable all warnings +WARNINGS = + +# specify whether image symbols will be created +# so that stack crawls in the debugger are meaningful +# if TRUE symbols will be created +SYMBOLS = + +# specify debug settings +# if TRUE will allow application to be run from a source-level +# debugger. Note that this will disable all optimzation. +DEBUGGER = + +# specify additional compiler flags for all files +COMPILER_FLAGS = + +# specify additional linker flags +LINKER_FLAGS = + +# specify the version of this particular item +# (for example, -app 3 4 0 d 0 -short 340 -long "340 "`echo -n -e '\302\251'`"1999 GNU GPL") +# This may also be specified in a resource. +APP_VERSION = + +# (for TYPE == DRIVER only) Specify desired location of driver in the /dev +# hierarchy. Used by the driverinstall rule. E.g., DRIVER_PATH = video/usb will +# instruct the driverinstall rule to place a symlink to your driver's binary in +# ~/add-ons/kernel/drivers/dev/video/usb, so that your driver will appear at +# /dev/video/usb when loaded. Default is "misc". +DRIVER_PATH = + +## include the makefile-engine +include $(BUILDHOME)/etc/makefile-engine diff --git a/src/data/settings/tracker_new_templates/text file b/src/data/settings/tracker_new_templates/text file new file mode 100644 index 0000000000..e69de29bb2 From f3b11fcb9d1100868ed938afcf9dbf812ea01c93 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 23 Apr 2013 20:49:06 +0200 Subject: [PATCH 0482/1170] Update p7zip package --- build/jam/OptionalPackages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index dcdd55eda9..fc2595efa5 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -1111,7 +1111,7 @@ if [ IsOptionalHaikuImagePackageAdded P7zip ] { $(baseURL)/p7zip-9.13-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/p7zip-9.13-1-x86_gcc2.hpkg + $(hpkgBaseURL)/p7zip-9.20.1-2-x86_gcc2.hpkg : common packages ; } AddExpanderRuleToHaikuImage "application/x-7z-compressed" : .7z From e49c7394ef9cf5b080e8c717553a52e244a68a8e Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Tue, 23 Apr 2013 23:07:34 +0200 Subject: [PATCH 0483/1170] Update groff optional package to hpkg --- build/jam/OptionalPackages | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index fc2595efa5..055acb86c2 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -714,8 +714,8 @@ if [ IsOptionalHaikuImagePackageAdded Groff ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(baseURL)/groff-1.20.1-r1a3-x86-gcc2-2011-05-18.zip - : : true ; + $(hpkgBaseURL)/groff-1.20.1-1-x86_gcc2.hpkg + : common packages ; } } } From ffeecbcc87d8ebf8abd4c1395fcf63f8645415ed Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 24 Apr 2013 13:05:54 +0200 Subject: [PATCH 0484/1170] Add more provides to haiku[_devel].hpkg --- src/data/package_infos/haiku | 191 ++++++++++++++++++++++++++--- src/data/package_infos/haiku_devel | 3 +- 2 files changed, 178 insertions(+), 16 deletions(-) diff --git a/src/data/package_infos/haiku b/src/data/package_infos/haiku index c7fb256813..7f9a70ec99 100644 --- a/src/data/package_infos/haiku +++ b/src/data/package_infos/haiku @@ -17,21 +17,182 @@ licenses { provides { haiku=R1~alpha3_pm-1 compat>=R1~alpha1 - coreutils=8.4 compat>=0.0 - diffutils=2.8.1 compat>=0.0 - findutils=4.2.33 compat>=0.0 - zlib=1.2.5 compat>=1 - cmd:awk=0.0.0 - cmd:cp=8.4 compat>=0.0 - cmd:diff=2.8.1 compat>=0.0 - cmd:find=4.2.33 compat>=0.0 - cmd:ln=8.4 compat>=0.0 - cmd:mv=8.4 compat>=0.0 - cmd:sh=0.0.0 - cmd:unzip=5.50 compat>=0.0 - cmd:wget=0.0.0 - cmd:zip=2.32 compat>=0.0 - lib:libz=1.2.5 compat>=1 + coreutils = 8.4 compat >= 0 + diffutils = 2.8.1 compat >= 0 + findutils = 4.2.33 compat >= 0 + zlib = 1.2.5 compat >= 1 + cmd:arp + cmd:awk + cmd:base64 + cmd:basename + cmd:bash + cmd:bc + cmd:bunzip2 + cmd:bzip2 + cmd:cat + cmd:chgrp + cmd:chmod + cmd:chop + cmd:chown + cmd:chroot + cmd:cksum + cmd:clear + cmd:cmp + cmd:comm + cmd:compress + cmd:cp = 8.4 + cmd:csplit + cmd:ctags + cmd:cut + cmd:date + cmd:dc + cmd:dd + cmd:df + cmd:diff = 2.8.1 + cmd:diff3 + cmd:dirname + cmd:du + cmd:echo + cmd:egrep + cmd:env + cmd:expand + cmd:expr + cmd:factor + cmd:false + cmd:fgrep + cmd:find = 4.2.33 + cmd:fmt + cmd:fold + cmd:frcode + cmd:ftp + cmd:ftpd + cmd:funzip + cmd:gawk + cmd:gdb + cmd:getlimits + cmd:grep + cmd:groups + cmd:gunzip + cmd:gzexe + cmd:gzip + cmd:hd + cmd:head + cmd:hostname + cmd:id + cmd:install + cmd:join + cmd:kill + cmd:less + cmd:lessecho + cmd:lesskey + cmd:link + cmd:ln = 8.4 + cmd:locate + cmd:logname + cmd:ls + cmd:md5sum + cmd:merge + cmd:mkdir + cmd:mkfifo + cmd:mktemp + cmd:more + cmd:mv = 8.4 + cmd:netcat + cmd:nl + cmd:nohup + cmd:nproc + cmd:od + cmd:paste + cmd:patch + cmd:pathchk + cmd:ping + cmd:ping6 + cmd:pr + cmd:printenv + cmd:printf + cmd:prio + cmd:ps + cmd:ptx + cmd:pwd + cmd:readlink + cmd:renice + cmd:rlog + cmd:rm + cmd:rmdir + cmd:sdiff + cmd:seq + cmd:sh + cmd:sha1sum + cmd:sha256sum + cmd:shar + cmd:shred + cmd:shuf + cmd:sleep + cmd:sort + cmd:split + cmd:stat + cmd:stty + cmd:su + cmd:sum + cmd:sync + cmd:tac + cmd:tail + cmd:tcpdump + cmd:tee + cmd:telnet + cmd:telnetd + cmd:test + cmd:timeout + cmd:top + cmd:touch + cmd:tput + cmd:tr + cmd:traceroute + cmd:trash + cmd:true + cmd:truncate + cmd:tsort + cmd:tty + cmd:uname + cmd:unchop + cmd:unexpand + cmd:uniq + cmd:unlink + cmd:unrar + cmd:unshar + cmd:unzip = 5.50 + cmd:unzipsfx + cmd:updatedb + cmd:useradd + cmd:uudecode + cmd:uuencode + cmd:vdir + cmd:watch + cmd:wc + cmd:wget = 1.12 + cmd:which + cmd:whoami + cmd:xargs + cmd:xres + cmd:yes + cmd:zcat + cmd:zcmp + cmd:zdiff + cmd:zforce + cmd:zgrep + cmd:zip = 2.32 + cmd:zipcloak + cmd:zipgrep + cmd:zipinfo + cmd:zipnote + cmd:zipsplit + cmd:zmore + cmd:znew + lib:libfreetype = 2.4.4 compat >= 2 + lib:libjpeg = 8.0 + lib:libpng = 1.4.4 compat >= 1 + lib:libtiff = 3.9.4 compat >= 3 + lib:libz = 1.2.5 compat >= 1 } requires { diff --git a/src/data/package_infos/haiku_devel b/src/data/package_infos/haiku_devel index b4ff007c5d..e17c7af56d 100644 --- a/src/data/package_infos/haiku_devel +++ b/src/data/package_infos/haiku_devel @@ -14,7 +14,8 @@ copyrights "2001-2011 Haiku, Inc. et al" licenses "MIT" provides { - haiku_devel=R1~alpha3_pm-1 + haiku_devel = R1~alpha3_pm-1 + lib:libncurses = 5.5 compat >= 5 } requires { From 3f85cfc1322254c2be3b8ef4aa54ea39616e91ed Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 24 Apr 2013 14:55:03 +0200 Subject: [PATCH 0485/1170] Add a few missing directory_which constants --- headers/os/storage/FindDirectory.h | 4 ++++ src/bin/finddir.c | 4 ++++ src/system/libroot/os/find_directory.cpp | 4 ++++ 3 files changed, 12 insertions(+) diff --git a/headers/os/storage/FindDirectory.h b/headers/os/storage/FindDirectory.h index e5550cfb7e..4f84e5805c 100644 --- a/headers/os/storage/FindDirectory.h +++ b/headers/os/storage/FindDirectory.h @@ -68,6 +68,7 @@ typedef enum { B_COMMON_NONPACKAGED_DOCUMENTATION_DIRECTORY, B_COMMON_NONPACKAGED_LIB_DIRECTORY, B_COMMON_NONPACKAGED_HEADERS_DIRECTORY, + B_COMMON_NONPACKAGED_DEVELOP_DIRECTORY, /* User directories. These are interpreted in the context of the user making the find_directory call. */ @@ -98,6 +99,9 @@ typedef enum { B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY, B_USER_NONPACKAGED_LIB_DIRECTORY, B_USER_NONPACKAGED_HEADERS_DIRECTORY, + B_USER_NONPACKAGED_DEVELOP_DIRECTORY, + B_USER_DEVELOP_DIRECTORY, + B_USER_DOCUMENTATION_DIRECTORY, /* Global directories. */ B_APPS_DIRECTORY = 4000, diff --git a/src/bin/finddir.c b/src/bin/finddir.c index 1f659d7d84..d578ddde4a 100644 --- a/src/bin/finddir.c +++ b/src/bin/finddir.c @@ -86,6 +86,7 @@ directoryType directoryTypes[] = { KEYVALUE_PAIR(B_COMMON_NONPACKAGED_DOCUMENTATION_DIRECTORY), KEYVALUE_PAIR(B_COMMON_NONPACKAGED_LIB_DIRECTORY), KEYVALUE_PAIR(B_COMMON_NONPACKAGED_HEADERS_DIRECTORY), + KEYVALUE_PAIR(B_COMMON_NONPACKAGED_DEVELOP_DIRECTORY), // User directories KEYVALUE_PAIR(B_USER_DIRECTORY), @@ -103,6 +104,8 @@ directoryType directoryTypes[] = { KEYVALUE_PAIR(B_USER_DATA_DIRECTORY), KEYVALUE_PAIR(B_USER_CACHE_DIRECTORY), KEYVALUE_PAIR(B_USER_PACKAGES_DIRECTORY), + KEYVALUE_PAIR(B_USER_DEVELOP_DIRECTORY), + KEYVALUE_PAIR(B_USER_DOCUMENTATION_DIRECTORY), KEYVALUE_PAIR(B_USER_HEADERS_DIRECTORY), KEYVALUE_PAIR(B_USER_NONPACKAGED_DIRECTORY), KEYVALUE_PAIR(B_USER_NONPACKAGED_ADDONS_DIRECTORY), @@ -115,6 +118,7 @@ directoryType directoryTypes[] = { KEYVALUE_PAIR(B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY), KEYVALUE_PAIR(B_USER_NONPACKAGED_LIB_DIRECTORY), KEYVALUE_PAIR(B_USER_NONPACKAGED_HEADERS_DIRECTORY), + KEYVALUE_PAIR(B_USER_NONPACKAGED_DEVELOP_DIRECTORY), // Legacy system directories KEYVALUE_PAIR(B_BEOS_DIRECTORY), diff --git a/src/system/libroot/os/find_directory.cpp b/src/system/libroot/os/find_directory.cpp index 659b9f2546..7556f29011 100644 --- a/src/system/libroot/os/find_directory.cpp +++ b/src/system/libroot/os/find_directory.cpp @@ -103,6 +103,7 @@ static const char *kCommonDirectories[] = { COMMON NON_PACKAGED "/documentation", COMMON NON_PACKAGED "/lib", COMMON NON_PACKAGED "/develop/headers", + COMMON NON_PACKAGED "/develop", }; /* User directories */ @@ -138,6 +139,9 @@ static const char *kUserDirectories[] = { HOME CONFIG NON_PACKAGED "/documentation", HOME CONFIG NON_PACKAGED "/lib", HOME CONFIG NON_PACKAGED "/develop/headers", + HOME CONFIG NON_PACKAGED "/develop", + HOME CONFIG "/develop", + HOME CONFIG "/documentation", }; From f7d5bd46d78af12f42fd9bd7c524eda17ce17dc4 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 24 Apr 2013 15:10:55 +0200 Subject: [PATCH 0486/1170] finddir: Print more useful message in error case --- src/bin/finddir.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/bin/finddir.c b/src/bin/finddir.c index d578ddde4a..4c8a16eae6 100644 --- a/src/bin/finddir.c +++ b/src/bin/finddir.c @@ -249,9 +249,8 @@ main(int argc, char *argv[]) if (result == B_OK) { printf("%s\n", buffer); } else { - /* else what? */ - /* this can not happen! */ - fprintf(stderr, "Serious internal error; contact support\n"); + fprintf(stderr, "Failed to get directory: %s\n", strerror(result)); + return 1; } } From 3b5cb3253307909f6bf5a6b29c3d2f081008ac62 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 24 Apr 2013 15:11:16 +0200 Subject: [PATCH 0487/1170] find_directory(): Actually handle the new constants --- src/system/libroot/os/find_directory.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/system/libroot/os/find_directory.cpp b/src/system/libroot/os/find_directory.cpp index 7556f29011..b3ec64614d 100644 --- a/src/system/libroot/os/find_directory.cpp +++ b/src/system/libroot/os/find_directory.cpp @@ -308,6 +308,7 @@ find_directory(directory_which which, dev_t device, bool createIt, case B_COMMON_NONPACKAGED_DOCUMENTATION_DIRECTORY: case B_COMMON_NONPACKAGED_LIB_DIRECTORY: case B_COMMON_NONPACKAGED_HEADERS_DIRECTORY: + case B_COMMON_NONPACKAGED_DEVELOP_DIRECTORY: templatePath = kCommonDirectories[which - B_COMMON_DIRECTORY]; break; @@ -328,6 +329,8 @@ find_directory(directory_which which, dev_t device, bool createIt, case B_USER_CACHE_DIRECTORY: case B_USER_PACKAGES_DIRECTORY: case B_USER_HEADERS_DIRECTORY: + case B_USER_DEVELOP_DIRECTORY: + case B_USER_DOCUMENTATION_DIRECTORY: case B_USER_NONPACKAGED_DIRECTORY: case B_USER_NONPACKAGED_ADDONS_DIRECTORY: case B_USER_NONPACKAGED_TRANSLATORS_DIRECTORY: @@ -339,6 +342,7 @@ find_directory(directory_which which, dev_t device, bool createIt, case B_USER_NONPACKAGED_DOCUMENTATION_DIRECTORY: case B_USER_NONPACKAGED_LIB_DIRECTORY: case B_USER_NONPACKAGED_HEADERS_DIRECTORY: + case B_USER_NONPACKAGED_DEVELOP_DIRECTORY: templatePath = kUserDirectories[which - B_USER_DIRECTORY]; break; From 4b42e1a6bec76cc3e890f254f74c67ddf6eadf3f Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 24 Apr 2013 16:05:05 +0200 Subject: [PATCH 0488/1170] Update man optional package to hpkg --- build/jam/OptionalPackages | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 055acb86c2..0ebb3d707d 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -926,7 +926,8 @@ if [ IsOptionalHaikuImagePackageAdded Man ] { $(baseURL)/man-1.6f-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(baseURL)/man-1.6f-r1a3-x86-gcc2-2011-05-18.zip ; + $(hpkgBaseURL)/man-1.6g-1-x86_gcc2.hpkg + : common packages ; } } From ad1d8a9d0136e8f7aa3e7816a7f74ef6bb167de5 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Wed, 24 Apr 2013 22:35:49 +0200 Subject: [PATCH 0489/1170] Remove ncurses from the haiku_devel package Besides that this version is very old, eventually we want to outsource ncurses anyway. --- build/jam/HaikuPackages | 2 -- src/data/package_infos/haiku_devel | 1 - 2 files changed, 3 deletions(-) diff --git a/build/jam/HaikuPackages b/build/jam/HaikuPackages index 544cc22122..ff61b9c59a 100644 --- a/build/jam/HaikuPackages +++ b/build/jam/HaikuPackages @@ -393,7 +393,6 @@ for lib in $(SYSTEM_LIBS) $(SYSTEM_LIBS_LIBGL_ALIASES) $(developmentLibs) { } # static libraries -AddFilesToPackage $(developDirTokens) lib : libncurses.a ; AddFilesToPackage $(developDirTokens) lib : liblocalestub.a ; # the POSIX error code mapper library @@ -431,7 +430,6 @@ AddHeaderDirectoryToPackage compatibility gnu : gnu ; # third party libs headers AddHeaderDirectoryToPackage libs freetype2 : 3rdparty ; AddHeaderDirectoryToPackage libs jpeg : 3rdparty ; -AddHeaderDirectoryToPackage libs ncurses : 3rdparty ; AddHeaderDirectoryToPackage libs png : 3rdparty ; AddHeaderDirectoryToPackage libs termcap : 3rdparty ; AddHeaderDirectoryToPackage libs tiff : 3rdparty ; diff --git a/src/data/package_infos/haiku_devel b/src/data/package_infos/haiku_devel index e17c7af56d..cbf84da65f 100644 --- a/src/data/package_infos/haiku_devel +++ b/src/data/package_infos/haiku_devel @@ -15,7 +15,6 @@ licenses "MIT" provides { haiku_devel = R1~alpha3_pm-1 - lib:libncurses = 5.5 compat >= 5 } requires { From db88e4417b9247dd8021108296930f974bf35bcc Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 25 Apr 2013 03:38:32 +0200 Subject: [PATCH 0490/1170] Add ncurses optional package --- build/jam/OptionalPackages | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 0ebb3d707d..d14c4d46db 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -52,6 +52,7 @@ # Man - standard commands to read man pages # Mercurial - the distributed version control system # Nano - the command line text editor +# NCurses - the new curses library # Neon - support libraries used for example by SVN # NetFS - the native networked file system components # NetSurf - the web browser @@ -973,6 +974,22 @@ if [ IsOptionalHaikuImagePackageAdded Nano ] { } +# NCurses +if [ IsOptionalHaikuImagePackageAdded Nano ] { + if $(TARGET_ARCH) != x86 { + Echo "No optional package NCurses available for $(TARGET_ARCH)" ; + } else { + if $(HAIKU_GCC_VERSION[1]) >= 4 { + Echo "No optional package NCurses available for gcc 4" ; + } else { + InstallOptionalHaikuImagePackage + $(hpkgBaseURL)/ncurses-5.9-3-x86_gcc2.hpkg + : common packages ; + } + } +} + + # Neon if [ IsOptionalHaikuImagePackageAdded Neon ] { if $(TARGET_ARCH) != x86 { From 8e452bcfc774196f96da51880b5c77d860c425b3 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 25 Apr 2013 17:59:02 +0200 Subject: [PATCH 0491/1170] Update gcc, ncurses, and nano packages --- build/jam/OptionalPackageDependencies | 1 + build/jam/OptionalPackages | 6 +++--- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/build/jam/OptionalPackageDependencies b/build/jam/OptionalPackageDependencies index 7a721eb5c2..cd5479e9f3 100644 --- a/build/jam/OptionalPackageDependencies +++ b/build/jam/OptionalPackageDependencies @@ -22,6 +22,7 @@ OptionalPackageDependencies Man : Groff ; OptionalPackageDependencies Tar : LibIconv ; OptionalPackageDependencies Python : Bzip ; OptionalPackageDependencies Mercurial : Python ; +OptionalPackageDependencies Nano : NCurses ; OptionalPackageDependencies Neon : LibXML2 ; OptionalPackageDependencies NetFS : UserlandFS ; OptionalPackageDependencies NetSurf : OpenSSL Curl LibXML2 LibIconv Libmng ; diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index d14c4d46db..d2e250707d 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -491,7 +491,7 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ] $(hpkgBaseURL)/binutils-2.17_130421-1-x86_gcc2.hpkg : common packages ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/gcc-2.95.3_130421-1-x86_gcc2.hpkg + $(hpkgBaseURL)/gcc-2.95.3_130425-1-x86_gcc2.hpkg : common packages ; } @@ -967,7 +967,7 @@ if [ IsOptionalHaikuImagePackageAdded Nano ] { $(baseURL)/nano-2.2.6-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/nano-2.2.6-1-x86_gcc2.hpkg + $(hpkgBaseURL)/nano-2.2.6-2-x86_gcc2.hpkg : common packages ; } } @@ -983,7 +983,7 @@ if [ IsOptionalHaikuImagePackageAdded Nano ] { Echo "No optional package NCurses available for gcc 4" ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/ncurses-5.9-3-x86_gcc2.hpkg + $(hpkgBaseURL)/ncurses-5.9-4-x86_gcc2.hpkg : common packages ; } } From 44f60330e1abc910883e463b3331c4d952807a59 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Thu, 25 Apr 2013 18:00:08 +0200 Subject: [PATCH 0492/1170] SetupEnvironment: Remove BELIBRARIES It is no longer needed with the current gcc 2 package. --- data/system/boot/SetupEnvironment | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/data/system/boot/SetupEnvironment b/data/system/boot/SetupEnvironment index b4da8e6bd0..cc34c8c2a7 100644 --- a/data/system/boot/SetupEnvironment +++ b/data/system/boot/SetupEnvironment @@ -19,14 +19,11 @@ BeMac|BeBox) BE_HOST_CPU=unknown esac -BELIBRARIES="/boot/common/non-packaged/lib:/boot/common/lib:$BUILDHOME/lib" - -# not used by Haiku, but probably by legacy applications (BeIDE?) +# not used by Haiku, but by (legacy) applications (e.g. Pe) BH=$BUILDHOME/headers BEINCLUDES="$BH;$BH/be;$BH/posix;$BH/glibc;$BH/cpp;$BH/be/app;$BH/be/device;$BH/be/interface;$BH/be/locale;$BH/be/media;$BH/be/midi;$BH/be/midi2;$BH/be/net;$BH/be/kernel;$BH/be/storage;$BH/be/support;$BH/be/game;$BH/be/opengl;$BH/be/drivers;$BH/gnu;$BH/be/mail;$BH/be/translation;$BH/be/devel;$BH/be/add-ons/graphics;$BH/be/be_apps/Deskbar;$BH/be/be_apps/NetPositive;$BH/be/be_apps/Tracker" export BUILDHOME -export BELIBRARIES export BEINCLUDES export BE_HOST_CPU From 13321f4d4b7760bf58faec2b2ffef234a99631ab Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 26 Apr 2013 00:03:31 +0200 Subject: [PATCH 0493/1170] Update sqlite package --- build/jam/OptionalPackages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index d2e250707d..75c1844849 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -1291,7 +1291,7 @@ if [ IsOptionalHaikuImagePackageAdded SQLite ] { $(baseURL)/sqlite-3.7.5-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/sqlite-3.7.5-5-x86_gcc2.hpkg + $(hpkgBaseURL)/sqlite-3.7.13-1-x86_gcc2.hpkg : common packages ; } } From 603c7647a0a04f729a15d118e308c91aa23bdd86 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 26 Apr 2013 01:39:55 +0200 Subject: [PATCH 0494/1170] Update openssl package --- build/jam/OptionalBuildFeatures | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures index 46211c7037..f17e648a0b 100644 --- a/build/jam/OptionalBuildFeatures +++ b/build/jam/OptionalBuildFeatures @@ -14,7 +14,7 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSL ] { if $(HAIKU_GCC_VERSION[1]) >= 4 { HAIKU_OPENSSL_PACKAGE = openssl-1.0.0e-x86-gcc4-2011-09-08.zip ; } else { - HAIKU_OPENSSL_PACKAGE = openssl-1.0.0d-4-x86_gcc2.hpkg ; + HAIKU_OPENSSL_PACKAGE = openssl-1.0.0j-1-x86_gcc2.hpkg ; } local baseURL = http://haiku-files.org/files/optional-packages ; @@ -25,7 +25,7 @@ if $(HAIKU_BUILD_FEATURE_SSL) { if $(TARGET_ARCH) != x86 { Echo "SSL build feature not available for $(TARGET_ARCH)" ; } else { - # Download the zip archive. + # Download the package. local zipFile = [ DownloadFile $(HAIKU_OPENSSL_PACKAGE) : $(HAIKU_OPENSSL_URL) ] ; @@ -36,19 +36,20 @@ if $(HAIKU_BUILD_FEATURE_SSL) { # extract headers and libraries HAIKU_OPENSSL_HEADERS_DEPENDENCY = [ ExtractArchive $(HAIKU_OPENSSL_DIR) - : include/ : $(zipFile) : extracted-openssl + : develop/headers/ : $(zipFile) : extracted-openssl ] ; HAIKU_OPENSSL_LIBS = [ ExtractArchive $(HAIKU_OPENSSL_DIR) : - lib/libcrypto.so - lib/libssl.so + develop/lib/libcrypto.so + develop/lib/libssl.so : $(zipFile) : extracted-openssl ] ; HAIKU_OPENSSL_ENABLED = 1 ; - HAIKU_OPENSSL_HEADERS = [ FDirName $(HAIKU_OPENSSL_DIR) include ] ; + HAIKU_OPENSSL_HEADERS + = [ FDirName $(HAIKU_OPENSSL_DIR) develop/headers ] ; } } From 4d6fe712e00933ce87a40731bc8f8eadacb18261 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 26 Apr 2013 01:40:34 +0200 Subject: [PATCH 0495/1170] Update sqlite package (fix pkgconfig) --- build/jam/OptionalPackages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 75c1844849..a3f341e27e 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -1291,7 +1291,7 @@ if [ IsOptionalHaikuImagePackageAdded SQLite ] { $(baseURL)/sqlite-3.7.5-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/sqlite-3.7.13-1-x86_gcc2.hpkg + $(hpkgBaseURL)/sqlite-3.7.13-2-x86_gcc2.hpkg : common packages ; } } From e25f5f75e8c0fba577b8785e8affc1fddaf1c5d1 Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Fri, 26 Apr 2013 16:28:07 +0200 Subject: [PATCH 0496/1170] Update required version of legacy compiler in configure --- configure | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/configure b/configure index 76af9f2983..c5ebae17c6 100755 --- a/configure +++ b/configure @@ -311,7 +311,7 @@ HOST_GCC_OBJCOPY=`gcc -print-prog-name=objcopy` SFDISK_BINARY=sfdisk HOST_SFDISK=$SFDISK_BINARY -haikuRequiredLegacyGCCVersion="2.95.3-haiku-130421" +haikuRequiredLegacyGCCVersion="2.95.3-haiku-130425" export haikuRequiredLegacyGCCVersion # version of legacy gcc required to build haiku From 4e8a27c90f682fb4de0df8b8263f4d8eb40692a3 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 26 Apr 2013 16:30:00 +0200 Subject: [PATCH 0497/1170] Update libxml2 package --- build/jam/OptionalPackages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index a3f341e27e..7b942f2d27 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -863,7 +863,7 @@ if [ IsOptionalHaikuImagePackageAdded LibXML2 ] { $(baseURL)/libxml2-2.7.8-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/libxml2-2.7.8-4-x86_gcc2.hpkg + $(hpkgBaseURL)/libxml2-2.8.0-1-x86_gcc2.hpkg : common packages ; } } From d26ca29d7559451d836caedfd7fa4dfafe9af606 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 27 Apr 2013 00:19:18 +0200 Subject: [PATCH 0498/1170] Update mkdepend package --- build/jam/OptionalPackages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 7b942f2d27..8afdcf7424 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -528,7 +528,7 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ] $(hpkgBaseURL)/jam-2.5-1-x86_gcc2.hpkg : common packages ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/mkdepend-1.7-1-x86_gcc2.hpkg + $(hpkgBaseURL)/mkdepend-1.7-2-x86_gcc2.hpkg : common packages ; InstallOptionalHaikuImagePackage $(hpkgBaseURL)/make-3.82-4-x86_gcc2.hpkg From b87aa11726e42b170f07dc9b55bf8e9604226326 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 27 Apr 2013 02:57:17 +0200 Subject: [PATCH 0499/1170] Update ncurses package It now includes both the wchar and the non-wchar libraries. --- build/jam/OptionalPackages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 8afdcf7424..d954d916a8 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -983,7 +983,7 @@ if [ IsOptionalHaikuImagePackageAdded Nano ] { Echo "No optional package NCurses available for gcc 4" ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/ncurses-5.9-4-x86_gcc2.hpkg + $(hpkgBaseURL)/ncurses-5.9-5-x86_gcc2.hpkg : common packages ; } } From 6ff8ef530d0b824b73be01005412d2b01bc612af Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 27 Apr 2013 03:12:50 +0200 Subject: [PATCH 0500/1170] Add libedit package --- build/jam/OptionalPackageDependencies | 1 + build/jam/OptionalPackages | 17 +++++++++++++++++ 2 files changed, 18 insertions(+) diff --git a/build/jam/OptionalPackageDependencies b/build/jam/OptionalPackageDependencies index cd5479e9f3..03e246eb5a 100644 --- a/build/jam/OptionalPackageDependencies +++ b/build/jam/OptionalPackageDependencies @@ -17,6 +17,7 @@ OptionalPackageDependencies Development : DevelopmentBase Perl ; OptionalPackageDependencies GetText : LibIconv ; OptionalPackageDependencies Git : Expat Curl OpenSSL LibIconv ; OptionalPackageDependencies ICU-devel : DevelopmentBase ; +OptionalPackageDependencies LibEdit : NCurses ; OptionalPackageDependencies LibLayout : DevelopmentBase ; OptionalPackageDependencies Man : Groff ; OptionalPackageDependencies Tar : LibIconv ; diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index d954d916a8..ca0c6ec7a5 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -40,6 +40,7 @@ # Groff - text formatter used for man pages # ICU-devel - the headers and lib-links for ICU (for development) # KeymapSwitcher - Easy to use keymap switcher +# LibEdit - A BSD licensed replacement for GNU readline # LibEvent - An event notification library # LibIconv - text encoding conversion library # LibLayout - GCC2 package needed by some BeOS apps to compile @@ -779,6 +780,22 @@ if [ IsOptionalHaikuImagePackageAdded KeymapSwitcher ] { } +# LibEdit +if [ IsOptionalHaikuImagePackageAdded LibEdit ] { + if $(TARGET_ARCH) != x86 { + Echo "No optional package LibEdit available for $(TARGET_ARCH)" ; + } else { + if $(HAIKU_GCC_VERSION[1]) >= 4 { + Echo "No optional package LibEdit available for gcc 4" ; + } else { + InstallOptionalHaikuImagePackage + $(hpkgBaseURL)/libedit-20120601_3.0-2-x86_gcc2.hpkg + : common packages ; + } + } +} + + # LibEvent if [ IsOptionalHaikuImagePackageAdded LibEvent ] { if $(TARGET_ARCH) != x86 { From abfcf6aa3fd2cdd4cb65196a7c4909f61eb8a593 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sat, 27 Apr 2013 03:13:37 +0200 Subject: [PATCH 0501/1170] Fix copy and paste error in NCurses optional package section --- build/jam/OptionalPackages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index ca0c6ec7a5..589fad2f41 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -992,7 +992,7 @@ if [ IsOptionalHaikuImagePackageAdded Nano ] { # NCurses -if [ IsOptionalHaikuImagePackageAdded Nano ] { +if [ IsOptionalHaikuImagePackageAdded NCurses ] { if $(TARGET_ARCH) != x86 { Echo "No optional package NCurses available for $(TARGET_ARCH)" ; } else { From c704b139ee161a954250cdf14d809807d67eead3 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 28 Apr 2013 02:25:01 +0200 Subject: [PATCH 0502/1170] Update packages libtool, texinfo, sed, tar --- build/jam/OptionalPackages | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 589fad2f41..4e5547734c 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -474,10 +474,10 @@ if [ IsOptionalHaikuImagePackageAdded Development ] && $(TARGET_ARCH) = x86 { $(hpkgBaseURL)/automake-1.13.1-3-x86_gcc2.hpkg : common packages ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/libtool-2.4-4-x86_gcc2.hpkg + $(hpkgBaseURL)/libtool-2.4-7-x86_gcc2.hpkg : common packages ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/texinfo-4.13a-4-x86_gcc2.hpkg + $(hpkgBaseURL)/texinfo-4.13a-6-x86_gcc2.hpkg : common packages ; } } @@ -1292,7 +1292,7 @@ if [ IsOptionalHaikuImagePackageAdded Sed ] { $(baseURL)/sed-4.2.1-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/sed-4.2.1-3-x86_gcc2.hpkg + $(hpkgBaseURL)/sed-4.2.1-4-x86_gcc2.hpkg : common packages ; } } @@ -1357,7 +1357,7 @@ if [ IsOptionalHaikuImagePackageAdded Tar ] { $(baseURL)/tar-1.25-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/tar-1.26-3-x86_gcc2.hpkg + $(hpkgBaseURL)/tar-1.26-4-x86_gcc2.hpkg : common packages ; } } From 8aa0b0d7928ea2bd8e62917e3e79dbf5e6ae503f Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Sun, 28 Apr 2013 02:40:13 +0200 Subject: [PATCH 0503/1170] Update packages apr, apr_util, curl, flex, jam, libpcre and Pe. --- build/jam/OptionalPackages | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 4e5547734c..9e54cae48f 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -113,7 +113,7 @@ if [ IsOptionalHaikuImagePackageAdded APR ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/apr-1.4.2-5-x86_gcc2.hpkg + $(hpkgBaseURL)/apr-1.4.6-5-x86_gcc2.hpkg : common packages ; } } @@ -129,7 +129,7 @@ if [ IsOptionalHaikuImagePackageAdded APR-util ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/apr_util-1.3.10-4-x86_gcc2.hpkg + $(hpkgBaseURL)/apr_util-1.4.1-1-x86_gcc2.hpkg : common packages ; } } @@ -426,7 +426,7 @@ if [ IsOptionalHaikuImagePackageAdded Curl ] { $(baseURL)/curl-7.21.7-x86-gcc4-2011-06-23.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/curl-7.21.6-1-x86_gcc2.hpkg + $(hpkgBaseURL)/curl-7.26.0-1-x86_gcc2.hpkg : common packages ; } } @@ -523,10 +523,10 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ] $(hpkgBaseURL)/m4-1.4.16-4-x86_gcc2.hpkg : common packages ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/flex-2.5.35-4-x86_gcc2.hpkg + $(hpkgBaseURL)/flex-2.5.35-5-x86_gcc2.hpkg : common packages ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/jam-2.5-1-x86_gcc2.hpkg + $(hpkgBaseURL)/jam-2.5_121012-2-x86_gcc2.hpkg : common packages ; InstallOptionalHaikuImagePackage $(hpkgBaseURL)/mkdepend-1.7-2-x86_gcc2.hpkg @@ -1189,7 +1189,7 @@ if [ IsOptionalHaikuImagePackageAdded PCRE ] { $(baseURL)/libpcre-8.12-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/libpcre-8.12-1-x86_gcc2.hpkg + $(hpkgBaseURL)/libpcre-8.21-3-x86_gcc2.hpkg : common packages ; } } @@ -1206,7 +1206,7 @@ if [ IsOptionalHaikuImagePackageAdded Pe ] { $(baseURL)/pe-2.4.3-600-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/pe-2.4.3_600-1-x86_gcc2.hpkg + $(hpkgBaseURL)/pe-2.4.3_hg602-2-x86_gcc2.hpkg : common packages ; } AddSymlinkToHaikuImage home config settings deskbar Applications From 4521d4c6c7111c68cbbbb4889a0f257548de3ca3 Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Sun, 28 Apr 2013 14:11:17 +0200 Subject: [PATCH 0504/1170] Updated package for Pe (lpe symlink was borked). --- build/jam/OptionalPackages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 9e54cae48f..41c49fc74b 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -1206,7 +1206,7 @@ if [ IsOptionalHaikuImagePackageAdded Pe ] { $(baseURL)/pe-2.4.3-600-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/pe-2.4.3_hg602-2-x86_gcc2.hpkg + $(hpkgBaseURL)/pe-2.4.3_hg602-3-x86_gcc2.hpkg : common packages ; } AddSymlinkToHaikuImage home config settings deskbar Applications From 212cb7333a3d7d583db21e258de72f52ae1f10f1 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 28 Apr 2013 14:39:58 +0200 Subject: [PATCH 0505/1170] packagefs: Fix deadbeef when using a file after package removal When closing a file whose package had been removed, PackageFile::VFSUninit() would crash due to calling Package::Close() on an already destroyed Package object. PackageNode does now hold a reference to the package between VFSInit() and VFSUninit(). --- .../kernel/file_systems/packagefs/PackageFile.cpp | 13 ++++++++++++- .../kernel/file_systems/packagefs/PackageNode.cpp | 3 +++ .../kernel/file_systems/packagefs/PackageNode.h | 12 ++++++++++++ 3 files changed, 27 insertions(+), 1 deletion(-) diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp index d61f36b533..3074257c90 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageFile.cpp @@ -9,6 +9,8 @@ #include #include +#include + #include #include @@ -153,6 +155,12 @@ PackageFile::~PackageFile() status_t PackageFile::VFSInit(dev_t deviceID, ino_t nodeID) { + status_t error = PackageNode::VFSInit(deviceID, nodeID); + if (error != B_OK) + return error; + MethodDeleter baseClassUninit(this, + &PackageNode::NonVirtualVFSUninit); + // open the package int fd = fPackage->Open(); if (fd < 0) @@ -164,7 +172,7 @@ PackageFile::VFSInit(dev_t deviceID, ino_t nodeID) if (fDataAccessor == NULL) RETURN_ERROR(B_NO_MEMORY); - status_t error = fDataAccessor->Init(deviceID, nodeID, fd); + error = fDataAccessor->Init(deviceID, nodeID, fd); if (error != B_OK) { delete fDataAccessor; fDataAccessor = NULL; @@ -172,6 +180,7 @@ PackageFile::VFSInit(dev_t deviceID, ino_t nodeID) } packageCloser.Detach(); + baseClassUninit.Detach(); return B_OK; } @@ -184,6 +193,8 @@ PackageFile::VFSUninit() delete fDataAccessor; fDataAccessor = NULL; } + + PackageNode::VFSUninit(); } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp index 585907afe4..06eb88110a 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageNode.cpp @@ -10,6 +10,7 @@ #include #include "DebugSupport.h" +#include "Package.h" PackageNode::PackageNode(Package* package, mode_t mode) @@ -48,6 +49,7 @@ PackageNode::Init(PackageDirectory* parent, const char* name) status_t PackageNode::VFSInit(dev_t deviceID, ino_t nodeID) { + fPackage->AcquireReference(); return B_OK; } @@ -55,6 +57,7 @@ PackageNode::VFSInit(dev_t deviceID, ino_t nodeID) void PackageNode::VFSUninit() { + fPackage->ReleaseReference(); } diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageNode.h b/src/add-ons/kernel/file_systems/packagefs/PackageNode.h index ec6a57fdc5..8f9ed2f048 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageNode.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageNode.h @@ -28,6 +28,11 @@ public: virtual ~PackageNode(); Package* GetPackage() const { return fPackage; } + // Since PackageNode does only hold a + // reference to the package between + // VFSInit() and VFSUninit(), the caller + // must otherwise make sure the package + // still exists. PackageDirectory* Parent() const { return fParent; } const char* Name() const { return fName; } @@ -36,6 +41,7 @@ public: virtual status_t VFSInit(dev_t deviceID, ino_t nodeID); virtual void VFSUninit(); + // base class versions must be called mode_t Mode() const { return fMode; } @@ -65,6 +71,12 @@ public: inline void* IndexCookieForAttribute(const char* name) const; +protected: + void NonVirtualVFSUninit() + { PackageNode::VFSUninit(); } + // service for derived classes, e.g. for use + // with MethodDeleter + protected: Package* fPackage; PackageDirectory* fParent; From 49da4a2d47649eb78d923de9f23795ab4a1b0e46 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Sun, 28 Apr 2013 19:21:12 +0200 Subject: [PATCH 0506/1170] Update cmake and libsolv packages --- build/jam/OptionalBuildFeatures | 10 +++++----- build/jam/OptionalPackages | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/build/jam/OptionalBuildFeatures b/build/jam/OptionalBuildFeatures index f17e648a0b..cffb52519c 100644 --- a/build/jam/OptionalBuildFeatures +++ b/build/jam/OptionalBuildFeatures @@ -222,7 +222,7 @@ if $(TARGET_ARCH) != x86 { Echo "Libsolv not available for $(TARGET_ARCH)." ; } else if $(HAIKU_GCC_VERSION[1]) = 2 { HAIKU_LIBSOLV_PACKAGE - = libsolv-0.3.0_haiku_2013_04_18-1-x86_gcc2.hpkg ; + = libsolv-0.3.0_haiku_2013_04_18-2-x86_gcc2.hpkg ; } else { Echo "Libsolv not available for gcc4." ; } @@ -236,16 +236,16 @@ if $(HAIKU_LIBSOLV_PACKAGE) { # extract headers and libraries HAIKU_LIBSOLV_HEADERS_DEPENDENCY = [ ExtractArchive $(HAIKU_LIBSOLV_DIR) - : include/ : $(HAIKU_LIBSOLV_PACKAGE_FILE) : extracted-libsolv + : develop/headers/ : $(HAIKU_LIBSOLV_PACKAGE_FILE) : extracted-libsolv ] ; HAIKU_LIBSOLV_LIBS = [ ExtractArchive $(HAIKU_LIBSOLV_DIR) : - lib/libsolv.so - lib/libsolvext.so + develop/lib/libsolv.so + develop/lib/libsolvext.so : $(HAIKU_LIBSOLV_PACKAGE_FILE) : extracted-libsolv ] ; - HAIKU_LIBSOLV_HEADERS = [ FDirName $(HAIKU_LIBSOLV_DIR) include ] ; + HAIKU_LIBSOLV_HEADERS = [ FDirName $(HAIKU_LIBSOLV_DIR) develop/headers ] ; } diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 41c49fc74b..766f53b161 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -410,7 +410,7 @@ if [ IsOptionalHaikuImagePackageAdded CMake ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/cmake-2.8.5-2-gcc2_x86.hpkg + $(hpkgBaseURL)/cmake-2.8.5-3-x86_gcc2.hpkg : common packages ; } } From 3cd00599c8c42e2fa48bd8890adf7b12fc3dad37 Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Sun, 28 Apr 2013 19:56:49 +0200 Subject: [PATCH 0507/1170] Update packages for CARootCertificates, curl, BePDF --- build/jam/OptionalPackages | 19 +++++++++++++++++-- 1 file changed, 17 insertions(+), 2 deletions(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 766f53b161..b05fd784d0 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -19,6 +19,7 @@ # Bluetooth - experimental Haiku components for Bluetooth # BurnItNow - CD burning app # Bzip - file archiving utility +# CARootCertificates - bundle with trusted CA root certificates # CCache - fast compiler cache # CDRecord - the command line CD writing tools # Clockwerk - native audio/video compositing @@ -250,7 +251,7 @@ if [ IsOptionalHaikuImagePackageAdded BePDF ] { Echo "No optional package BePDF available for gcc4" ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/bepdf-1.1.1b4-1-x86_gcc2.hpkg + $(hpkgBaseURL)/bepdf-1.1.1~beta5-1-x86_gcc2.hpkg : common packages ; AddSymlinkToHaikuImage home config settings deskbar Applications : /boot/apps/BePDF/BePDF ; @@ -338,6 +339,20 @@ if [ IsOptionalHaikuImagePackageAdded Bzip ] { } +# CARootCertificates +if [ IsOptionalHaikuImagePackageAdded CARootCertificates ] { + if $(HAIKU_GCC_VERSION[1]) >= 4 { + InstallOptionalHaikuImagePackage + : $(baseURL)/cert-2012-07-04.zip + : common data ssl ; + } else { + InstallOptionalHaikuImagePackage + : $(hpkgBaseURL)/ca_root_certificates-121229-1-any.hpkg + : common packages ; + } +} + + # CCache if [ IsOptionalHaikuImagePackageAdded CCache ] { if $(TARGET_ARCH) != x86 { @@ -426,7 +441,7 @@ if [ IsOptionalHaikuImagePackageAdded Curl ] { $(baseURL)/curl-7.21.7-x86-gcc4-2011-06-23.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/curl-7.26.0-1-x86_gcc2.hpkg + $(hpkgBaseURL)/curl-7.26.0-2-x86_gcc2.hpkg : common packages ; } } From d28741462809e47e61b24d35735ab923fabb2863 Mon Sep 17 00:00:00 2001 From: Oliver Tappe Date: Sun, 28 Apr 2013 23:50:46 +0200 Subject: [PATCH 0508/1170] Update BeBook package and fix URL of BePDF package. --- build/jam/OptionalPackages | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index b05fd784d0..32566f8f76 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -201,10 +201,10 @@ if [ IsOptionalHaikuImagePackageAdded Beam ] { # BeBook if [ IsOptionalHaikuImagePackageAdded BeBook ] { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/bebook-2008-10-26-1.hpkg + $(hpkgBaseURL)/be_book-20081026-1-any.hpkg : system packages ; AddSymlinkToHaikuImage home Desktop - : /boot/system/documentation/bebook/index.html + : /boot/system/documentation/BeBook/index.html : BeBook ; } @@ -251,7 +251,7 @@ if [ IsOptionalHaikuImagePackageAdded BePDF ] { Echo "No optional package BePDF available for gcc4" ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/bepdf-1.1.1~beta5-1-x86_gcc2.hpkg + $(hpkgBaseURL)/bepdf-1.1.1~beta5_130428-1-x86_gcc2.hpkg : common packages ; AddSymlinkToHaikuImage home config settings deskbar Applications : /boot/apps/BePDF/BePDF ; From bd3c533887006582a8d64f54b5f95706ab4146c5 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 29 Apr 2013 01:03:19 +0200 Subject: [PATCH 0509/1170] Update openssh package --- build/jam/OptionalPackages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 32566f8f76..eafde52573 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -1126,7 +1126,7 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSH ] { $(baseURL)/openssh-5.9p1-x86-gcc4-2011-09-08.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/openssh-5.8p2-1-x86_gcc2.hpkg + $(hpkgBaseURL)/openssh-6.0p1-2-x86_gcc2.hpkg : common packages ; } From 0302ce8180857193a39eaeca936085fdc306fa42 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 29 Apr 2013 01:43:01 +0200 Subject: [PATCH 0510/1170] Update bzip2 package --- build/jam/OptionalPackages | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index eafde52573..0784f790a2 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -333,7 +333,7 @@ if [ IsOptionalHaikuImagePackageAdded Bzip ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/bzip2-1.0.6-1-x86_gcc2.hpkg + $(hpkgBaseURL)/bzip2-1.0.6-2-x86_gcc2.hpkg : common packages ; } } From e17463fed22edbca4eb0ada0340b334777a46fce Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 29 Apr 2013 11:44:34 +0200 Subject: [PATCH 0511/1170] Update gettext package --- build/jam/OptionalPackages | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 0784f790a2..4d1b2f0c26 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -677,8 +677,8 @@ if [ IsOptionalHaikuImagePackageAdded GetText ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(baseURL)/gettext-0.18.1.1-x86-gcc2-2011-02-07.zip - : : true ; + $(hpkgBaseURL)/gettext-0.18.1.1-3-x86_gcc2.hpkg + : common packages ; } } } From 87a36d222790146939fc4d26960101e6a5bc5252 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 29 Apr 2013 15:31:13 +0200 Subject: [PATCH 0512/1170] PackageFSMountType: Add *_ENUM_COUNT --- headers/private/package/packagefs.h | 4 +++- src/add-ons/kernel/file_systems/packagefs/Volume.cpp | 2 ++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/headers/private/package/packagefs.h b/headers/private/package/packagefs.h index 8768e6c0ef..3737eee821 100644 --- a/headers/private/package/packagefs.h +++ b/headers/private/package/packagefs.h @@ -16,7 +16,9 @@ enum PackageFSMountType { PACKAGE_FS_MOUNT_TYPE_SYSTEM, PACKAGE_FS_MOUNT_TYPE_COMMON, PACKAGE_FS_MOUNT_TYPE_HOME, - PACKAGE_FS_MOUNT_TYPE_CUSTOM + PACKAGE_FS_MOUNT_TYPE_CUSTOM, + + PACKAGE_FS_MOUNT_TYPE_ENUM_COUNT }; diff --git a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp index 8fdc491b01..6f9f788442 100644 --- a/src/add-ons/kernel/file_systems/packagefs/Volume.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/Volume.cpp @@ -1654,6 +1654,8 @@ Volume::_CreateShineThroughDirectories(const char* shineThroughSetting) break; case PACKAGE_FS_MOUNT_TYPE_CUSTOM: return B_OK; + case PACKAGE_FS_MOUNT_TYPE_ENUM_COUNT: + return B_BAD_VALUE; } } else if (strcmp(shineThroughSetting, "system") == 0) directories = kSystemShineThroughDirectories; From 58081381ea065528589e828d290d8643526cd64e Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 29 Apr 2013 15:38:34 +0200 Subject: [PATCH 0513/1170] packagefs: Add a .settings package symlink It points to the settings directory appropriate for global settings. When a package is installed in ~/config, we cannot use the settings/ subdirectory for global settings, since then the files could clash with equally named user specific settings files (e.g. in case of ssh/known_hosts). So we use ~/config/settings/global for global settings instead. --- build/jam/HaikuImage | 5 +- .../packagefs/PackageLinkDirectory.cpp | 105 +++++++++++------- .../packagefs/PackageLinkDirectory.h | 10 +- .../packagefs/PackageLinkSymlink.cpp | 40 ++++--- .../packagefs/PackageLinkSymlink.h | 12 +- 5 files changed, 112 insertions(+), 60 deletions(-) diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 580bdb670b..0fd497d1cd 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -212,8 +212,11 @@ AddDirectoryToHaikuImage home mail draft ; AddDirectoryToHaikuImage home mail in ; AddDirectoryToHaikuImage home mail out ; -AddSymlinkToHaikuImage home config settings : deskbar : be ; +# global settings when a package is installed in ~/config +AddDirectoryToHaikuImage home config settings global ; + # Deskbar Application links +AddSymlinkToHaikuImage home config settings : deskbar : be ; AddDirectoryToHaikuImage home config settings deskbar Applications ; DESKBAR_APPLICATIONS = ActivityMonitor CharacterMap CodyCam CDPlayer DeskCalc Devices DiskProbe DriveSetup DiskUsage Expander Icon-O-Matic Installer diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp index b0dc5a45a6..24e505bbf7 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.cpp @@ -20,13 +20,15 @@ static const char* const kSelfLinkName = ".self"; +static const char* const kSettingsLinkName = ".settings"; PackageLinkDirectory::PackageLinkDirectory() : Directory(0), // the ID needs to be assigned later, when added to a volume - fSelfLink(NULL) + fSelfLink(NULL), + fSettingsLink(NULL) { get_real_time(fModifiedTime); } @@ -36,6 +38,8 @@ PackageLinkDirectory::~PackageLinkDirectory() { if (fSelfLink != NULL) fSelfLink->ReleaseReference(); + if (fSettingsLink != NULL) + fSettingsLink->ReleaseReference(); while (DependencyLink* link = fDependencyLinks.RemoveHead()) link->ReleaseReference(); @@ -154,55 +158,32 @@ PackageLinkDirectory::_Update(PackageLinksListener* listener) { // Always remove all dependency links -- if there's still a package, they // will be re-created below. - while (DependencyLink* link = fDependencyLinks.RemoveHead()) { - NodeWriteLocker linkLocker(link); - if (listener != NULL) - listener->PackageLinkNodeRemoved(link); - - RemoveChild(link); - linkLocker.Unlock(); - link->ReleaseReference(); - } + while (DependencyLink* link = fDependencyLinks.RemoveHead()) + _RemoveLink(link, listener); // check, if empty Package* package = fPackages.Head(); if (package == NULL) { - // remove self link, if any - if (fSelfLink != NULL) { - NodeWriteLocker selfLinkLocker(fSelfLink); - if (listener != NULL) - listener->PackageLinkNodeRemoved(fSelfLink); + // remove self and settings link + _RemoveLink(fSelfLink, listener); + fSelfLink = NULL; - RemoveChild(fSelfLink); - selfLinkLocker.Unlock(); - fSelfLink->ReleaseReference(); - fSelfLink = NULL; - } + _RemoveLink(fSettingsLink, listener); + fSettingsLink = NULL; return B_OK; } - // create/update self link - if (fSelfLink == NULL) { - fSelfLink = new(std::nothrow) Link(package); - if (fSelfLink == NULL) - return B_NO_MEMORY; + // create/update self and settings link + status_t error = _CreateOrUpdateLink(fSelfLink, package, + Link::TYPE_INSTALLATION_LOCATION, kSelfLinkName, listener); + if (error != B_OK) + RETURN_ERROR(error); - status_t error = fSelfLink->Init(this, kSelfLinkName, - NODE_FLAG_CONST_NAME); - if (error != B_OK) - RETURN_ERROR(error); - - AddChild(fSelfLink); - - if (listener != NULL) { - NodeWriteLocker selfLinkLocker(fSelfLink); - listener->PackageLinkNodeAdded(fSelfLink); - } - } else { - NodeWriteLocker selfLinkLocker(fSelfLink); - fSelfLink->Update(package, listener); - } + error = _CreateOrUpdateLink(fSettingsLink, package, Link::TYPE_SETTINGS, + kSettingsLinkName, listener); + if (error != B_OK) + RETURN_ERROR(error); // update the dependency links return _UpdateDependencies(listener); @@ -256,3 +237,47 @@ PackageLinkDirectory::_UpdateDependencies(PackageLinksListener* listener) return B_OK; } + + +void +PackageLinkDirectory::_RemoveLink(Link* link, PackageLinksListener* listener) +{ + if (link != NULL) { + NodeWriteLocker linkLocker(link); + if (listener != NULL) + listener->PackageLinkNodeRemoved(link); + + RemoveChild(link); + linkLocker.Unlock(); + link->ReleaseReference(); + } +} + + +status_t +PackageLinkDirectory::_CreateOrUpdateLink(Link*& link, Package* package, + Link::Type type, const char* name, PackageLinksListener* listener) +{ + if (link == NULL) { + link = new(std::nothrow) Link(package, type); + if (link == NULL) + return B_NO_MEMORY; + + status_t error = link->Init(this, name, NODE_FLAG_CONST_NAME); + if (error != B_OK) + RETURN_ERROR(error); + + AddChild(link); + + if (listener != NULL) { + NodeWriteLocker lLinkLocker(link); + listener->PackageLinkNodeAdded(link); + } + } else { + NodeWriteLocker lLinkLocker(link); + link->Update(package, listener); + } + + + return B_OK; +} diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h index 798592c243..c0af9ab3ef 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkDirectory.h @@ -41,7 +41,7 @@ private: struct DependencyLink : public PackageLinkSymlink { DependencyLink(Package* package) : - PackageLinkSymlink(package) + PackageLinkSymlink(package, TYPE_INSTALLATION_LOCATION) { } @@ -58,10 +58,18 @@ private: status_t _UpdateDependencies( PackageLinksListener* listener); + status_t _CreateOrUpdateLink(Link*& link, + Package* package, Link::Type type, + const char* name, + PackageLinksListener* listener); + void _RemoveLink(Link* link, + PackageLinksListener* listener); + private: timespec fModifiedTime; PackageList fPackages; Link* fSelfLink; + Link* fSettingsLink; FamilyDependencyList fDependencyLinks; }; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp index 4fbf81f7f2..23098716ab 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.cpp @@ -17,27 +17,32 @@ #include "Volume.h" -static const char* const kSystemLinkPath = "../.."; -static const char* const kCommonLinkPath = "../../../common"; -static const char* const kHomeLinkPath = "../../../home/config"; +static const char* const kLinkPaths[PackageLinkSymlink::TYPE_ENUM_COUNT] + [PACKAGE_FS_MOUNT_TYPE_ENUM_COUNT] = { + { + "../..", + "../../../common", + "../../../home/config" + }, + { + "../../../common/settings", + "../../../common/settings", + "../../../home/config/settings/global" + } +}; static const char* const kUnknownLinkTarget = "?"; static const char* -link_path_for_mount_type(MountType type) +link_path_for_mount_type(MountType mountType, PackageLinkSymlink::Type linkType) { - switch (type) { - case PACKAGE_FS_MOUNT_TYPE_SYSTEM: - return kSystemLinkPath; - case PACKAGE_FS_MOUNT_TYPE_COMMON: - return kCommonLinkPath; - case PACKAGE_FS_MOUNT_TYPE_HOME: - return kHomeLinkPath; - case PACKAGE_FS_MOUNT_TYPE_CUSTOM: - default: - return "?"; + if (mountType < 0 || mountType >= PACKAGE_FS_MOUNT_TYPE_ENUM_COUNT + || linkType < 0 || linkType >= PackageLinkSymlink::TYPE_ENUM_COUNT) { + return kUnknownLinkTarget; } + + return kLinkPaths[linkType][mountType]; } @@ -71,10 +76,11 @@ private: // #pragma mark - PackageLinkSymlink -PackageLinkSymlink::PackageLinkSymlink(Package* package) +PackageLinkSymlink::PackageLinkSymlink(Package* package, Type type) : Node(0), - fLinkPath(kUnknownLinkTarget) + fLinkPath(kUnknownLinkTarget), + fType(type) { Update(package, NULL); } @@ -94,7 +100,7 @@ PackageLinkSymlink::Update(Package* package, PackageLinksListener* listener) fLinkPath = package->InstallPath(); if (fLinkPath == NULL) { fLinkPath = link_path_for_mount_type( - package->Volume()->MountType()); + package->Volume()->MountType(), fType); } } else fLinkPath = kUnknownLinkTarget; diff --git a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h index cbf66fcec3..37e3c42a53 100644 --- a/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h +++ b/src/add-ons/kernel/file_systems/packagefs/PackageLinkSymlink.h @@ -15,7 +15,16 @@ class PackageLinksListener; class PackageLinkSymlink : public Node { public: - PackageLinkSymlink(Package* package); + enum Type { + TYPE_INSTALLATION_LOCATION, + TYPE_SETTINGS, + + TYPE_ENUM_COUNT + }; + +public: + PackageLinkSymlink(Package* package, + Type type); virtual ~PackageLinkSymlink(); void Update(Package* package, @@ -37,6 +46,7 @@ private: private: timespec fModifiedTime; const char* fLinkPath; + Type fType; }; From 5d41bc9af9a872e54abc29fc14fe0120c586e42b Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 29 Apr 2013 16:13:03 +0200 Subject: [PATCH 0514/1170] Add AddPackageFilesToHaikuImage rule --- build/jam/HaikuImage | 2 +- build/jam/ImageRules | 5 +++++ build/jam/OptionalPackages | 8 ++++---- 3 files changed, 10 insertions(+), 5 deletions(-) diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index 0fd497d1cd..efd0563d09 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -200,7 +200,7 @@ SYSTEM_ADD_ONS_FILE_SYSTEMS = bfs bindfs btrfs cdda exfat ext2 fat iso9660 nfs # build the haiku system package and add it include [ FDirName $(HAIKU_BUILD_RULES_DIR) HaikuPackages ] ; -AddFilesToHaikuImage system packages : haiku.hpkg ; +AddPackageFilesToHaikuImage system : haiku.hpkg ; AddSymlinkToHaikuImage . : /boot/common/apps ; diff --git a/build/jam/ImageRules b/build/jam/ImageRules index c3cc52893a..c75240b421 100644 --- a/build/jam/ImageRules +++ b/build/jam/ImageRules @@ -862,6 +862,11 @@ rule AddBootModuleSymlinksToHaikuImage targets : $(targets) ; } +rule AddPackageFilesToHaikuImage location : packages +{ + AddFilesToHaikuImage $(location) packages : $(packages) ; +} + rule AddOptionalHaikuImagePackages packages { local package ; diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index 4d1b2f0c26..ad704e16f1 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -579,8 +579,8 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentMin ] && $(TARGET_ARCH) = x86 { $(HAIKU_GCC_VERSION[1]) ; } - AddFilesToHaikuImage system packages : haiku_devel.hpkg ; - AddFilesToHaikuImage common packages : makefile_engine.hpkg ; + AddPackageFilesToHaikuImage system : haiku_devel.hpkg ; + AddPackageFilesToHaikuImage common : makefile_engine.hpkg ; } @@ -1515,8 +1515,8 @@ if [ IsOptionalHaikuImagePackageAdded WebPositive ] { # Welcome if [ IsOptionalHaikuImagePackageAdded Welcome ] { - AddFilesToHaikuImage system packages : haiku_userguide.hpkg ; - AddFilesToHaikuImage system packages : haiku_welcome.hpkg ; + AddPackageFilesToHaikuImage system : haiku_userguide.hpkg ; + AddPackageFilesToHaikuImage system : haiku_welcome.hpkg ; AddSymlinkToHaikuImage home Desktop : /boot/system/bin/welcome : Welcome ; From 4fd280ddfa2f999654dfe20d9a7980c84c0108a0 Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 29 Apr 2013 16:15:39 +0200 Subject: [PATCH 0515/1170] Simplify use of InstallOptionalHaikuImagePackage When invoked for a hpkg only the installation location (i.e. "common" or "system") has to be specified now and "common" is the default. The rule uses AddPackageFilesToHaikuImage now. --- build/jam/ImageRules | 15 +++- build/jam/OptionalPackages | 162 +++++++++++++------------------------ 2 files changed, 70 insertions(+), 107 deletions(-) diff --git a/build/jam/ImageRules b/build/jam/ImageRules index c75240b421..4b09b0a262 100644 --- a/build/jam/ImageRules +++ b/build/jam/ImageRules @@ -927,16 +927,29 @@ rule InstallSourceArchive file : url rule InstallOptionalHaikuImagePackage url : dirTokens : isCDPackage { + # TODO: Remove the non-hpkg cases! + # Currently the semantics differs depending on isCDPackage and the type of + # the package file: + # * For a hpkg is "common" (default) or "system" and specifies + # the installation location of the package (will be copied to the + # packages/ subdirectory). + # * For a regular archive and isCDPackage true, is ignored and + # the package will be copied to the _package_ directory of the CD image. + # * For a regular archive and isCDPackage false, specifies the + # directory relative to the image's root directory where the content of + # the archive will be extracted to. + local package = $(url:BS) ; # download archive file local archiveFile = [ DownloadFile $(package) : $(url) ] ; if $(package:S) = .hpkg { + local location = $(dirTokens:E=common) ; if $(HAIKU_UPDATE_ALL_PACKAGES) { HAIKU_INCLUDE_IN_IMAGE on $(archiveFile) = 1 ; } - AddFilesToHaikuImage $(dirTokens) : $(archiveFile) ; + AddPackageFilesToHaikuImage $(location) : $(archiveFile) ; } else if ( $(isCDPackage) = true || $(isCDPackage) = 1 ) && $(HAIKU_CD_NAME) { # TODO: If HAIKU_CD_NAME is set, that doesn't mean we're building a CD diff --git a/build/jam/OptionalPackages b/build/jam/OptionalPackages index ad704e16f1..3f77ff2781 100644 --- a/build/jam/OptionalPackages +++ b/build/jam/OptionalPackages @@ -114,8 +114,7 @@ if [ IsOptionalHaikuImagePackageAdded APR ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/apr-1.4.6-5-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/apr-1.4.6-5-x86_gcc2.hpkg ; } } @@ -130,8 +129,7 @@ if [ IsOptionalHaikuImagePackageAdded APR-util ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/apr_util-1.4.1-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/apr_util-1.4.1-1-x86_gcc2.hpkg ; } } @@ -202,7 +200,7 @@ if [ IsOptionalHaikuImagePackageAdded Beam ] { if [ IsOptionalHaikuImagePackageAdded BeBook ] { InstallOptionalHaikuImagePackage $(hpkgBaseURL)/be_book-20081026-1-any.hpkg - : system packages ; + : system ; AddSymlinkToHaikuImage home Desktop : /boot/system/documentation/BeBook/index.html : BeBook ; @@ -251,8 +249,7 @@ if [ IsOptionalHaikuImagePackageAdded BePDF ] { Echo "No optional package BePDF available for gcc4" ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/bepdf-1.1.1~beta5_130428-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/bepdf-1.1.1~beta5_130428-1-x86_gcc2.hpkg ; AddSymlinkToHaikuImage home config settings deskbar Applications : /boot/apps/BePDF/BePDF ; } @@ -269,8 +266,7 @@ if [ IsOptionalHaikuImagePackageAdded BeZillaBrowser ] { $(baseURL)/BeZillaBrowser-2.0.0.22pre-r1a2-x86-gcc4-2010-05-04.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/bezillabrowser-2.0.0.22pre_2010_05_02-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/bezillabrowser-2.0.0.22pre_2010_05_02-1-x86_gcc2.hpkg ; } AddSymlinkToHaikuImage home config settings deskbar Applications : /boot/common/apps/BeZillaBrowser/BeZillaBrowser ; @@ -333,8 +329,7 @@ if [ IsOptionalHaikuImagePackageAdded Bzip ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/bzip2-1.0.6-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/bzip2-1.0.6-2-x86_gcc2.hpkg ; } } @@ -347,8 +342,7 @@ if [ IsOptionalHaikuImagePackageAdded CARootCertificates ] { : common data ssl ; } else { InstallOptionalHaikuImagePackage - : $(hpkgBaseURL)/ca_root_certificates-121229-1-any.hpkg - : common packages ; + : $(hpkgBaseURL)/ca_root_certificates-121229-1-any.hpkg ; } } @@ -376,8 +370,7 @@ if [ IsOptionalHaikuImagePackageAdded CDRecord ] { $(baseURL)/cdrtools-3.01a01-r1a3-x86-gcc4-2011-05-23.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/cdrtools-3.00-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/cdrtools-3.00-1-x86_gcc2.hpkg ; } } @@ -425,8 +418,7 @@ if [ IsOptionalHaikuImagePackageAdded CMake ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/cmake-2.8.5-3-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/cmake-2.8.5-3-x86_gcc2.hpkg ; } } } @@ -441,8 +433,7 @@ if [ IsOptionalHaikuImagePackageAdded Curl ] { $(baseURL)/curl-7.21.7-x86-gcc4-2011-06-23.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/curl-7.26.0-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/curl-7.26.0-2-x86_gcc2.hpkg ; } } @@ -458,8 +449,7 @@ if [ IsOptionalHaikuImagePackageAdded CVS ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/cvs-1.12.13.1-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/cvs-1.12.13.1-2-x86_gcc2.hpkg ; } } } @@ -483,17 +473,13 @@ if [ IsOptionalHaikuImagePackageAdded Development ] && $(TARGET_ARCH) = x86 { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/autoconf-2.69-3-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/autoconf-2.69-3-x86_gcc2.hpkg ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/automake-1.13.1-3-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/automake-1.13.1-3-x86_gcc2.hpkg ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/libtool-2.4-7-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/libtool-2.4-7-x86_gcc2.hpkg ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/texinfo-4.13a-6-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/texinfo-4.13a-6-x86_gcc2.hpkg ; } } @@ -504,11 +490,9 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ] # gcc and binutils if $(HAIKU_GCC_VERSION[1]) = 2 { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/binutils-2.17_130421-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/binutils-2.17_130421-1-x86_gcc2.hpkg ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/gcc-2.95.3_130425-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/gcc-2.95.3_130425-1-x86_gcc2.hpkg ; } if $(HAIKU_GCC_VERSION[1]) = 4 { @@ -532,23 +516,17 @@ if [ IsOptionalHaikuImagePackageAdded DevelopmentBase ] $(baseURL)/make-3.82-r1a3-x86-gcc4-2011-05-23.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/bison-2.4.3-4-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/bison-2.4.3-4-x86_gcc2.hpkg ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/m4-1.4.16-4-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/m4-1.4.16-4-x86_gcc2.hpkg ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/flex-2.5.35-5-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/flex-2.5.35-5-x86_gcc2.hpkg ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/jam-2.5_121012-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/jam-2.5_121012-2-x86_gcc2.hpkg ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/mkdepend-1.7-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/mkdepend-1.7-2-x86_gcc2.hpkg ; InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/make-3.82-4-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/make-3.82-4-x86_gcc2.hpkg ; } } @@ -609,8 +587,7 @@ if [ IsOptionalHaikuImagePackageAdded Doxygen ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/doxygen-1.6.3-1-gcc2_x86.hpkg - : common packages ; + $(hpkgBaseURL)/doxygen-1.6.3-1-gcc2_x86.hpkg ; } } } @@ -627,8 +604,7 @@ if [ IsOptionalHaikuImagePackageAdded Expat ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/expat-2.0.1-4-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/expat-2.0.1-4-x86_gcc2.hpkg ; } } } @@ -677,8 +653,7 @@ if [ IsOptionalHaikuImagePackageAdded GetText ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/gettext-0.18.1.1-3-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/gettext-0.18.1.1-3-x86_gcc2.hpkg ; } } } @@ -695,8 +670,7 @@ if [ IsOptionalHaikuImagePackageAdded Git ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/git-1.7.5-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/git-1.7.5-1-x86_gcc2.hpkg ; } } } @@ -731,8 +705,7 @@ if [ IsOptionalHaikuImagePackageAdded Groff ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/groff-1.20.1-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/groff-1.20.1-1-x86_gcc2.hpkg ; } } } @@ -747,7 +720,7 @@ if [ IsOptionalHaikuImagePackageAdded ICU ] { # unzip gcc2 InstallOptionalHaikuImagePackage $(hpkgBaseURL)/$(HAIKU_ICU_GCC_2_PACKAGE) - : system packages ; + : system ; } else { # unzip gcc4 InstallOptionalHaikuImagePackage @@ -762,7 +735,7 @@ if [ IsOptionalHaikuImagePackageAdded ICU ] { if [ IsOptionalHaikuImagePackageAdded ICU-devel ] { InstallOptionalHaikuImagePackage $(hpkgBaseURL)/$(HAIKU_ICU_DEVEL_PACKAGE) - : common packages ; + : system ; local arch = $(TARGET_ARCH) ; local abi = gcc$(HAIKU_GCC_VERSION[1]) ; @@ -804,8 +777,7 @@ if [ IsOptionalHaikuImagePackageAdded LibEdit ] { Echo "No optional package LibEdit available for gcc 4" ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/libedit-20120601_3.0-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/libedit-20120601_3.0-2-x86_gcc2.hpkg ; } } } @@ -839,8 +811,7 @@ if [ IsOptionalHaikuImagePackageAdded LibIconv ] { $(baseURL)/libiconv-1.13.1-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/libiconv-1.13.1-4-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/libiconv-1.13.1-4-x86_gcc2.hpkg ; } } } @@ -880,7 +851,7 @@ if [ IsOptionalHaikuImagePackageAdded LibSolv ] { } else { InstallOptionalHaikuImagePackage $(hpkgBaseURL)/$(HAIKU_LIBSOLV_PACKAGE) - : system packages ; + : system ; } } @@ -895,8 +866,7 @@ if [ IsOptionalHaikuImagePackageAdded LibXML2 ] { $(baseURL)/libxml2-2.7.8-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/libxml2-2.8.0-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/libxml2-2.8.0-1-x86_gcc2.hpkg ; } } } @@ -959,8 +929,7 @@ if [ IsOptionalHaikuImagePackageAdded Man ] { $(baseURL)/man-1.6f-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/man-1.6g-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/man-1.6g-1-x86_gcc2.hpkg ; } } @@ -982,8 +951,7 @@ if [ IsOptionalHaikuImagePackageAdded Mercurial ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/mercurial-1.8.3-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/mercurial-1.8.3-1-x86_gcc2.hpkg ; } } } @@ -999,8 +967,7 @@ if [ IsOptionalHaikuImagePackageAdded Nano ] { $(baseURL)/nano-2.2.6-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/nano-2.2.6-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/nano-2.2.6-2-x86_gcc2.hpkg ; } } } @@ -1015,8 +982,7 @@ if [ IsOptionalHaikuImagePackageAdded NCurses ] { Echo "No optional package NCurses available for gcc 4" ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/ncurses-5.9-5-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/ncurses-5.9-5-x86_gcc2.hpkg ; } } } @@ -1032,8 +998,7 @@ if [ IsOptionalHaikuImagePackageAdded Neon ] { $(baseURL)/neon-0.29.6-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/neon-0.29.6-4-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/neon-0.29.6-4-x86_gcc2.hpkg ; } } } @@ -1126,8 +1091,7 @@ if [ IsOptionalHaikuImagePackageAdded OpenSSH ] { $(baseURL)/openssh-5.9p1-x86-gcc4-2011-09-08.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/openssh-6.0p1-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/openssh-6.0p1-2-x86_gcc2.hpkg ; } AddUserToHaikuImage sshd : 1001 : 100 : /var/empty : /bin/true @@ -1161,8 +1125,7 @@ if [ IsOptionalHaikuImagePackageAdded P7zip ] { $(baseURL)/p7zip-9.13-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/p7zip-9.20.1-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/p7zip-9.20.1-2-x86_gcc2.hpkg ; } AddExpanderRuleToHaikuImage "application/x-7z-compressed" : .7z : "7za l \\0045s" @@ -1204,8 +1167,7 @@ if [ IsOptionalHaikuImagePackageAdded PCRE ] { $(baseURL)/libpcre-8.12-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/libpcre-8.21-3-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/libpcre-8.21-3-x86_gcc2.hpkg ; } } } @@ -1221,8 +1183,7 @@ if [ IsOptionalHaikuImagePackageAdded Pe ] { $(baseURL)/pe-2.4.3-600-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/pe-2.4.3_hg602-3-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/pe-2.4.3_hg602-3-x86_gcc2.hpkg ; } AddSymlinkToHaikuImage home config settings deskbar Applications : /boot/apps/Pe/Pe ; @@ -1241,8 +1202,7 @@ if [ IsOptionalHaikuImagePackageAdded Perl ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/perl-5.10.1-4-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/perl-5.10.1-4-x86_gcc2.hpkg ; } } } @@ -1259,8 +1219,7 @@ if [ IsOptionalHaikuImagePackageAdded Python ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/python-2.6.6-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/python-2.6.6-1-x86_gcc2.hpkg ; } } } @@ -1307,8 +1266,7 @@ if [ IsOptionalHaikuImagePackageAdded Sed ] { $(baseURL)/sed-4.2.1-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/sed-4.2.1-4-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/sed-4.2.1-4-x86_gcc2.hpkg ; } } @@ -1323,8 +1281,7 @@ if [ IsOptionalHaikuImagePackageAdded SQLite ] { $(baseURL)/sqlite-3.7.5-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/sqlite-3.7.13-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/sqlite-3.7.13-2-x86_gcc2.hpkg ; } } } @@ -1341,8 +1298,7 @@ if [ IsOptionalHaikuImagePackageAdded Subversion ] { : : true ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/subversion-1.6.15-4-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/subversion-1.6.15-4-x86_gcc2.hpkg ; } } } @@ -1372,8 +1328,7 @@ if [ IsOptionalHaikuImagePackageAdded Tar ] { $(baseURL)/tar-1.25-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/tar-1.26-4-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/tar-1.26-4-x86_gcc2.hpkg ; } } } @@ -1383,7 +1338,7 @@ if [ IsOptionalHaikuImagePackageAdded Tar ] { if [ IsOptionalHaikuImagePackageAdded TimGMSoundFont ] { InstallOptionalHaikuImagePackage $(hpkgBaseURL)/TimGMSoundFont-2010-06-16.hpkg - : system packages ; + : system ; } @@ -1489,8 +1444,7 @@ if [ IsOptionalHaikuImagePackageAdded Vision ] { $(baseURL)/vision-908-r1a3-x86-gcc4-2011-06-07.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/vision-908-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/vision-908-2-x86_gcc2.hpkg ; } AddSymlinkToHaikuImage home config settings deskbar Applications : /boot/apps/Vision/Vision ; @@ -1584,8 +1538,7 @@ if [ IsOptionalHaikuImagePackageAdded WonderBrush ] { Echo "No optional package WonderBrush available for gcc4" ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/wonderbrush-2.1.2-1-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/wonderbrush-2.1.2-1-x86_gcc2.hpkg ; AddSymlinkToHaikuImage home config settings deskbar Applications : /boot/common/apps/WonderBrush/WonderBrush ; } @@ -1602,7 +1555,7 @@ if [ IsOptionalHaikuImagePackageAdded wpa_supplicant ] { } else { InstallOptionalHaikuImagePackage $(hpkgBaseURL)/wpa_supplicant-0.7.3-2-x86_gcc2.hpkg - : system packages ; + : system ; } } @@ -1610,8 +1563,7 @@ if [ IsOptionalHaikuImagePackageAdded wpa_supplicant ] { # WQY-MicroHei if [ IsOptionalHaikuImagePackageAdded WQY-MicroHei ] { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/wqy_microhei-0.2.0~beta-2-any.hpkg - : common packages ; + $(hpkgBaseURL)/wqy_microhei-0.2.0~beta-2-any.hpkg ; } @@ -1621,8 +1573,7 @@ if [ IsOptionalHaikuImagePackageAdded XZ-Utils ] { Echo "No optional package XZ-Utils available for $(TARGET_ARCH)" ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/xz-utils-5.0.1-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/xz-utils-5.0.1-2-x86_gcc2.hpkg ; AddExpanderRuleToHaikuImage "application/x-xz" : .tar.xz : "tar -Jtvf \\0045s" : "tar -Jxvf \\0045s" @@ -1648,7 +1599,6 @@ if [ IsOptionalHaikuImagePackageAdded Yasm ] { $(baseURL)/yasm-1.1.0-r1a3-x86-gcc4-2011-05-24.zip ; } else { InstallOptionalHaikuImagePackage - $(hpkgBaseURL)/yasm-1.2.0-2-x86_gcc2.hpkg - : common packages ; + $(hpkgBaseURL)/yasm-1.2.0-2-x86_gcc2.hpkg ; } } From ece8449668c88aaf2cf351842830aaa51c30723c Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Mon, 29 Apr 2013 17:57:37 +0200 Subject: [PATCH 0516/1170] Pimp up AddTargetVariableToScript to support a list of targets --- build/jam/ImageRules | 45 +++++++++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 13 deletions(-) diff --git a/build/jam/ImageRules b/build/jam/ImageRules index 4b09b0a262..11eff03b2c 100644 --- a/build/jam/ImageRules +++ b/build/jam/ImageRules @@ -70,28 +70,47 @@ actions together AddVariableToScript1 $(VARIABLE_DEFS)$(1); } -rule AddTargetVariableToScript + +rule AddTargetVariableToScript script : targets : variable { - # AddTargetVariableToScript