📄 rm.c
字号:
/* `rm' file deletion utility for GNU.
Copyright (C) 1988, 1989, 1990 Free Software Foundation, Inc.
This program 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 1, or (at your option)
any later version.
This program 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 this program; if not, write to the Free Software
Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */
/* Written by Paul Rubin, David MacKenzie, and Richard Stallman. */
/* MS-DOS port (c) 1990 by Thorsten Ohl, ohl@gnu.ai.mit.edu
This port is also distributed under the terms of the
GNU General Public License as published by the
Free Software Foundation.
Please note that this file is not identical to the
original GNU release, you should have received this
code as patch to the official release. */
#ifdef MSDOS
static char RCS_Id[] =
"$Header: e:/gnu/fileutil/RCS/rm.c 1.4.0.3 90/09/20 08:46:14 tho Exp $";
static char Program_Id[] = "rm";
static char RCS_Revision[] = "$Revision: 1.4.0.3 $";
#define VERSION \
"GNU %s, Version %.*s (compiled %s %s for MS-DOS)\n", Program_Id, \
(sizeof RCS_Revision - 14), (RCS_Revision + 11), __DATE__, __TIME__
#define COPYING \
"This is free software, distributed under the terms of the\n" \
"GNU General Public License. For details, see the file COPYING.\n"
#endif /* MSDOS */
#include <stdio.h>
#include <getopt.h>
#include <sys/types.h>
#include <errno.h>
#include "system.h"
#ifdef STDC_HEADERS
#include <stdlib.h>
#else
char *malloc ();
char *realloc ();
extern int errno;
#endif
#ifdef MSDOS
#include <string.h>
#include <malloc.h>
#include <io.h>
#include <direct.h>
#include <gnulib.h>
extern void main (int argc, char **argv);
static int rm (void);
static int remove_file (struct stat *statp);
static int remove_dir (struct stat *statp);
static int clear_directory (struct stat *statp);
static int yesno (void);
static char *basename (char *name);
static char *stpcpy (char *dest, char *source);
static void usage (void);
extern int eaccess (char *path, int mode);
extern int eaccess_stat (struct stat *statp, int mode);
static void strip_trailing_slashes (char **path);
#define strip_trailing_slashes(path) strip_trailing_slashes (&path)
#define check_stack(stck, ino) 0
#define unlink(name) force_unlink (name)
static int force_unlink (char *filename);
#else /* not MSDOS */
char *basename ();
char *stpcpy ();
char *xmalloc ();
char *xrealloc ();
int check_stack ();
int clear_directory ();
int eaccess_stat ();
int remove_dir ();
int remove_file ();
int rm ();
int yesno ();
void error ();
void strip_trailing_slashes ();
void usage ();
#endif /* not MSDOS */
/* Path of file now being processed; extended as necessary. */
char *pathname;
/* Number of bytes currently allocated for `pathname';
made larger when necessary, but never smaller. */
int pnsize;
/* Name this program was run with. */
char *program_name;
/* If nonzero, display the name of each file removed. */
int verbose;
/* If nonzero, ignore nonexistant files. */
int ignore_missing_files;
/* If nonzero, recursively remove directories. */
int recursive;
/* If nonzero, query the user about whether to remove each file. */
int interactive;
/* If nonzero, remove directories with unlink instead of rmdir, and don't
require a directory to be empty before trying to unlink it.
Only works for the super-user. */
int unlink_dirs;
/* Information for detecting attempted removal of `.' and `..'. */
dev_t dot_dev, dotdot_dev;
ino_t dot_ino, dotdot_ino;
struct option long_opts[] =
{
#ifdef MSDOS
{"copying", 0, NULL, 30},
{"version", 0, NULL, 31},
#endif
{"directory", 0, &unlink_dirs, 1},
{"force", 0, NULL, 'f'},
{"interactive", 0, NULL, 'i'},
{"recursive", 0, &recursive, 1},
{"verbose", 0, &verbose, 1},
{NULL, 0, NULL, 0}
};
void
main (argc, argv)
int argc;
char **argv;
{
int err = 0;
int c;
int ind;
struct stat stats;
verbose = ignore_missing_files = recursive = interactive
= unlink_dirs = 0;
pnsize = 256;
program_name = argv[0];
pathname = xmalloc (pnsize);
while ((c = getopt_long (argc, argv, "dfirvR", long_opts, &ind)) != EOF)
{
switch (c)
{
case 0: /* Long option. */
break;
case 'd':
unlink_dirs = 1;
break;
case 'f':
ignore_missing_files = 1;
interactive = 0;
break;
case 'i':
ignore_missing_files = 0;
interactive = 1;
break;
case 'r':
case 'R':
recursive = 1;
break;
case 'v':
verbose = 1;
break;
#ifdef MSDOS
case 30:
fprintf (stderr, COPYING);
exit (0);
break;
case 31:
fprintf (stderr, VERSION);
exit (0);
break;
#endif
default:
usage ();
}
}
if (optind == argc)
usage ();
#ifndef MSDOS /* this fails at the root ... */
if (lstat (".", &stats))
error (1, errno, ".");
dot_dev = stats.st_dev;
dot_ino = stats.st_ino;
if (lstat ("..", &stats))
error (1, errno, "..");
dotdot_dev = stats.st_dev;
dotdot_ino = stats.st_ino;
#endif /* not MSDOS */
for (; optind < argc; optind++)
{
int len;
strip_trailing_slashes (argv[optind]);
len = strlen (argv[optind]);
if (len + 1 > pnsize)
{
free (pathname);
pnsize = 2 * (len + 1);
pathname = xmalloc (pnsize);
}
strcpy (pathname, argv[optind]);
err += rm ();
}
exit (err > 0);
}
/* Remove file or directory `pathname' after checking appropriate things.
Return 0 if `pathname' is removed, 1 if not. */
int
rm ()
{
struct stat path_stats;
if (lstat (pathname, &path_stats))
{
if (errno == ENOENT && ignore_missing_files)
return 0;
error (0, errno, "%s", pathname);
return 1;
}
#ifndef MSDOS
if ((path_stats.st_dev == dot_dev && path_stats.st_ino == dot_ino)
|| (path_stats.st_dev == dotdot_dev && path_stats.st_ino == dotdot_ino))
{
error (0, 0, "%s: cannot remove current directory or parent", pathname);
return 1;
}
#endif /* not MSDOS */
if ((path_stats.st_mode & S_IFMT) == S_IFDIR && !unlink_dirs)
return remove_dir (&path_stats);
else
return remove_file (&path_stats);
}
/* Query the user if appropriate, and if ok try to remove the
non-directory `pathname', which STATP contains info about.
Return 0 if `pathname' is removed, 1 if not. */
int
remove_file (statp)
struct stat *statp;
{
if (interactive)
{
fprintf (stderr, "%s: remove %s`%s'? ", program_name,
(statp->st_mode & S_IFMT) == S_IFDIR ? "directory " : "",
pathname);
if (!yesno ())
return 1;
}
if (verbose)
printf (" %s\n", pathname);
if (unlink (pathname))
{
error (0, errno, "%s", pathname);
return 1;
}
return 0;
}
/* If not in recursive mode, print an error message and return 1.
Otherwise, query the user if appropriate, then try to recursively
remove directory `pathname', which STATP contains info about.
Return 0 if `pathname' is removed, 1 if not. */
int
remove_dir (statp)
struct stat *statp;
{
int err;
int writable;
if (!recursive)
{
error (0, 0, "%s: is a directory", pathname);
return 1;
}
#ifdef S_IFLNK
if ((statp->st_mode & S_IFMT) == S_IFLNK)
writable = 1;
else
#endif
writable = eaccess_stat (statp, W_OK) == 0;
if (!writable)
{
error (0, 0, "%s: no write permission for directory", pathname);
return 1;
}
if (interactive)
{
fprintf (stderr, "%s: recursively descend directory `%s'? ",
program_name, pathname);
if (!yesno ())
return 1;
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -