aboutsummaryrefslogtreecommitdiff
path: root/win32/mingw.c
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2018-02-26 20:39:23 +0000
committerRon Yorston <rmy@pobox.com>2018-02-26 20:39:23 +0000
commit650f67507f2718dec0d4282afea619cfe7a53305 (patch)
tree82e523133f961e8337f42765307b63dc737f2580 /win32/mingw.c
parentfcb5c968bef6c4fd234e000aaeaa160ac1d16f11 (diff)
downloadbusybox-w32-650f67507f2718dec0d4282afea619cfe7a53305.tar.gz
busybox-w32-650f67507f2718dec0d4282afea619cfe7a53305.tar.bz2
busybox-w32-650f67507f2718dec0d4282afea619cfe7a53305.zip
win32: move detection of file formats to stat(2)
Move the code to detect shell scripts and binary executables from mingw_access to a separate function, has_exec_format. Call this function in do_lstat to decide whether to set the executable bits in the file mode. This will slow down stat but has a couple of advantages: - shell scripts are highlighted in ls output - the test applet can use stat(2) to detect executable files The new function is used to handle another corner case in spawnveq: binary executables without the usual .exe extension are only run by spawnve if the file name ends with '.'. Two minor changes: - file_is_win32_executable has been renamed add_win32_extension to clarify what it does - a call to file_is_executable has been removed from find_command in ash as it resulted in unhelpful error messages.
Diffstat (limited to 'win32/mingw.c')
-rw-r--r--win32/mingw.c111
1 files changed, 60 insertions, 51 deletions
diff --git a/win32/mingw.c b/win32/mingw.c
index bd4d9b34a..713778ff1 100644
--- a/win32/mingw.c
+++ b/win32/mingw.c
@@ -300,7 +300,8 @@ static int do_lstat(int follow, const char *file_name, struct mingw_stat *buf)
300 buf->st_gid = DEFAULT_GID; 300 buf->st_gid = DEFAULT_GID;
301 buf->st_nlink = 1; 301 buf->st_nlink = 1;
302 buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes); 302 buf->st_mode = file_attr_to_st_mode(fdata.dwFileAttributes);
303 if (has_exe_suffix(file_name)) 303 if (S_ISREG(buf->st_mode) &&
304 (has_exe_suffix(file_name) || has_exec_format(file_name)))
304 buf->st_mode |= S_IXUSR|S_IXGRP|S_IXOTH; 305 buf->st_mode |= S_IXUSR|S_IXGRP|S_IXOTH;
305 buf->st_size = fdata.nFileSizeLow | 306 buf->st_size = fdata.nFileSizeLow |
306 (((off64_t)fdata.nFileSizeHigh)<<32); 307 (((off64_t)fdata.nFileSizeHigh)<<32);
@@ -982,9 +983,6 @@ int mingw_access(const char *name, int mode)
982{ 983{
983 int ret; 984 int ret;
984 struct stat s; 985 struct stat s;
985 int fd, n, sig;
986 unsigned int offset;
987 unsigned char buf[1024];
988 986
989 /* Windows can only handle test for existence, read or write */ 987 /* Windows can only handle test for existence, read or write */
990 if (mode == F_OK || (mode & ~X_OK)) { 988 if (mode == F_OK || (mode & ~X_OK)) {
@@ -994,52 +992,8 @@ int mingw_access(const char *name, int mode)
994 } 992 }
995 } 993 }
996 994
997 if (!mingw_stat(name, &s) && S_ISREG(s.st_mode)) { 995 if (!mingw_stat(name, &s) && S_ISREG(s.st_mode) && (s.st_mode&S_IXUSR)) {
998 996 return 0;
999 /* stat marks files as executable according to their suffix */
1000 if ((s.st_mode&S_IEXEC)) {
1001 return 0;
1002 }
1003
1004 fd = open(name, O_RDONLY);
1005 if (fd < 0)
1006 return -1;
1007 n = read(fd, buf, sizeof(buf)-1);
1008 close(fd);
1009 if (n < 4) /* at least '#!/x' and not error */
1010 return -1;
1011
1012 /* shell script */
1013 if (buf[0] == '#' && buf[1] == '!') {
1014 return 0;
1015 }
1016
1017 /*
1018 * Poke about in file to see if it's a PE binary. I've just copied
1019 * the magic from the file command.
1020 */
1021 if (buf[0] == 'M' && buf[1] == 'Z') {
1022 offset = (buf[0x19] << 8) + buf[0x18];
1023 if (offset > 0x3f) {
1024 offset = (buf[0x3f] << 24) + (buf[0x3e] << 16) +
1025 (buf[0x3d] << 8) + buf[0x3c];
1026 if (offset < sizeof(buf)-100) {
1027 if (memcmp(buf+offset, "PE\0\0", 4) == 0) {
1028 sig = (buf[offset+25] << 8) + buf[offset+24];
1029 if (sig == 0x10b || sig == 0x20b) {
1030 sig = (buf[offset+23] << 8) + buf[offset+22];
1031 if ((sig & 0x2000) != 0) {
1032 /* DLL */
1033 return -1;
1034 }
1035 sig = buf[offset+92];
1036 return !(sig == 1 || sig == 2 ||
1037 sig == 3 || sig == 7);
1038 }
1039 }
1040 }
1041 }
1042 }
1043 } 997 }
1044 998
1045 return -1; 999 return -1;
@@ -1085,7 +1039,7 @@ int has_exe_suffix(const char *name)
1085 * 1039 *
1086 * if path already has a suffix don't even bother trying 1040 * if path already has a suffix don't even bother trying
1087 */ 1041 */
1088char *file_is_win32_executable(const char *p) 1042char *add_win32_extension(const char *p)
1089{ 1043{
1090 char *path; 1044 char *path;
1091 int i, len; 1045 int i, len;
@@ -1109,6 +1063,61 @@ char *file_is_win32_executable(const char *p)
1109 return NULL; 1063 return NULL;
1110} 1064}
1111 1065
1066/*
1067 * Examine a file's contents to determine if it can be executed. This
1068 * should be a last resort: in most cases it's much more efficient to
1069 * check the file extension.
1070 *
1071 * We look for two types of file: shell scripts and binary executables.
1072 */
1073int has_exec_format(const char *name)
1074{
1075 int fd, n, sig;
1076 unsigned int offset;
1077 unsigned char buf[1024];
1078
1079 fd = open(name, O_RDONLY);
1080 if (fd < 0)
1081 return 0;
1082 n = read(fd, buf, sizeof(buf)-1);
1083 close(fd);
1084 if (n < 4) /* at least '#!/x' and not error */
1085 return 0;
1086
1087 /* shell script */
1088 if (buf[0] == '#' && buf[1] == '!') {
1089 return 1;
1090 }
1091
1092 /*
1093 * Poke about in file to see if it's a PE binary. I've just copied
1094 * the magic from the file command.
1095 */
1096 if (buf[0] == 'M' && buf[1] == 'Z') {
1097 offset = (buf[0x19] << 8) + buf[0x18];
1098 if (offset > 0x3f) {
1099 offset = (buf[0x3f] << 24) + (buf[0x3e] << 16) +
1100 (buf[0x3d] << 8) + buf[0x3c];
1101 if (offset < sizeof(buf)-100) {
1102 if (memcmp(buf+offset, "PE\0\0", 4) == 0) {
1103 sig = (buf[offset+25] << 8) + buf[offset+24];
1104 if (sig == 0x10b || sig == 0x20b) {
1105 sig = (buf[offset+23] << 8) + buf[offset+22];
1106 if ((sig & 0x2000) != 0) {
1107 /* DLL */
1108 return 0;
1109 }
1110 sig = buf[offset+92];
1111 return (sig == 1 || sig == 2 || sig == 3 || sig == 7);
1112 }
1113 }
1114 }
1115 }
1116 }
1117
1118 return 0;
1119}
1120
1112#undef opendir 1121#undef opendir
1113DIR *mingw_opendir(const char *path) 1122DIR *mingw_opendir(const char *path)
1114{ 1123{