diff --git a/build/jam/BeOSRules b/build/jam/BeOSRules index 4559bfb01b..9592fea8e9 100644 --- a/build/jam/BeOSRules +++ b/build/jam/BeOSRules @@ -262,7 +262,7 @@ actions ResAttr1 { $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) if [ \\"$(deleteAttributeFile1)\\" = "true" ]; then - rm -f $(1) + $(RM) $(1) fi $(2[1]) -O -o "$(1)" "$(2[2-])" } diff --git a/build/jam/BuildSetup b/build/jam/BuildSetup index 386efd516c..c121f67b69 100644 --- a/build/jam/BuildSetup +++ b/build/jam/BuildSetup @@ -527,15 +527,21 @@ if $(HOST_PLATFORM_BEOS_COMPATIBLE) { # for builds of tools in the current environment HOST_BUILD_COMPATIBILITY_LIB_DIR = [ FDirName $(HOST_OBJECT_BASE_DIR) lib ] ; +# For the generic attributes emulation: Target rm_attrs -- rm replacement that +# also removes the attributes. +HOST_RM_ATTRS_TARGET = ; + if $(HOST_PLATFORM_BEOS_COMPATIBLE) { HOST_LIBSTDC++ = stdc++.r4 ; HOST_LIBROOT = root ; + HOST_STATIC_LIBROOT = $(HOST_LIBROOT) ; HOST_LIBBE = be ; HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR = ; HOST_LIBRARY_NAME_MAP_input_server = /system/servers/input_server ; } else { HOST_LIBSTDC++ = stdc++ ; HOST_LIBROOT = libroot_build.so ; + HOST_STATIC_LIBROOT = libroot_build.a ; HOST_LIBBE = libbe_build.so ; HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR = "export LD_LIBRARY_PATH=$LD_LIBRARY_PATH:$(HOST_BUILD_COMPATIBILITY_LIB_DIR)" ; @@ -556,8 +562,10 @@ if $(HOST_PLATFORM_BEOS_COMPATIBLE) { # Unlike glibc FreeBSD's libc doesn't have built-in regex support. if $(HOST_PLATFORM) = freebsd { HOST_LIBROOT += /usr/lib/libgnuregex.so ; + HOST_STATIC_LIBROOT += /usr/lib/libgnuregex.so ; } else if $(HOST_PLATFORM) = darwin { HOST_LIBROOT += /opt/local/lib/libgnuregex.dylib ; + HOST_STATIC_LIBROOT += /opt/local/lib/libgnuregex.dylib ; } @@ -580,6 +588,19 @@ if $(HOST_PLATFORM_BEOS_COMPATIBLE) { # which is somewhat more robust. if $(HAIKU_HOST_USE_XATTR) = 1 { HOST_DEFINES += HAIKU_HOST_USE_XATTR ; + } else { + # Otherwise the generic attribute emulation is used, which uses a + # directory per file to store its attribute. We need to redefine RM so + # that the attributes are removed as well. We use a wrapper script, which + # invokes a build tool. If the build tool hasn't been built yet, the + # normal "rm" is used and the attributes are leaked (likely there aren't + # any yet). + RM = $(HOST_ADD_BUILD_COMPATIBILITY_LIB_DIR) ";" + [ FDirName $(HAIKU_TOP) build scripts rm_attrs ] + [ FDirName $(HAIKU_OBJECT_DIR) $(HOST_PLATFORM) $(HOST_ARCH) release + tools rm_attrs ] -f ; + # assumes that rm_attrs is built with debugging disabled + HOST_RM_ATTRS_TARGET = rm_attrs ; } } diff --git a/build/jam/HaikuImage b/build/jam/HaikuImage index b3c6dd15cd..19c4b2ee64 100644 --- a/build/jam/HaikuImage +++ b/build/jam/HaikuImage @@ -664,6 +664,12 @@ AddVariableToScript $(script) : sourceDirsToCopy : $(HAIKU_INSTALL_SOURCE_DIRS) ; AddVariableToScript $(script) : headerDirsToCopy : $(HAIKU_INSTALL_HEADER_DIRS) ; +if $(HOST_RM_ATTRS_TARGET) { + AddTargetVariableToScript $(script) : $(HOST_RM_ATTRS_TARGET) : rmAttrs ; +} else { + AddVariableToScript $(script) : rmAttrs : rm ; +} + # create the other scripts HAIKU_IMAGE_MAKE_DIRS_SCRIPT = haiku.image-make-dirs ; diff --git a/build/jam/ImageRules b/build/jam/ImageRules index 10504b952b..3eda4c8938 100644 --- a/build/jam/ImageRules +++ b/build/jam/ImageRules @@ -37,7 +37,7 @@ rule InitScript actions InitScript1 { - rm -f $(1) + $(RM) $(1) echo -n > $(1) } @@ -678,7 +678,7 @@ rule BuildVMWareImage vmwareImage : plainImage : imageSize actions BuildVMWareImage1 { - rm -f $(1) + $(RM) $(1) $(2[1]) -h 64k -i$(IMAGE_SIZE)M $(1) && cat $(2[2]) >> $(1) } @@ -857,7 +857,7 @@ rule BuildFloppyBootImage image : zbeos : archive actions BuildFloppyBootImage1 { - rm -f $(<) + $(RM) $(<) # make an empty image dd if=/dev/zero of=$(<) bs=1k count=1440 # add zbeos @@ -882,7 +882,7 @@ rule BuildCDBootImage image : bootfloppy : extrafiles actions BuildCDBootImage1 { - rm -f $(<) + $(RM) $(<) mkisofs -b $(BOOTIMG) -r -J -V bootimg -o $(<) $(>[1]) $(>[2-]) } diff --git a/build/jam/MainBuildRules b/build/jam/MainBuildRules index 141411b390..b5b4f2a7ed 100644 --- a/build/jam/MainBuildRules +++ b/build/jam/MainBuildRules @@ -557,8 +557,9 @@ rule BuildPlatformMain # add the build libroot if ! $(HOST_PLATFORM_BEOS_COMPATIBLE) { - Depends $(target) : $(HOST_LIBROOT) ; - NEEDLIBS on $(target) += $(HOST_LIBROOT) ; + local libroot = [ on $(target) return $(HOST_LIBROOT) ] ; + Depends $(target) : $(libroot) ; + NEEDLIBS on $(target) += $(libroot) ; } } @@ -635,15 +636,15 @@ rule BuildPlatformMergeObjectPIC target : sources : otherObjects BuildPlatformMergeObject $(target) : $(sources) : $(otherObjects) ; } -rule BuildPlatformStaticLibrary +rule BuildPlatformStaticLibrary lib : sources : otherObjects { # BuildPlatformStaticLibrary : ; # Creates a static library from sources. - # : The library. + # : The static library to be built. # : List of source files. + # : List of additional object files. + # - local lib = $(1) ; - local sources = $(2) ; local objects = [ FGristFiles $(sources:S=$(SUFOBJ)) ] ; PLATFORM on $(lib) = host ; @@ -655,6 +656,6 @@ rule BuildPlatformStaticLibrary USES_BE_API on $(objects) = $(usesBeAPI) ; } - StaticLibrary $(lib) : $(sources) ; + StaticLibrary $(lib) : $(sources) : $(otherObjects) ; } diff --git a/build/jam/OverriddenJamRules b/build/jam/OverriddenJamRules index dd3ec73aff..1712f81b69 100644 --- a/build/jam/OverriddenJamRules +++ b/build/jam/OverriddenJamRules @@ -37,6 +37,12 @@ rule Link SetType $(1) ; MimeSet $(1) ; SetVersion $(1) ; + + # If the generic attribute emulation is enabled, make sure the tool to + # remove the attributes is built first. + if $(HOST_RM_ATTRS_TARGET) { + Depends $(1) : $(HOST_RM_ATTRS_TARGET) ; + } } } diff --git a/build/scripts/build_haiku_image b/build/scripts/build_haiku_image index ec1405d5bc..ac4e45c726 100755 --- a/build/scripts/build_haiku_image +++ b/build/scripts/build_haiku_image @@ -21,6 +21,7 @@ # makebootable # resattr # rc +# rmAttrs # unzip # vmdkheader # @@ -59,20 +60,6 @@ else fi -# attribute-safe rm -rf -# This makes sure there are no leftover attribute file before removing each file -attrrmrf() -{ - test -e "$1" || return - if [ -d "$outputDir/attributes" ]; then - # test for gnu stat, else fallback to the bsd one. - statFormatOpt="-c" - stat -c '%i' . >/dev/null 2>&1 || statFormatOpt="-f" - find "$1" -print0 | xargs -0 stat $statFormatOpt %i | awk "{ print \"$outputDir/attributes/\" \$1 }" | xargs rm -rf - fi - rm -rf "$1" -} - unzipFile() { # unzipFile @@ -83,13 +70,13 @@ unzipFile() if [ $isImage ]; then unzipDir=$tmpDir/unzip - attrrmrf "$unzipDir" + $rmAttrs -rf "$unzipDir" mkdir -p "$unzipDir" $unzip -q -d "$unzipDir" "$zipFile" $cp -r "${sPrefix}$unzipDir/." "${tPrefix}$targetUnzipDir" - attrrmrf "$unzipDir" + $rmAttrs -rf "$unzipDir" else $unzip -q -o -d "${tPrefix}$targetUnzipDir" "${sPrefix}$zipFile" fi @@ -192,7 +179,7 @@ if [ ! $updateOnly ]; then done # cleanup tmp dir - attrrmrf $mimeTmpDir + $rmAttrs -rf $mimeTmpDir fi # ! updateOnly diff --git a/build/scripts/rm_attrs b/build/scripts/rm_attrs new file mode 100755 index 0000000000..1b76bb6bfa --- /dev/null +++ b/build/scripts/rm_attrs @@ -0,0 +1,15 @@ +#!/bin/sh + +if [ $# -lt 2 ]; then + echo "$0: Usage:..." + exit 1; +fi + +rmAttrs=$1 +shift + +if [ -f $rmAttrs ]; then + $rmAttrs $@ +else + rm $@ +fi diff --git a/src/tools/Jamfile b/src/tools/Jamfile index 104468b3de..8f1151be94 100644 --- a/src/tools/Jamfile +++ b/src/tools/Jamfile @@ -11,6 +11,7 @@ local tools = listattr mimeset mkindex + rm_attrs_tmp rmattr settype setversion @@ -56,6 +57,14 @@ BuildPlatformMain mimeset : BuildPlatformMain mkindex : mkindex.cpp : $(HOST_LIBBE) ; +# We want rm_attrs to be self-contained, so we link against the static libroot. +HOST_LIBROOT on rm_attrs_tmp = $(HOST_STATIC_LIBROOT) ; +BuildPlatformMain rm_attrs_tmp : rm_attrs.cpp + : $(HOST_LIBSUPC++) $(HOST_LIBSTDC++) ; +MakeLocateDebug rm_attrs ; +File rm_attrs : rm_attrs_tmp ; +MODE on rm_attrs = 755 ; + BuildPlatformMain rmattr : rmattr.cpp : $(HOST_LIBBE) ; BuildPlatformMain set_haiku_revision : set_haiku_revision.cpp diff --git a/src/tools/rm_attrs.cpp b/src/tools/rm_attrs.cpp new file mode 100644 index 0000000000..49a696ed45 --- /dev/null +++ b/src/tools/rm_attrs.cpp @@ -0,0 +1,231 @@ +/* + * Copyright 2008, Ingo Weinhold, ingo_weinhold@gmx.de. + * Distributed under the terms of the MIT License. + */ + +#include +#include +#include +#include +#include +#include +#include +#include + + +// exported by the generic attribute support in libroot_build.so +extern "C" bool __get_attribute_dir_path(const struct stat* st, char* buffer); + + +class Path { +public: + bool Init(const char* path) + { + size_t len = strlen(path); + if (len == 0 || len >= PATH_MAX) + return false; + + strcpy(fPath, path); + fPathLen = len; + + return true; + } + + const char* GetPath() const + { + return fPath; + } + + char* Buffer() + { + return fPath; + } + + void BufferChanged() + { + fPathLen = strlen(fPath); + } + + bool PushLeaf(const char* leaf) + { + size_t leafLen = strlen(leaf); + + int separatorLen = (fPath[fPathLen - 1] == '/' ? 0 : 1); + if (fPathLen + separatorLen + leafLen >= PATH_MAX) + return false; + + if (separatorLen > 0) + fPath[fPathLen++] = '/'; + + strcpy(fPath + fPathLen, leaf); + fPathLen += leafLen; + + return true; + } + + bool PopLeaf() + { + char* lastSlash = strrchr(fPath, '/'); + if (lastSlash == NULL || lastSlash == fPath) + return false; + + *lastSlash = '\0'; + fPathLen = lastSlash - fPath; + + return true; + } + + char fPath[PATH_MAX]; + size_t fPathLen; +}; + + +static bool remove_entry(Path& entry, bool recursive, bool force, + bool removeAttributes); + + +static void +remove_dir_contents(Path& path, bool force, bool removeAttributes) +{ + // open the dir + DIR* dir = opendir(path.GetPath()); + if (dir < 0) { + fprintf(stderr, "Error: Failed to open dir \"%s\": %s\n", + path.GetPath(), strerror(errno)); + return; + } + + // iterate through the entries + errno = 0; + while (dirent* entry = readdir(dir)) { + // skip "." and ".." + if (strcmp(entry->d_name, ".") == 0 || strcmp(entry->d_name, "..") == 0) + continue; + + if (!path.PushLeaf(entry->d_name)) { + fprintf(stderr, "Error: Path name of entry too long: dir: \"%s\", " + "entry: \"%s\"\n", path.GetPath(), entry->d_name); + continue; + } + + remove_entry(path, true, force, removeAttributes); + + path.PopLeaf(); + + errno = 0; + } + + if (errno != 0) { + fprintf(stderr, "Error: Failed to read directory \"%s\": %s\n", + path.GetPath(), strerror(errno)); + } + + // close + closedir(dir); +} + + +static bool +remove_entry(Path& path, bool recursive, bool force, bool removeAttributes) +{ + // stat the file + struct stat st; + if (lstat(path.GetPath(), &st) < 0) { + // errno == 0 shouldn't happen, but found on OpenSUSE Linux 10.3 + if (force && (errno == ENOENT || errno == 0)) + return true; + + fprintf(stderr, "Error: Failed to remove \"%s\": %s\n", path.GetPath(), + strerror(errno)); + return false; + } + + // remove the file's attributes + if (removeAttributes) { + Path attrDirPath; + if (__get_attribute_dir_path(&st, attrDirPath.Buffer())) { + attrDirPath.BufferChanged(); + remove_entry(attrDirPath, true, true, false); + } + } + + if (S_ISDIR(st.st_mode)) { + if (!recursive) { + fprintf(stderr, "Error: \"%s\" is a directory.\n", path.GetPath()); + return false; + } + + // remove the contents + remove_dir_contents(path, force, removeAttributes); + + // remove the directory + if (rmdir(path.GetPath()) < 0) { + fprintf(stderr, "Error: Failed to remove directory \"%s\": %s\n", + path.GetPath(), strerror(errno)); + return false; + } + } else { + // remove the entry + if (unlink(path.GetPath()) < 0) { + fprintf(stderr, "Error: Failed to remove entry \"%s\": %s\n", + path.GetPath(), strerror(errno)); + return false; + } + } + + return true; +} + + +int +main(int argc, const char* const* argv) +{ + bool recursive = false; + bool force = false; + + // parse parameters + int argi = 1; + for (argi = 1; argi < argc; argi++) { + const char *arg = argv[argi]; + if (arg[0] != '-') + break; + + if (arg[1] == '\0') { + fprintf(stderr, "Error: Invalid option \"-\"\n"); + exit(1); + } + + for (int i = 1; arg[i]; i++) { + switch (arg[i]) { + case 'f': + force = true; + break; + case 'r': + recursive = true; + break; + default: + fprintf(stderr, "Error: Unknown option \"-%c\"\n", arg[i]); + exit(1); + } + } + } + + // check params + if (argi >= argc) { + fprintf(stderr, "Usage: %s [ -rf ] ...\n", argv[0]); + exit(1); + } + + // remove loop + for (; argi < argc; argi++) { + Path path; + if (!path.Init(argv[argi])) { + fprintf(stderr, "Error: Invalid path: \"%s\".\n", argv[argi]); + continue; + } + + remove_entry(path, recursive, force, true); + } + + return 0; +}