Index: trunk/src/kmk/Makefile.am
===================================================================
--- trunk/src/kmk/Makefile.am	(revision 1597)
+++ trunk/src/kmk/Makefile.am	(revision 1598)
@@ -75,4 +75,5 @@
 		kmkbuiltin/strlcpy.c \
 		kmkbuiltin/osdep.c \
+		kmkbuiltin/kbuild_protection.c \
 		kmkbuiltin/kbuild_version.c
 
Index: trunk/src/kmk/Makefile.kmk
===================================================================
--- trunk/src/kmk/Makefile.kmk	(revision 1597)
+++ trunk/src/kmk/Makefile.kmk	(revision 1598)
@@ -82,4 +82,5 @@
 	kmkbuiltin/strmode.c \
 	kmkbuiltin/kbuild_version.c \
+	kmkbuiltin/kbuild_protection.c \
 	getopt.c \
 	getopt1.c \
Index: trunk/src/kmk/kmkbuiltin/kbuild_protection.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/kbuild_protection.c	(revision 1598)
+++ trunk/src/kmk/kmkbuiltin/kbuild_protection.c	(revision 1598)
@@ -0,0 +1,369 @@
+/* $Id$ */
+/** @file
+ * Simple File Protection.
+ */
+
+/*
+ * Copyright (c) 2008 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+
+/*******************************************************************************
+*   Header Files                                                               *
+*******************************************************************************/
+#include <sys/types.h>
+#include <stdlib.h>
+#include <string.h>
+#include <ctype.h>
+#include <assert.h>
+#include "kbuild_protection.h"
+
+
+/*******************************************************************************
+*   Defined Constants And Macros                                               *
+*******************************************************************************/
+#define KBUILD_PROTECTION_MAGIC     0x00111100
+
+#if defined(__EMX__) || defined(_MSC_VER)
+# define IS_SLASH(ch)               ( (ch) == '/' || (ch) == '\\' )
+# define DEFAULT_PROTECTION_DEPTH   1
+#else
+# define IS_SLASH(ch)               ( (ch) == '/' )
+# define DEFAULT_PROTECTION_DEPTH   2
+#endif
+
+
+
+/**
+ * Counts the components in the specified sub path.
+ * This is a helper for count_path_components.
+ *
+ * etc = 1
+ * etc/ = 1
+ * etc/x11 = 2
+ * and so and and so forth.
+ */
+static int countSubPathComponents(const char *pszPath, int cDepth)
+{
+    for (;;)
+    {
+        const char *pszEnd;
+        size_t cch;
+
+        /* skip slashes. */
+        while (IS_SLASH(*pszPath))
+            pszPath++;
+        if (!*pszPath)
+            break;
+
+        /* find end of component. */
+        pszEnd = pszPath;
+        while (!IS_SLASH(*pszEnd) && *pszEnd)
+            pszEnd++;
+
+        /* count it, checking for '..' and '.'. */
+        cch = pszEnd - pszPath;
+        if (cch == 2 && pszPath[0] == '.' && pszPath[1] == '.')
+        {
+            if (cDepth > 0)
+                cDepth--;
+        }
+        else if (cch != 1 || pszPath[0] != '.')
+            cDepth++;
+
+        /* advance */
+        if (!*pszEnd)
+            break;
+        pszPath = pszEnd + 1;
+    }
+    return cDepth;
+}
+
+
+/**
+ * Parses the specified path counting the number of components
+ * relative to root.
+ *
+ * We don't check symbolic links and such, just some simple and cheap
+ * path parsing.
+ *
+ * @param   pszPath     The path to process.
+ *
+ * @returns 0 or higher on success.
+ *          On failure an error is printed, eval is set and -1 is returned.
+ */
+static int countPathComponents(const char *pszPath)
+{
+    int cComponents = 0;
+
+    /*
+     * Deal with root, UNC, drive letter.
+ */
+#if defined(_MSC_VER) || defined(__OS2__)
+    if (IS_SLASH(pszPath[0]) && IS_SLASH(pszPath[1]) && !IS_SLASH(pszPath[2]))
+    {
+        /* skip the root - UNC */
+        pszPath += 3;
+        while (!IS_SLASH(*pszPath) && *pszPath) /* server name */
+            pszPath++;
+        while (IS_SLASH(*pszPath))
+            pszPath++;
+        while (!IS_SLASH(*pszPath) && *pszPath) /* share name */
+            pszPath++;
+        while (IS_SLASH(*pszPath))
+            pszPath++;
+    }
+    else
+    {
+        unsigned uDriveLetter = (unsigned)toupper(pszPath[0]) - (unsigned)'A';
+        if (uDriveLetter <= (unsigned)('Z' - 'A') && pszPath[1] == ':')
+            uDriveLetter++; /* A == 1 */
+        else
+            uDriveLetter = 0; /* 0 == default */
+
+        if (!IS_SLASH(pszPath[uDriveLetter ? 2 : 0]))
+        {
+            /*
+             * Relative path, must count cwd depth first.
+             */
+#ifdef __OS2__ /** @todo remove when ticket 194 has been fixed */
+            char *pszCwd = _getdcwd(uDriveLetter, NULL, PATH_MAX);
+#else
+            char *pszCwd = _getdcwd(uDriveLetter, NULL, 0);
+#endif
+            char *pszTmp = pszCwd;
+            if (!pszTmp)
+            {
+                err(1, "_getdcwd");
+                return -1;
+            }
+
+            if (IS_SLASH(pszTmp[0]) && IS_SLASH(pszTmp[1]))
+            {
+                /* skip the root - UNC */
+                pszTmp += 2;
+                while (!IS_SLASH(*pszTmp) && *pszTmp) /* server name */
+                    pszTmp++;
+                while (IS_SLASH(*pszTmp))
+                    pszTmp++;
+                while (!IS_SLASH(*pszTmp) && *pszTmp) /* share name */
+                    pszTmp++;
+            }
+            else
+            {
+                /* skip the drive letter and while we're at it, the root slash too. */
+                pszTmp += 1 + (pszTmp[1] == ':');
+            }
+            cComponents = countSubPathComponents(pszTmp, 0);
+            free(pszCwd);
+        }
+        else
+        {
+            /* skip the drive letter and while we're at it, the root slash too. */
+            pszPath += uDriveLetter ? 3 : 1;
+        }
+    }
+#else
+    if (!IS_SLASH(pszPath[0]))
+    {
+        /*
+         * Relative path, must count cwd depth first.
+         */
+        char szCwd[4096];
+        if (!getcwd(szCwd, sizeof(szCwd)))
+        {
+            err(1, "getcwd");
+            return -1;
+        }
+        cComponents = countSubPathComponents(szCwd, 0);
+    }
+#endif
+
+    /*
+     * We're now past any UNC or drive letter crap, possibly positioned
+     * at the root slash or at the start of a path component at the
+     * given depth. Count the remainder.
+     */
+    return countSubPathComponents(pszPath, cComponents);
+}
+
+
+/**
+ * Initializes the instance data.
+ *
+ * @param   pThis   Pointer to the instance data.
+ */
+void kBuildProtectionInit(PKBUILDPROTECTION pThis)
+{
+    pThis->uMagic = KBUILD_PROTECTION_MAGIC;
+    pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] = 0;
+    pThis->afTypes[KBUILDPROTECTIONTYPE_RECURSIVE] = 1;
+    pThis->cProtectionDepth = DEFAULT_PROTECTION_DEPTH;
+}
+
+
+/**
+ * Destroys the instance data.
+ *
+ * @param   pThis   Pointer to the instance data.
+ */
+void kBuildProtectionTerm(PKBUILDPROTECTION pThis)
+{
+    pThis->uMagic = 0;
+}
+
+
+void kBuildProtectionEnable(PKBUILDPROTECTION pThis, KBUILDPROTECTIONTYPE enmType)
+{
+    assert(pThis->uMagic == KBUILD_PROTECTION_MAGIC);
+    assert(enmType < KBUILDPROTECTIONTYPE_MAX && enmType >= KBUILDPROTECTIONTYPE_FIRST);
+    pThis->afTypes[enmType] |= 1;
+}
+
+
+void kBuildProtectionDisable(PKBUILDPROTECTION pThis, KBUILDPROTECTIONTYPE enmType)
+{
+    assert(pThis->uMagic == KBUILD_PROTECTION_MAGIC);
+    assert(enmType < KBUILDPROTECTIONTYPE_MAX && enmType >= KBUILDPROTECTIONTYPE_FIRST);
+    pThis->afTypes[enmType] &= ~1U;
+}
+
+
+/**
+ * Sets the protection depth according to the option argument.
+ *
+ * @param   pszValue    The value.
+ *
+ * @returns 0 on success, -1 and errx on failure.
+ */
+int  kBuildProtectionSetDepth(PKBUILDPROTECTION pThis, const char *pszValue)
+{
+    /* skip leading blanks, they don't count either way. */
+    while (isspace(*pszValue))
+        pszValue++;
+
+    /* number or path? */
+    if (!isdigit(*pszValue) || strpbrk(pszValue, ":/\\"))
+        pThis->cProtectionDepth = countPathComponents(pszValue);
+    else
+    {
+        char *pszMore = 0;
+        pThis->cProtectionDepth = strtol(pszValue, &pszMore, 0);
+        if (pThis->cProtectionDepth != 0 && pszMore)
+        {
+            /* trailing space is harmless. */
+            while (isspace(*pszMore))
+                pszMore++;
+        }
+        if (!pThis->cProtectionDepth || pszValue == pszMore || *pszMore)
+            return errx(1, "bogus protection depth: %s", pszValue);
+    }
+
+    if (pThis->cProtectionDepth < 1)
+        return  errx(1, "bogus protection depth: %s", pszValue);
+    return 0;
+}
+
+
+/**
+ * Scans the environment for option overrides.
+ *
+ * @param   pThis       Pointer to the instance data.
+ * @param   papszEnv    The environment array.
+ * @param   pszPrefix   The variable prefix.
+ *
+ * @returns 0 on success, -1 and err*() on failure.
+ */
+int  kBuildProtectionScanEnv(PKBUILDPROTECTION pThis, char **papszEnv, const char *pszPrefix)
+{
+    unsigned i;
+    const size_t cchPrefix = strlen(pszPrefix);
+
+    for (i = 0; papszEnv[i]; i++)
+    {
+        const char *pszVar = papszEnv[i];
+        if (!strncmp(pszVar, pszPrefix, cchPrefix))
+        {
+            pszVar += cchPrefix;
+            if (!strncmp(pszVar, "PROTECTION_DEPTH=", sizeof("PROTECTION_DEPTH=") - 1))
+            {
+                const char *pszVal = pszVar + sizeof("PROTECTION_DEPTH=") - 1;
+                if (kBuildProtectionSetDepth(pThis, pszVal))
+                    return -1;
+            }
+            else if (!strncmp(pszVar, "DISABLE_PROTECTION=", sizeof("DISABLE_PROTECTION=") - 1))
+                pThis->afTypes[KBUILDPROTECTIONTYPE_RECURSIVE] &= ~1U;
+            else if (!strncmp(pszVar, "ENABLE_PROTECTION=", sizeof("ENABLE_PROTECTION=") - 1))
+                pThis->afTypes[KBUILDPROTECTIONTYPE_RECURSIVE] |= 3;
+            else if (!strncmp(pszVar, "DISABLE_FULL_PROTECTION=", sizeof("DISABLE_FULL_PROTECTION=") - 1))
+                pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] &= ~1U;
+            else if (!strncmp(pszVar, "ENABLE_FULL_PROTECTION=", sizeof("ENABLE_FULL_PROTECTION=") - 1))
+                pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] |= 3;
+        }
+    }
+    return 0;
+}
+
+
+/**
+ * Protect the upper layers of the file system against accidental
+ * or malicious deletetion attempt from within a makefile.
+ *
+ * @param   pszPath             The path to check.
+ * @param   required_depth      The minimum number of components in the
+ *                              path counting from the root.
+ *
+ * @returns 0 on success.
+ *          On failure an error is printed and -1 is returned.
+ */
+int  kBuildProtectionEnforce(PCKBUILDPROTECTION pThis, KBUILDPROTECTIONTYPE enmType, const char *pszPath)
+{
+    assert(pThis->uMagic == KBUILD_PROTECTION_MAGIC);
+    assert(enmType < KBUILDPROTECTIONTYPE_MAX && enmType >= KBUILDPROTECTIONTYPE_FIRST);
+
+    if (   (pThis->afTypes[enmType] & 3)
+        || (pThis->afTypes[KBUILDPROTECTIONTYPE_FULL] & 3))
+    {
+        /*
+         * Count the path and compare it with the required depth.
+         */
+        int cComponents = countPathComponents(pszPath);
+        if (cComponents < 0)
+            return -1;
+        if (cComponents <= pThis->cProtectionDepth)
+        {
+            errx(1, "%s: protected", pszPath);
+            return -1;
+        }
+    }
+    return 0;
+}
+
+
+/**
+ * Retrieve the default path protection depth.
+ *
+ * @returns the default value.
+ */
+int  kBuildProtectionDefaultDepth(void)
+{
+    return DEFAULT_PROTECTION_DEPTH;
+}
+
Index: trunk/src/kmk/kmkbuiltin/kbuild_protection.h
===================================================================
--- trunk/src/kmk/kmkbuiltin/kbuild_protection.h	(revision 1598)
+++ trunk/src/kmk/kmkbuiltin/kbuild_protection.h	(revision 1598)
@@ -0,0 +1,66 @@
+/* $Id$ */
+/** @file
+ * Simple File Protection.
+ */
+
+/*
+ * Copyright (c) 2008 knut st. osmundsen <bird-src-spam@anduin.net>
+ *
+ * This file is part of kBuild.
+ *
+ * kBuild is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * kBuild is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with kBuild; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
+ *
+ */
+
+#ifndef ___kbuild_protection_h___
+#define ___kbuild_protection_h___
+
+/**
+ * The different protection types.
+ */
+typedef enum
+{
+    KBUILDPROTECTIONTYPE_FIRST = 0,
+    KBUILDPROTECTIONTYPE_RECURSIVE = KBUILDPROTECTIONTYPE_FIRST,
+    KBUILDPROTECTIONTYPE_FULL,
+    KBUILDPROTECTIONTYPE_MAX
+} KBUILDPROTECTIONTYPE;
+
+
+/**
+ * The instance data.
+ * Don't touch.
+ */
+typedef struct KBUILDPROTECTION
+{
+    unsigned        uMagic;
+    unsigned        cProtectionDepth;
+    unsigned char   afTypes[KBUILDPROTECTIONTYPE_MAX];
+} KBUILDPROTECTION;
+typedef KBUILDPROTECTION  *PKBUILDPROTECTION;
+typedef const KBUILDPROTECTION *PCKBUILDPROTECTION;
+
+
+void kBuildProtectionInit(PKBUILDPROTECTION pThis);
+void kBuildProtectionTerm(PKBUILDPROTECTION pThis);
+int  kBuildProtectionScanEnv(PKBUILDPROTECTION pThis, char **papszEnv, const char *pszPrefix);
+void kBuildProtectionEnable(PKBUILDPROTECTION pThis, KBUILDPROTECTIONTYPE enmType);
+void kBuildProtectionDisable(PKBUILDPROTECTION pThis, KBUILDPROTECTIONTYPE enmType);
+int  kBuildProtectionSetDepth(PKBUILDPROTECTION pThis, const char *pszValue);
+int  kBuildProtectionEnforce(PCKBUILDPROTECTION pThis, KBUILDPROTECTIONTYPE enmType, const char *pszPath);
+int  kBuildProtectionDefaultDepth(void);
+
+#endif
+
Index: trunk/src/kmk/kmkbuiltin/rm.c
===================================================================
--- trunk/src/kmk/kmkbuiltin/rm.c	(revision 1597)
+++ trunk/src/kmk/kmkbuiltin/rm.c	(revision 1598)
@@ -67,6 +67,7 @@
 # include <direct.h>
 # include <limits.h>
-#endif 
+#endif
 #include "kmkbuiltin.h"
+#include "kbuild_protection.h"
 
 #if defined(__EMX__) || defined(_MSC_VER)
@@ -94,9 +95,9 @@
 #endif
 
-static int protectionflag, fullprotectionflag, protectiondepth;
 static int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok;
 static uid_t uid;
 
 static char *argv0;
+static KBUILDPROTECTION g_ProtData;
 
 static struct option long_options[] =
@@ -115,7 +116,7 @@
 static int	check(char *, char *, struct stat *);
 static void	checkdot(char **);
-static void	rm_file(char **);
+static int	rm_file(char **);
 static int	rm_overwrite(char *, struct stat *);
-static void	rm_tree(char **);
+static int	rm_tree(char **);
 static int	count_path_components(const char *);
 static int  set_protection_depth(const char *);
@@ -140,8 +141,6 @@
 	argv0 = argv[0];
 	dflag = eval = fflag = iflag = Pflag = vflag = Wflag = stdin_ok = 0;
-	fullprotectionflag = 0;
-	protectionflag = 1;
-	protectiondepth = DEFAULT_PROTECTION_DEPTH;
 	uid = 0;
+	kBuildProtectionInit(&g_ProtData);
 
 	/* kmk: reset getopt and set program name. */
@@ -184,25 +183,31 @@
 #endif
 		case 261:
+			kBuildProtectionTerm(&g_ProtData);
 			usage(stdout);
 			return 0;
 		case 262:
+			kBuildProtectionTerm(&g_ProtData);
 			return kbuild_version(argv[0]);
 		case 263:
-			protectionflag = 0;
+			kBuildProtectionDisable(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
 			break;
 		case 264:
-			protectionflag = 1;
+			kBuildProtectionEnable(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE);
 			break;
 		case 265:
-			fullprotectionflag = 1;
+			kBuildProtectionEnable(&g_ProtData, KBUILDPROTECTIONTYPE_FULL);
 			break;
 		case 266:
-			fullprotectionflag = 0;
+			kBuildProtectionDisable(&g_ProtData, KBUILDPROTECTIONTYPE_FULL);
 			break;
 		case 267:
-			set_protection_depth(optarg);
+			if (kBuildProtectionSetDepth(&g_ProtData, optarg)) {
+			    kBuildProtectionTerm(&g_ProtData);
+			    return 1;
+			}
 			break;
 		case '?':
 		default:
+			kBuildProtectionTerm(&g_ProtData);
 			return usage(stderr);
 		}
@@ -211,4 +216,5 @@
 
 	if (argc < 1) {
+		kBuildProtectionTerm(&g_ProtData);
 		if (fflag)
 			return (0);
@@ -216,247 +222,24 @@
 	}
 
-	/* Search the environment for option overrides (protection). */
-	for (i = 0; envp[i]; i++) {
-		if (!strncmp(envp[i], "KMK_RM_", sizeof("KMK_RM_") - 1)) {
-			if (!strncmp(envp[i], "KMK_RM_PROTECTION_DEPTH=", sizeof("KMK_RM_PROTECTION_DEPTH=") - 1)) {
-				const char *val = envp[i] + sizeof("KMK_RM_PROTECTION_DEPTH=") - 1;
-				if (set_protection_depth(val))
-					return eval;
-			} else if (!strncmp(envp[i], "KMK_RM_DISABLE_PROTECTION=", sizeof("KMK_RM_DISABLE_PROTECTION=") - 1)) {
-				if (protectionflag >= 0)
-					protectionflag = 0;
-			} else if (!strncmp(envp[i], "KMK_RM_ENABLE_PROTECTION=", sizeof("KMK_RM_ENABLE_PROTECTION=") - 1)) {
-				protectionflag = -1;
-			} else if (!strncmp(envp[i], "KMK_RM_DISABLE_FULL_PROTECTION=", sizeof("KMK_RM_DISABLE_FULL_PROTECTION=") - 1)) {
-				if (fullprotectionflag >= 0)
-					fullprotectionflag = 0;
-			} else if (!strncmp(envp[i], "KMK_RM_ENABLE_FULL_PROTECTION=", sizeof("KMK_RM_ENABLE_FULL_PROTECTION=") - 1)) {
-				fullprotectionflag = protectionflag = -1;
-			}
-		}
-	}
-	if (fullprotectionflag)
-		protectionflag = 1;
-
-	checkdot(argv);
-	uid = geteuid();
-
-	if (*argv) {
-		stdin_ok = isatty(STDIN_FILENO);
-		if (rflag)
-			rm_tree(argv);
-		else
-			rm_file(argv);
-	}
-
+	if (!kBuildProtectionScanEnv(&g_ProtData, envp, "KMK_RM_")) {
+		checkdot(argv);
+		uid = geteuid();
+
+		if (*argv) {
+			stdin_ok = isatty(STDIN_FILENO);
+			if (rflag)
+				eval |= rm_tree(argv);
+			else
+				eval |= rm_file(argv);
+		}
+	} else {
+		eval = 1;
+	}
+
+	kBuildProtectionTerm(&g_ProtData);
 	return eval;
 }
 
-/**
- * Sets protectiondepth according to the option argument.
- *
- * @returns eval, that is 0 on success and non-zero on failure
- *
- * @param   val		The value.
- */
 static int
-set_protection_depth(const char *val)
-{
-	/* skip leading blanks, they don't count either way. */
-	while (isspace(*val))
-		val++;
-
-	/* number or path? */
-	if (!isdigit(*val) || strpbrk(val, ":/\\")) {
-		protectiondepth = count_path_components(val);
-	} else {
-		char *more = 0;
-		protectiondepth = strtol(val, &more, 0);
-		if (protectiondepth != 0 && more) {
-			/* trailing space is harmless. */
-			while (isspace(*more))
-				more++;
-		}
-		if (!protectiondepth || val == more || *more)
-			return eval = errx(1, "bogus protection depth: %s", val);
-	}
-
-	if (protectiondepth < 1)
-		return eval = errx(1, "bogus protection depth: %s", val);
-	return eval;
-}
-
-/**
- * Counts the components in the specified sub path.
- * This is a helper for count_path_components.
- *
- * etc = 1
- * etc/ = 1
- * etc/x11 = 2
- * and so and and so forth.
- */
-static int
-count_sub_path_components(const char *path, int depth)
-{
-	for (;;) {
-		const char *end;
-		size_t len;
-
-		/* skip slashes. */
-		while (IS_SLASH(*path))
-			path++;
-		if (!*path)
-			break;
-
-		/* find end of component. */
-		end = path;
-		while (!IS_SLASH(*end) && *end)
-			end++;
-
-		/* count it, checking for '..' and '.'. */
-		len = end - path;
-		if (len == 2 && path[0] == '.' && path[1] == '.') {
-			if (depth > 0)
-				depth--;
-		} else if (len != 1 || path[0] != '.') {
-			depth++;
-		}
-
-		/* advance */
-		if (!*end)
-			break;
-		path = end + 1;
-	}
-	return depth;
-}
-
-/**
- * Parses the specified path counting the number of components
- * relative to root.
- *
- * We don't check symbolic links and such, just some simple and cheap
- * path parsing.
- *
- * @param   path                The path to process.
- *
- * @returns 0 or higher on success.
- *          On failure an error is printed, eval is set and -1 is returned.
- */
-static int
-count_path_components(const char *path)
-{
-	int components = 0;
-
-	/*
-	 * Deal with root, UNC, drive letter.
-     */
-#if defined(_MSC_VER) || defined(__OS2__)
-	if (IS_SLASH(path[0]) && IS_SLASH(path[1]) && !IS_SLASH(path[2])) {
-		/* skip the root - UNC */
-		path += 3;
-		while (!IS_SLASH(*path) && *path) /* server name */
-			path++;
-		while (IS_SLASH(*path))
-			path++;
-		while (!IS_SLASH(*path) && *path) /* share name */
-			path++;
-		while (IS_SLASH(*path))
-			path++;
-	} else {
-		unsigned drive_letter = (unsigned)toupper(path[0]) - (unsigned)'A';
-		if (drive_letter <= (unsigned)('Z' - 'A') && path[1] == ':') {
-			drive_letter++; /* A == 1 */
-		} else {
-			drive_letter = 0; /* 0 == default */
-		}
-
-		if (!IS_SLASH(path[drive_letter ? 2 : 0])) {
-			/*
-			 * Relative path, must count cwd depth first.
-			 */
-#ifdef __OS2__ /** @todo remove when ticket 194 has been fixed */
-			char *cwd = _getdcwd(drive_letter, NULL, PATH_MAX);
-#else
-			char *cwd = _getdcwd(drive_letter, NULL, 0);
-#endif
-			char *tmp = cwd;
-			if (!tmp) {
-				eval = err(1, "_getdcwd");
-				return -1;
-			}
-
-			if (IS_SLASH(tmp[0]) && IS_SLASH(tmp[1])) {
-				/* skip the root - UNC */
-				tmp += 2;
-				while (!IS_SLASH(*tmp) && *tmp) /* server name */
-					tmp++;
-				while (IS_SLASH(*tmp))
-					tmp++;
-				while (!IS_SLASH(*tmp) && *tmp) /* share name */
-					tmp++;
-			} else {
-				/* skip the drive letter and while we're at it, the root slash too. */
-				tmp += 1 + (tmp[1] == ':');
-			}
-			components = count_sub_path_components(tmp, 0);
-			free(cwd);
-		} else {
-			/* skip the drive letter and while we're at it, the root slash too. */
-			path += drive_letter ? 3 : 1;
-		}
-	}
-#else
-	if (!IS_SLASH(path[0])) {
-		/*
-		 * Relative path, must count cwd depth first.
-         */
-		char cwd[4096];
-		if (!getcwd(cwd, sizeof(cwd))) {
-			eval = err(1, "getcwd");
-			return -1;
-		}
-		components = count_sub_path_components(cwd, 0);
-	}
-#endif
-
-	/*
-	 * We're now past any UNC or drive letter crap, possibly positioned
-	 * at the root slash or at the start of a path component at the
-	 * given depth. Count the remainder.
-	 */
-	return count_sub_path_components(path, components);
-}
-
-
-/**
- * Protect the upper layers of the file system against accidental
- * or malicious deletetion attempt from within a makefile.
- *
- * @param   path                The path to check.
- * @param   required_depth      The minimum number of components in the
- *                              path counting from the root.
- *
- * @returns 0 on success.
- *          On failure an error is printed, eval is set and -1 is returned.
- */
-static int
-enforce_protection(const char *path, int required_depth)
-{
-	int components;
-
-	/*
-	 * Count the path and compare it with the required depth.
-     */
-	components = count_path_components(path);
-	if (components < 0)
-		return -1;
-	if (components < required_depth) {
-		eval = errx(1, "%s: protected", path);
-		return -1;
-	}
-	return 0;
-}
-
-static void
 rm_tree(char **argv)
 {
@@ -471,9 +254,8 @@
 	 * everything, but we'll check the individual items later.
 	 */
-	if (protectionflag) {
-		int i;
-		for (i = 0; argv[i]; i++) {
-			if (enforce_protection(argv[i], protectiondepth + 1))
-				return;
+	int i;
+	for (i = 0; argv[i]; i++) {
+		if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE, argv[i])) {
+			return 1;
 		}
 	}
@@ -499,6 +281,5 @@
 #endif
 	if (!(fts = fts_open(argv, flags, NULL))) {
-		eval = err(1, "fts_open");
-		return;
+		return err(1, "fts_open");
 	}
 	while ((p = fts_read(fts)) != NULL) {
@@ -512,7 +293,6 @@
 			continue;
 		case FTS_ERR:
-			eval = errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
 			fts_close(fts);
-			return;
+			return errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
 		case FTS_NS:
 			/*
@@ -558,7 +338,7 @@
 		 * Protect against deleting root files and directories.
 		 */
-		if (protectionflag && enforce_protection(p->fts_accpath, protectiondepth + 1)) {
+		if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_RECURSIVE, p->fts_accpath)) {
 			fts_close(fts);
-			return;
+			return 1;
 		}
 
@@ -640,7 +420,8 @@
 	}
 	fts_close(fts);
+	return eval;
 }
 
-static void
+static int
 rm_file(char **argv)
 {
@@ -652,10 +433,8 @@
 	 * Check up front before anything is deleted.
 	 */
-	if (fullprotectionflag) {
-		int i;
-		for (i = 0; argv[i]; i++) {
-			if (enforce_protection(argv[i], protectiondepth + 1))
-				return;
-		}
+	int i;
+	for (i = 0; argv[i]; i++) {
+		if (kBuildProtectionEnforce(&g_ProtData, KBUILDPROTECTIONTYPE_FULL, argv[i]))
+			return 1;
 	}
 
@@ -714,5 +493,5 @@
 #ifdef _MSC_VER
 				if (rval != 0) {
-    					chmod(f, 0777);
+					chmod(f, 0777);
 					rval = unlink(f);
 				}
@@ -727,4 +506,5 @@
 			(void)printf("%s\n", f);
 	}
+	return eval;
 }
 
@@ -836,16 +616,16 @@
 		if ((flagsp = fflagstostr(sp->st_flags)) == NULL)
 			exit(err(1, "fflagstostr"));
-                (void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ",
-                    modep + 1, modep[9] == ' ' ? "" : " ",
-                    user_from_uid(sp->st_uid, 0),
-                    group_from_gid(sp->st_gid, 0),
-                    *flagsp ? flagsp : "", *flagsp ? " " : "",
-                    path);
+		(void)fprintf(stderr, "override %s%s%s/%s %s%sfor %s? ",
+		              modep + 1, modep[9] == ' ' ? "" : " ",
+		              user_from_uid(sp->st_uid, 0),
+		              group_from_gid(sp->st_gid, 0),
+		              *flagsp ? flagsp : "", *flagsp ? " " : "",
+		              path);
 		free(flagsp);
 #else
-                (void)flagsp;
-                (void)fprintf(stderr, "override %s%s %d/%d for %s? ",
-                    modep + 1, modep[9] == ' ' ? "" : " ",
-                    sp->st_uid, sp->st_gid, path);
+		(void)flagsp;
+		(void)fprintf(stderr, "override %s%s %d/%d for %s? ",
+		              modep + 1, modep[9] == ' ' ? "" : " ",
+		              sp->st_uid, sp->st_gid, path);
 #endif
 	}
@@ -951,5 +731,5 @@
 		,
 		g_progname, g_progname, g_progname,
-		DEFAULT_PROTECTION_DEPTH, DEFAULT_PROTECTION_DEPTH);
+		kBuildProtectionDefaultDepth(), kBuildProtectionDefaultDepth());
 	return EX_USAGE;
 }
