VirtualBox

Changeset 1550 in kBuild for trunk/src/kmk/kmkbuiltin/rm.c


Ignore:
Timestamp:
Apr 22, 2008 11:40:38 PM (17 years ago)
Author:
bird
Message:

Enabled rm -R.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/kmk/kmkbuiltin/rm.c

    r1328 r1550  
    5454#include <errno.h>
    5555#include <fcntl.h>
    56 #ifdef DO_RMTREE
    57 # include <fts.h>
    58 #endif
     56#include <fts.h>
    5957#include <grp.h>
    6058#include <pwd.h>
     
    7068#include "kmkbuiltin.h"
    7169
     70#if defined(__EMX__) || defined(_MSC_VER)
     71# define IS_SLASH(ch)   ( (ch) == '/' || (ch) == '\\' )
     72# define HAVE_DOS_PATHS 1
     73# define DEFAULT_REQUIRED_R_DEPTH 2
     74#else
     75# define IS_SLASH(ch)   ( (ch) == '/' )
     76# undef HAVE_DOS_PATHS
     77# define DEFAULT_REQUIRED_R_DEPTH 3
     78#endif
    7279
    7380#ifdef __EMX__
     
    8592#endif
    8693
     94static int protectionflag;
    8795static int dflag, eval, fflag, iflag, Pflag, vflag, Wflag, stdin_ok;
    8896static uid_t uid;
     
    94102    { "help",                                           no_argument, 0, 261 },
    95103    { "version",                                        no_argument, 0, 262 },
     104    { "disable-protection",                             no_argument, 0, 263 },
    96105    { 0, 0,     0, 0 },
    97106};
     
    102111static void     rm_file(char **);
    103112static int      rm_overwrite(char *, struct stat *);
    104 #ifdef DO_RMTREE
    105 static void     rm_tree(char **);
    106 #endif
     113static void     rm_tree(char **, int);
     114static int      count_path_components(const char *);
    107115static int      usage(FILE *);
    108116
     
    124132        argv0 = argv[0];
    125133        dflag = eval = fflag = iflag = Pflag = vflag = Wflag = stdin_ok = 0;
     134        protectionflag = 1;
    126135        uid = 0;
    127136
     
    151160                        break;
    152161                case 'R':
     162#if 0
    153163                case 'r':                       /* Compatibility. */
    154 #ifdef DO_RMTREE
     164#endif
    155165                        rflag = 1;
    156166                        break;
    157 #else
    158                         errno = EINVAL;
    159                         return err(1, "Recursion is not supported!");
    160 #endif
    161167                case 'v':
    162168                        vflag = 1;
     
    172178                case 262:
    173179                        return kbuild_version(argv[0]);
     180                case 263:
     181                        protectionflag = 0;
     182                        break;
    174183                case '?':
    175184                default:
     
    190199        if (*argv) {
    191200                stdin_ok = isatty(STDIN_FILENO);
    192 #ifdef DO_RMTREE
    193                 if (rflag)
    194                         rm_tree(argv);
    195                 else
    196 #endif
     201                if (rflag) {
     202                        /*
     203                         * Get options from the environment before doing rm_tree().
     204                         */
     205                        int required_r_depth = DEFAULT_REQUIRED_R_DEPTH;
     206                        int i;
     207                        for (i = 0; envp[i]; i++) {
     208                                if (!strncmp(envp[i], "KMK_RM_=", sizeof("KMK_RM_=") - 1)) {
     209                                        if (!strncmp(envp[i], "KMK_RM_PROTECTION_DEPTH=", sizeof("KMK_RM_PROTECTION_DEPTH=") - 1)) {
     210                                                char *ignore;
     211                                                const char *val = envp[i] + sizeof("KMK_RM_PROTECTION_DEPTH=") - 1;
     212                                                required_r_depth = isdigit(*val) ? strtol(val, &ignore, 0) : count_path_components(val);
     213                                                if (required_r_depth < 1)
     214                                                        required_r_depth = DEFAULT_REQUIRED_R_DEPTH;
     215                                        } else if (!strcmp(envp[i], "KMK_RM_DISABLE_PROTECTION=1")) {
     216                                                protectionflag = 0;
     217                                        }
     218                                }
     219                        }
     220
     221                        if (!eval)
     222                                rm_tree(argv, required_r_depth);
     223                } else {
    197224                        rm_file(argv);
     225                }
    198226        }
    199227
     
    201229}
    202230
    203 #ifdef DO_RMTREE
     231/**
     232 * Counts the components in the specified sub path.
     233 * This is a helper for count_path_components.
     234 *
     235 * etc = 1
     236 * etc/ = 1
     237 * etc/x11 = 2
     238 * and so and and so forth.
     239 */
     240static int
     241count_sub_path_components(const char *path, int depth)
     242{
     243        for (;;) {
     244                const char *end;
     245                size_t len;
     246
     247                /* skip slashes. */
     248                while (IS_SLASH(*path))
     249                        path++;
     250                if (!*path)
     251                        break;
     252
     253                /* find end of component. */
     254                end = path;
     255                while (!IS_SLASH(*end) && *end)
     256                        end++;
     257
     258                /* count it, checking for '..' and '.'. */
     259                len = end - path;
     260                if (len == 2 && path[0] == '.' && path[1] == '.') {
     261                        if (depth > 0)
     262                                depth--;
     263                } else if (len != 1 || path[0] != '.') {
     264                        depth++;
     265                }
     266
     267                /* advance */
     268                if (!*end)
     269                        break;
     270                path = end + 1;
     271        }
     272        return depth;
     273}
     274
     275/**
     276 * Parses the specified path counting the number of components
     277 * relative to root.
     278 *
     279 * We don't check symbolic links and such, just some simple and cheap
     280 * path parsing.
     281 *
     282 * @param   path                The path to process.
     283 *
     284 * @returns 0 or higher on success.
     285 *          On failure an error is printed, eval is set and -1 is returned.
     286 */
     287static int
     288count_path_components(const char *path)
     289{
     290        int components = 0;
     291
     292        /*
     293         * Deal with root, UNC, drive letter.
     294     */
     295#if defined(_MSC_VER) || defined(__OS2__)
     296    if (IS_SLASH(path[0]) && IS_SLASH(path[1]) && !IS_SLASH(path[2])) {
     297                /* skip the root - UNC */
     298                path += 3;
     299                while (!IS_SLASH(*path) && *path) /* server name */
     300                        path++;
     301                while (IS_SLASH(*path))
     302                        path++;
     303                while (!IS_SLASH(*path) && *path) /* share name */
     304                        path++;
     305                while (IS_SLASH(*path))
     306                        path++;
     307        } else {
     308                unsigned drive_letter = (unsigned)toupper(path[0]) - (unsigned)'A';
     309                if (drive_letter <= (unsigned)('Z' - 'A') && path[1] == ':') {
     310                        drive_letter++; /* A == 1 */
     311                } else {
     312                        drive_letter = 0; /* 0 == default */
     313                }
     314
     315                if (IS_SLASH(path[drive_letter ? 2 : 0])) {
     316                        /*
     317                         * Relative path, must count cwd depth first.
     318                         */
     319                        char *tmp = _getdcwd(drive_letter, NULL, 32);
     320                        if (!tmp) {
     321                                eval = err(1, "_getdcwd");
     322                                return -1;
     323                        }
     324
     325                        if (IS_SLASH(cwd[0]) && IS_SLASH(cwd[1])) {
     326                                /* skip the root - UNC */
     327                                tmp = &cwd[2];
     328                                while (!IS_SLASH(*tmp) && *tmp) /* server name */
     329                                        tmp++;
     330                                while (IS_SLASH(*tmp))
     331                                        tmp++;
     332                                while (!IS_SLASH(*tmp) && *tmp) /* share name */
     333                                        tmp++;
     334                        } else {
     335                                /* skip the drive letter and while we're at it, the root slash too. */
     336                                tmp = &cwd[1 + (cwd[1] == ':')];
     337                        }
     338                        components = count_sub_path_components(tmp, 0);
     339                        free(tmp);
     340                } else {
     341                        /* skip the drive letter and while we're at it, the root slash too. */
     342                        path += drive_letter ? 3 : 1;
     343                }
     344        }
     345#else
     346        if (!IS_SLASH(path[0])) {
     347                /*
     348                 * Relative path, must count cwd depth first.
     349         */
     350                char cwd[4096];
     351                if (!getcwd(cwd, sizeof(cwd))) {
     352                        eval = err(1, "getcwd");
     353                        return -1;
     354                }
     355                components = count_sub_path_components(cwd, 0);
     356        }
     357#endif
     358
     359        /*
     360         * We're now past any UNC or drive letter crap, possibly positioned
     361         * at the root slash or at the start of a path component at the
     362         * given depth. Count the remainder.
     363         */
     364        return count_sub_path_components(path, components);
     365}
     366
     367
     368/**
     369 * Protect the upper layers of the file system against accidental
     370 * or malicious deletetion attempt from within a makefile.
     371 *
     372 * @param   path                The path to check.
     373 * @param   required_depth      The minimum number of components in the
     374 *                              path counting from the root.
     375 *
     376 * @returns 0 on success.
     377 *          On failure an error is printed, eval is set and -1 is returned.
     378 */
     379static int
     380enforce_protection(const char *path, unsigned required_depth)
     381{
     382        int components;
     383
     384        /*
     385         * Count the path and compare it with the required depth.
     386     */
     387        components = count_path_components(path);
     388        if (components < 0)
     389                return -1;
     390        if (components < required_depth) {
     391                eval = errx(1, "%s: protected", path);
     392                return -1;
     393        }
     394        return 0;
     395}
     396
    204397static void
    205 rm_tree(char **argv)
     398rm_tree(char **argv, int required_r_depth)
    206399{
    207400        FTS *fts;
     
    210403        int flags;
    211404        int rval;
     405
     406        /*
     407         * Check up front before anything is deleted. This will not catch
     408         * everything, but we'll check the individual items later.
     409         */
     410        if (protectionflag) {
     411                int i;
     412                for (i = 0; argv[i]; i++) {
     413                        if (enforce_protection(argv[i], required_r_depth))
     414                                return;
     415                }
     416        }
    212417
    213418        /*
     
    245450                case FTS_ERR:
    246451                        eval = errx(1, "%s: %s", p->fts_path, strerror(p->fts_errno));
    247                         return;
     452                        fts_close(fts);
     453                        return;
    248454                case FTS_NS:
    249455                        /*
     
    284490                            !check(p->fts_path, p->fts_accpath, p->fts_statp))
    285491                                continue;
     492                }
     493
     494                /*
     495                 * Protect against deleting root files and directories.
     496                 */
     497                if (protectionflag && enforce_protection(p->fts_accpath, required_r_depth)) {
     498                        fts_close(fts);
     499                        return;
    286500                }
    287501
     
    358572        if (errno) {
    359573                fprintf(stderr, "%s: fts_read: %s\n", argv0, strerror(errno));
    360                 eval = 1;
    361         }
    362 }
    363 #endif /* DO_RMTREE */
     574                eval = 1;
     575        }
     576        fts_close(fts);
     577}
    364578
    365579static void
     
    577791        complained = 0;
    578792        for (t = argv; *t;) {
     793#ifdef HAVE_DOS_PATHS
     794                const char *tmp = p = *t;
     795                while (*tmp) {
     796                        switch (*tmp) {
     797                        case '/':
     798                        case '\\':
     799                        case ':':
     800                                p = (char *)tmp + 1;
     801                                break;
     802                        }
     803                        tmp++;
     804                }
     805#else
    579806                if ((p = strrchr(*t, '/')) != NULL)
    580807                        ++p;
    581808                else
    582809                        p = *t;
     810#endif
    583811                if (ISDOT(p)) {
    584812                        if (!complained++)
     
    596824usage(FILE *pf)
    597825{
    598         fprintf(pf, "usage: %s [-f | -i] [-dPRrvW] file ...\n"
    599                                 "   or: %s --help\n"
    600                                 "   or: %s --version\n",
    601                         g_progname, g_progname, g_progname);
     826        fprintf(pf,
     827                "usage: %s [-f | -i] [-dPRvW] [--disable-protection] file ...\n"
     828                "   or: %s --help\n"
     829                "   or: %s --version\n"
     830                "\n"
     831                "Options:\n"
     832                "   -f\n"
     833                "       Attempt to remove files without prompting, regardless of the file\n"
     834                "       permission. Ignore non-existing files. Overrides previous -i's.\n"
     835                "   -i\n"
     836                "       Prompt for each file. Always.\n"
     837                "   -d\n"
     838                "       Attempt to remove directories as well as other kinds of files.\n"
     839                "   -P\n"
     840                "       Overwrite regular files before deleting; three passes: ff,0,ff\n"
     841                "   -R\n"
     842                "       Attempt to remove the file hierachy rooted in each file argument.\n"
     843                "       This option implies -d and file protection.\n"
     844                "   -v\n"
     845                "       Be verbose, show files as they are removed.\n"
     846                "   -W\n"
     847                "       Undelete without files.\n"
     848                "   --disable-protection\n"
     849                "       Will disable the protection file protection applied by -R.\n"
     850                "\n"
     851                "Environment:\n"
     852                "    KMK_RM_DISABLE_PROTECTION\n"
     853                "       Same as --disable-protection.\n"
     854                "    KMK_RM_PROTECTION_DEPTH\n"
     855                "       Changes the protection depth, path or number. Default: %d\n"
     856                "\n"
     857                "The file protection of the top %d layers of the file hierarchy is there\n"
     858                "to try prevent makefiles from doing bad things to your system. This\n"
     859                "protection is not bulletproof, but should help prevent you from shooting\n"
     860                "yourself in the foot. Not that it does NOT apply to normal file removal.\n"
     861                ,
     862                g_progname, g_progname, g_progname,
     863                DEFAULT_REQUIRED_R_DEPTH, DEFAULT_REQUIRED_R_DEPTH);
    602864        return EX_USAGE;
    603865}
Note: See TracChangeset for help on using the changeset viewer.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette