Branch data Line data Source code
1 : : /** @file unixcmds.cc
2 : : * @brief C++ function versions of useful Unix commands.
3 : : */
4 : : /* Copyright (C) 2003,2004,2007 Olly Betts
5 : : *
6 : : * This program is free software; you can redistribute it and/or
7 : : * modify it under the terms of the GNU General Public License as
8 : : * published by the Free Software Foundation; either version 2 of the
9 : : * License, or (at your option) any later version.
10 : : *
11 : : * This program is distributed in the hope that it will be useful,
12 : : * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 : : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 : : * GNU General Public License for more details.
15 : : *
16 : : * You should have received a copy of the GNU General Public License
17 : : * along with this program; if not, write to the Free Software
18 : : * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 : : */
20 : :
21 : : #include <config.h>
22 : :
23 : : #include "unixcmds.h"
24 : :
25 : : #include <cstring>
26 : : #include <string>
27 : : #include <cstdlib>
28 : : #include <sys/types.h>
29 : : #include "safesysstat.h"
30 : : #include "safeunistd.h"
31 : : #include "safefcntl.h"
32 : :
33 : : #ifdef __WIN32__
34 : : # include "safewindows.h"
35 : : #endif
36 : :
37 : : #include "stringutils.h"
38 : : #include "utils.h"
39 : :
40 : : using namespace std;
41 : :
42 : : /// Append filename argument arg to command cmd with suitable escaping.
43 : : static bool
44 : 728 : append_filename_argument(string & cmd, const string & arg) {
45 : : #ifdef __WIN32__
46 : : cmd.reserve(cmd.size() + arg.size() + 3);
47 : : cmd += " \"";
48 : : for (string::const_iterator i = arg.begin(); i != arg.end(); ++i) {
49 : : if (*i == '/') {
50 : : // Convert Unix path separators to backslashes. C library
51 : : // functions understand "/" in paths, but we are going to
52 : : // call commands like "deltree" or "rd" which don't.
53 : : cmd += '\\';
54 : : } else if (*i < 32 || strchr("<>\"|*?", *i)) {
55 : : // Check for illegal characters in filename.
56 : : return false;
57 : : } else {
58 : : cmd += *i;
59 : : }
60 : : }
61 : : cmd += '"';
62 : : #else
63 : : // Allow for escaping a few characters.
64 : 728 : cmd.reserve(cmd.size() + arg.size() + 10);
65 : :
66 : : // Prevent a leading "-" on the filename being interpreted as a command
67 : : // line option.
68 [ - + ]: 728 : if (arg[0] == '-')
69 : 0 : cmd += " ./";
70 : : else
71 : 728 : cmd += ' ';
72 : :
73 [ + + ]: 8799 : for (string::const_iterator i = arg.begin(); i != arg.end(); ++i) {
74 : : // Don't escape a few safe characters which are common in filenames.
75 [ + + ][ - + ]: 8071 : if (!C_isalnum(*i) && strchr("/._-", *i) == NULL) {
[ - + ]
76 : 0 : cmd += '\\';
77 : : }
78 : 8071 : cmd += *i;
79 : : }
80 : : #endif
81 : 728 : return true;
82 : : }
83 : :
84 : : /// Recursively copy a directory.
85 : 5 : void cp_R(const std::string &src, const std::string &dest) {
86 : : #ifdef __WIN32__
87 : : // xcopy should be available on both NT and 95 derivatives. We create
88 : : // the target directory first to avoid being prompted as to whether we
89 : : // want to create a directory or a file (which makes no sense when
90 : : // copying a directory, but that's how xcopy seems to work!)
91 : : mkdir(dest.c_str());
92 : : string cmd("xcopy /E /Y");
93 : : #else
94 : 5 : string cmd("cp -R");
95 : : #endif
96 [ - + ]: 5 : if (!append_filename_argument(cmd, src)) return;
97 [ - + ]: 5 : if (!append_filename_argument(cmd, dest)) return;
98 : 5 : system(cmd);
99 : : #ifndef __WIN32__
100 : : // Allow write access to the copy (to deal with builds where srcdir is
101 : : // readonly).
102 : 5 : cmd = "chmod -R +w";
103 [ - + ]: 5 : if (!append_filename_argument(cmd, dest)) return;
104 : 5 : system(cmd);
105 : : #endif
106 : : }
107 : :
108 : : #ifdef __WIN32__
109 : : static bool running_on_win9x() {
110 : : static int win9x = -1;
111 : : if (win9x == -1) {
112 : : OSVERSIONINFO info;
113 : : memset(&info, 0, sizeof(OSVERSIONINFO));
114 : : info.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
115 : : if (GetVersionEx(&info)) {
116 : : win9x = (info.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS);
117 : : }
118 : : }
119 : : return win9x;
120 : : }
121 : : #endif
122 : :
123 : : /// Remove a directory and contents, just like the Unix "rm -rf" command.
124 : 859 : void rm_rf(const string &filename) {
125 : : // Check filename exists and is actually a directory
126 : : struct stat sb;
127 [ + - ][ + + ]: 859 : if (filename.empty() || stat(filename, &sb) != 0 || !S_ISDIR(sb.st_mode))
[ - + ][ + + ]
128 : 146 : return;
129 : :
130 : : #ifdef __WIN32__
131 : : string cmd;
132 : : if (running_on_win9x()) {
133 : : // For 95-like systems:
134 : : cmd = "deltree /y";
135 : : } else {
136 : : // For NT-like systems:
137 : : cmd = "rd /s /q";
138 : : }
139 : : #else
140 : 713 : string cmd("rm -rf");
141 : : #endif
142 [ - + ]: 713 : if (!append_filename_argument(cmd, filename)) return;
143 : 859 : system(cmd);
144 : : }
145 : :
146 : : /// Touch a file, just like the Unix "touch" command.
147 : 1 : void touch(const string &filename) {
148 : 1 : int fd = open(filename.c_str(), O_CREAT|O_WRONLY|O_BINARY, 0644);
149 [ + - ]: 1 : if (fd >= 0) close(fd);
150 : 1 : }
|