[BusyBox] PATCH: cp /dev/null some_file
Anthony Shipman
als at labyrinth.net.au
Thu May 27 08:21:55 UTC 2004
Below is a bug fix for the common idiom
cp /dev/null some_file
to create an empty file.
--- orig/busybox/busybox-1.00-pre10/coreutils/mv.c
+++ mod/busybox/busybox-1.00-pre10/coreutils/mv.c
@@ -121,7 +121,7 @@
}
}
if ((copy_file(*argv, dest,
- FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS) >= 0) &&
+ FILEUTILS_RECUR | FILEUTILS_PRESERVE_STATUS | FILEUTILS_MOVE) >= 0) &&
(remove_file(*argv, FILEUTILS_RECUR | FILEUTILS_FORCE) >= 0)) {
goto RET_0;
}
--- orig/busybox/busybox-1.00-pre10/include/libbb.h
+++ mod/busybox/busybox-1.00-pre10/include/libbb.h
@@ -318,7 +318,8 @@
FILEUTILS_DEREFERENCE = 2,
FILEUTILS_RECUR = 4,
FILEUTILS_FORCE = 8,
- FILEUTILS_INTERACTIVE = 16
+ FILEUTILS_INTERACTIVE = 16,
+ FILEUTILS_MOVE = 0x40000000
};
extern const char *bb_applet_name;
--- orig/busybox/busybox-1.00-pre10/libbb/copy_file.c
+++ mod/busybox/busybox-1.00-pre10/libbb/copy_file.c
@@ -32,12 +32,17 @@
#include "busybox.h"
+static int must_read(const struct stat* src_stat, int flags);
+
+
+
int copy_file(const char *source, const char *dest, int flags)
{
struct stat source_stat;
struct stat dest_stat;
int dest_exists = 0;
int status = 0;
+ int force_read = 0;
if ((!(flags & FILEUTILS_DEREFERENCE) &&
lstat(source, &source_stat) < 0) ||
@@ -61,6 +66,9 @@
dest_exists = 1;
}
+ /* Test for special treatment for some device files. */
+ force_read = must_read(&source_stat, flags);
+
if (S_ISDIR(source_stat.st_mode)) {
DIR *dp;
struct dirent *d;
@@ -122,7 +130,7 @@
bb_perror_msg("unable to change permissions of `%s'", dest);
status = -1;
}
- } else if (S_ISREG(source_stat.st_mode)) {
+ } else if (S_ISREG(source_stat.st_mode) || force_read) {
int src_fd;
int dst_fd;
#ifdef CONFIG_FEATURE_PRESERVE_HARDLINKS
@@ -209,9 +217,11 @@
}
if (S_ISBLK(source_stat.st_mode) || S_ISCHR(source_stat.st_mode) ||
S_ISSOCK(source_stat.st_mode)) {
- if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
- bb_perror_msg("unable to create `%s'", dest);
- return -1;
+ if (!force_read) {
+ if (mknod(dest, source_stat.st_mode, source_stat.st_rdev) < 0) {
+ bb_perror_msg("unable to create `%s'", dest);
+ return -1;
+ }
}
} else if (S_ISFIFO(source_stat.st_mode)) {
if (mkfifo(dest, source_stat.st_mode) < 0) {
@@ -264,3 +274,52 @@
return status;
}
+
+
+
+static int
+must_read(const struct stat* src_stat, int flags)
+{
+ /* Test if the file is a /dev file that should be read rather
+ then recreated. For example we want
+ cp /dev/null xyz
+ to create an empty file not try to make a device node called
+ 'xyz'.
+
+ On the other hand an attempt at
+ mv /dev/null xyz
+ should attempt to create a device node if the mv command
+ decides to copy after a rename fails (even if this is a
+ dumb thing to do). FILEUTILS_MOVE indicates this case.
+
+ At the moment only /dev/null is treated specially. Note
+ that we want to recognise the file in the case of a command
+ like
+ cd /dev; cp null xyz
+ Also we want to recognise copies of the file in e.g. chroot
+ environments. So we have to compare device numbers.
+
+ If we are recursively copying the /dev directory then
+ we should be attempting to make a device node in the
+ destination. But there is no reliable way to detect
+ this case.
+
+ This returns true if the file should be treated as data
+ rather than a device node.
+ */
+ struct stat null;
+
+ if (flags & FILEUTILS_MOVE)
+ return 0;
+
+ if (S_ISCHR(src_stat->st_mode)) {
+ /* It's a char device node. Compare it with /dev/null.
+ */
+ if (stat("/dev/null", &null) >= 0) {
+ if (S_ISCHR(null.st_mode) && src_stat->st_rdev == null.st_rdev)
+ return 1;
+ }
+ }
+
+ return 0;
+}
--
Anthony Shipman Elektrichore - The muse of
als at labyrinth.net.au high technology.
More information about the busybox
mailing list