fs.cpp revision 0b3ec5d32f15bdea67d15af95cf68e455867c668
1#include "fs.h"
2#include "files.h"
3#include <unistd.h>
4#include <stdlib.h>
5#include <sys/types.h>
6#include <sys/wait.h>
7#include <dirent.h>
8#include <string>
9#include <vector>
10#include <stdio.h>
11#include <string.h>
12#include <errno.h>
13#include <sys/stat.h>
14#include <unistd.h>
15#include <string.h>
16#include <host/CopyFile.h>
17
18using namespace std;
19
20static bool
21is_dir(const string& path)
22{
23    int err;
24    struct stat st;
25    err = stat(path.c_str(), &st);
26    return err != 0 || S_ISDIR(st.st_mode);
27}
28
29static int
30remove_file(const string& path)
31{
32    int err = unlink(path.c_str());
33    if (err != 0) {
34        fprintf(stderr, "error deleting file %s (%s)\n", path.c_str(),
35                strerror(errno));
36        return errno;
37    }
38    return 0;
39}
40
41int
42remove_recursively(const string& path)
43{
44    int err;
45
46    if (is_dir(path)) {
47        DIR *d = opendir(path.c_str());
48        if (d == NULL) {
49            fprintf(stderr, "error getting directory contents %s (%s)\n",
50                    path.c_str(), strerror(errno));
51            return errno;
52        }
53
54        vector<string> files;
55        vector<string> dirs;
56
57        struct dirent *ent;
58        while (NULL != (ent = readdir(d))) {
59            if (0 == strcmp(".", ent->d_name)
60                    || 0 == strcmp("..", ent->d_name)) {
61                continue;
62            }
63            string full = path;
64            full += '/';
65            full += ent->d_name;
66#ifdef HAVE_DIRENT_D_TYPE
67            bool is_directory = (ent->d_type == DT_DIR);
68#else
69            // If dirent.d_type is missing, then use stat instead
70            struct stat stat_buf;
71            stat(full.c_str(), &stat_buf);
72            bool is_directory = S_ISDIR(stat_buf.st_mode);
73#endif
74            if (is_directory) {
75                dirs.push_back(full);
76            } else {
77                files.push_back(full);
78            }
79        }
80        closedir(d);
81
82        for (vector<string>::iterator it=files.begin(); it!=files.end(); it++) {
83            err = remove_file(*it);
84            if (err != 0) {
85                return err;
86            }
87        }
88
89        for (vector<string>::iterator it=dirs.begin(); it!=dirs.end(); it++) {
90            err = remove_recursively(*it);
91            if (err != 0) {
92                return err;
93            }
94        }
95
96        err = rmdir(path.c_str());
97        if (err != 0) {
98            fprintf(stderr, "error deleting directory %s (%s)\n", path.c_str(),
99                    strerror(errno));
100            return errno;
101        }
102        return 0;
103    } else {
104        return remove_file(path);
105    }
106}
107
108int
109mkdir_recursively(const string& path)
110{
111    int err;
112    size_t pos = 0;
113    // For absolute pathnames, that starts with leading '/'
114    // use appropriate initial value.
115    if (path.length() != 0 and path[0] == '/') pos++;
116
117    while (true) {
118        pos = path.find('/', pos);
119        string p = path.substr(0, pos);
120        struct stat st;
121        err = stat(p.c_str(), &st);
122        if (err != 0) {
123            err = mkdir(p.c_str(), 0770);
124            if (err != 0) {
125                fprintf(stderr, "can't create directory %s (%s)\n",
126                        path.c_str(), strerror(errno));
127                return errno;
128            }
129        }
130        else if (!S_ISDIR(st.st_mode)) {
131            fprintf(stderr, "can't create directory %s because %s is a file.\n",
132                        path.c_str(), p.c_str());
133            return 1;
134        }
135        pos++;
136        if (p == path) {
137            return 0;
138        }
139    }
140}
141
142int
143copy_file(const string& src, const string& dst)
144{
145    int err;
146
147    err = copyFile(src.c_str(), dst.c_str(),
148                    COPY_NO_DEREFERENCE | COPY_FORCE | COPY_PERMISSIONS);
149    return err;
150}
151
152int
153strip_file(const string& path)
154{
155    // Default strip command to run is "strip" unless overridden by the STRIP env var.
156    const char* strip_cmd = getenv("STRIP");
157    if (!strip_cmd || !strip_cmd[0]) {
158        strip_cmd = "strip";
159    }
160    pid_t pid = fork();
161    if (pid == -1) {
162        // Fork failed. errno should be set.
163        return -1;
164    } else if (pid == 0) {
165        // Exec in the child. Only returns if execve failed.
166        return execlp(strip_cmd, strip_cmd, path.c_str(), (char *)NULL);
167    } else {
168        // Wait for child pid and return its exit code.
169        int status;
170        waitpid(pid, &status, 0);
171        return status;
172    }
173}
174
175