1*9e94795aSAndroid Build Coastguard Worker // Copyright 2014 The Bazel Authors. All rights reserved.
2*9e94795aSAndroid Build Coastguard Worker //
3*9e94795aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License");
4*9e94795aSAndroid Build Coastguard Worker // you may not use this file except in compliance with the License.
5*9e94795aSAndroid Build Coastguard Worker // You may obtain a copy of the License at
6*9e94795aSAndroid Build Coastguard Worker //
7*9e94795aSAndroid Build Coastguard Worker // http://www.apache.org/licenses/LICENSE-2.0
8*9e94795aSAndroid Build Coastguard Worker //
9*9e94795aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*9e94795aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS,
11*9e94795aSAndroid Build Coastguard Worker // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12*9e94795aSAndroid Build Coastguard Worker // See the License for the specific language governing permissions and
13*9e94795aSAndroid Build Coastguard Worker // limitations under the License.
14*9e94795aSAndroid Build Coastguard Worker //
15*9e94795aSAndroid Build Coastguard Worker // This program creates a "runfiles tree" from a "runfiles manifest".
16*9e94795aSAndroid Build Coastguard Worker //
17*9e94795aSAndroid Build Coastguard Worker // The command line arguments are an input manifest INPUT and an output
18*9e94795aSAndroid Build Coastguard Worker // directory RUNFILES. First, the files in the RUNFILES directory are scanned
19*9e94795aSAndroid Build Coastguard Worker // and any extraneous ones are removed. Second, any missing files are created.
20*9e94795aSAndroid Build Coastguard Worker // Finally, a copy of the input manifest is written to RUNFILES/MANIFEST.
21*9e94795aSAndroid Build Coastguard Worker //
22*9e94795aSAndroid Build Coastguard Worker // The input manifest consists of lines, each containing a relative path within
23*9e94795aSAndroid Build Coastguard Worker // the runfiles, a space, and an optional absolute path. If this second path
24*9e94795aSAndroid Build Coastguard Worker // is present, a symlink is created pointing to it; otherwise an empty file is
25*9e94795aSAndroid Build Coastguard Worker // created.
26*9e94795aSAndroid Build Coastguard Worker //
27*9e94795aSAndroid Build Coastguard Worker // Given the line
28*9e94795aSAndroid Build Coastguard Worker // <workspace root>/output/path /real/path
29*9e94795aSAndroid Build Coastguard Worker // we will create directories
30*9e94795aSAndroid Build Coastguard Worker // RUNFILES/<workspace root>
31*9e94795aSAndroid Build Coastguard Worker // RUNFILES/<workspace root>/output
32*9e94795aSAndroid Build Coastguard Worker // a symlink
33*9e94795aSAndroid Build Coastguard Worker // RUNFILES/<workspace root>/output/path -> /real/path
34*9e94795aSAndroid Build Coastguard Worker // and the output manifest will contain a line
35*9e94795aSAndroid Build Coastguard Worker // <workspace root>/output/path /real/path
36*9e94795aSAndroid Build Coastguard Worker //
37*9e94795aSAndroid Build Coastguard Worker // If --use_metadata is supplied, every other line is treated as opaque
38*9e94795aSAndroid Build Coastguard Worker // metadata, and is ignored here.
39*9e94795aSAndroid Build Coastguard Worker //
40*9e94795aSAndroid Build Coastguard Worker // All output paths must be relative and generally (but not always) begin with
41*9e94795aSAndroid Build Coastguard Worker // <workspace root>. No output path may be equal to another. No output path may
42*9e94795aSAndroid Build Coastguard Worker // be a path prefix of another.
43*9e94795aSAndroid Build Coastguard Worker
44*9e94795aSAndroid Build Coastguard Worker #define _FILE_OFFSET_BITS 64
45*9e94795aSAndroid Build Coastguard Worker
46*9e94795aSAndroid Build Coastguard Worker #include <dirent.h>
47*9e94795aSAndroid Build Coastguard Worker #include <err.h>
48*9e94795aSAndroid Build Coastguard Worker #include <errno.h>
49*9e94795aSAndroid Build Coastguard Worker #include <fcntl.h>
50*9e94795aSAndroid Build Coastguard Worker #include <limits.h>
51*9e94795aSAndroid Build Coastguard Worker #include <stdio.h>
52*9e94795aSAndroid Build Coastguard Worker #include <string.h>
53*9e94795aSAndroid Build Coastguard Worker #include <stdlib.h>
54*9e94795aSAndroid Build Coastguard Worker #include <sys/stat.h>
55*9e94795aSAndroid Build Coastguard Worker #include <unistd.h>
56*9e94795aSAndroid Build Coastguard Worker
57*9e94795aSAndroid Build Coastguard Worker #include <map>
58*9e94795aSAndroid Build Coastguard Worker #include <string>
59*9e94795aSAndroid Build Coastguard Worker
60*9e94795aSAndroid Build Coastguard Worker // program_invocation_short_name is not portable.
61*9e94795aSAndroid Build Coastguard Worker static const char *argv0;
62*9e94795aSAndroid Build Coastguard Worker
63*9e94795aSAndroid Build Coastguard Worker const char *input_filename;
64*9e94795aSAndroid Build Coastguard Worker const char *output_base_dir;
65*9e94795aSAndroid Build Coastguard Worker
66*9e94795aSAndroid Build Coastguard Worker enum FileType {
67*9e94795aSAndroid Build Coastguard Worker FILE_TYPE_REGULAR,
68*9e94795aSAndroid Build Coastguard Worker FILE_TYPE_DIRECTORY,
69*9e94795aSAndroid Build Coastguard Worker FILE_TYPE_SYMLINK
70*9e94795aSAndroid Build Coastguard Worker };
71*9e94795aSAndroid Build Coastguard Worker
72*9e94795aSAndroid Build Coastguard Worker struct FileInfo {
73*9e94795aSAndroid Build Coastguard Worker FileType type;
74*9e94795aSAndroid Build Coastguard Worker std::string symlink_target;
75*9e94795aSAndroid Build Coastguard Worker
operator ==FileInfo76*9e94795aSAndroid Build Coastguard Worker bool operator==(const FileInfo &other) const {
77*9e94795aSAndroid Build Coastguard Worker return type == other.type && symlink_target == other.symlink_target;
78*9e94795aSAndroid Build Coastguard Worker }
79*9e94795aSAndroid Build Coastguard Worker
operator !=FileInfo80*9e94795aSAndroid Build Coastguard Worker bool operator!=(const FileInfo &other) const {
81*9e94795aSAndroid Build Coastguard Worker return !(*this == other);
82*9e94795aSAndroid Build Coastguard Worker }
83*9e94795aSAndroid Build Coastguard Worker };
84*9e94795aSAndroid Build Coastguard Worker
85*9e94795aSAndroid Build Coastguard Worker typedef std::map<std::string, FileInfo> FileInfoMap;
86*9e94795aSAndroid Build Coastguard Worker
87*9e94795aSAndroid Build Coastguard Worker class RunfilesCreator {
88*9e94795aSAndroid Build Coastguard Worker public:
RunfilesCreator(const std::string & output_base)89*9e94795aSAndroid Build Coastguard Worker explicit RunfilesCreator(const std::string &output_base)
90*9e94795aSAndroid Build Coastguard Worker : output_base_(output_base),
91*9e94795aSAndroid Build Coastguard Worker output_filename_("MANIFEST"),
92*9e94795aSAndroid Build Coastguard Worker temp_filename_(output_filename_ + ".tmp") {
93*9e94795aSAndroid Build Coastguard Worker SetupOutputBase();
94*9e94795aSAndroid Build Coastguard Worker if (chdir(output_base_.c_str()) != 0) {
95*9e94795aSAndroid Build Coastguard Worker err(2, "chdir '%s'", output_base_.c_str());
96*9e94795aSAndroid Build Coastguard Worker }
97*9e94795aSAndroid Build Coastguard Worker }
98*9e94795aSAndroid Build Coastguard Worker
ReadManifest(const std::string & manifest_file,bool allow_relative,bool use_metadata)99*9e94795aSAndroid Build Coastguard Worker void ReadManifest(const std::string &manifest_file, bool allow_relative,
100*9e94795aSAndroid Build Coastguard Worker bool use_metadata) {
101*9e94795aSAndroid Build Coastguard Worker FILE *outfile = fopen(temp_filename_.c_str(), "w");
102*9e94795aSAndroid Build Coastguard Worker if (!outfile) {
103*9e94795aSAndroid Build Coastguard Worker err(2, "opening '%s/%s' for writing", output_base_.c_str(),
104*9e94795aSAndroid Build Coastguard Worker temp_filename_.c_str());
105*9e94795aSAndroid Build Coastguard Worker }
106*9e94795aSAndroid Build Coastguard Worker FILE *infile = fopen(manifest_file.c_str(), "r");
107*9e94795aSAndroid Build Coastguard Worker if (!infile) {
108*9e94795aSAndroid Build Coastguard Worker err(2, "opening '%s' for reading", manifest_file.c_str());
109*9e94795aSAndroid Build Coastguard Worker }
110*9e94795aSAndroid Build Coastguard Worker
111*9e94795aSAndroid Build Coastguard Worker // read input manifest
112*9e94795aSAndroid Build Coastguard Worker int lineno = 0;
113*9e94795aSAndroid Build Coastguard Worker char buf[3 * PATH_MAX];
114*9e94795aSAndroid Build Coastguard Worker while (fgets(buf, sizeof buf, infile)) {
115*9e94795aSAndroid Build Coastguard Worker // copy line to output manifest
116*9e94795aSAndroid Build Coastguard Worker if (fputs(buf, outfile) == EOF) {
117*9e94795aSAndroid Build Coastguard Worker err(2, "writing to '%s/%s'", output_base_.c_str(),
118*9e94795aSAndroid Build Coastguard Worker temp_filename_.c_str());
119*9e94795aSAndroid Build Coastguard Worker }
120*9e94795aSAndroid Build Coastguard Worker
121*9e94795aSAndroid Build Coastguard Worker // parse line
122*9e94795aSAndroid Build Coastguard Worker ++lineno;
123*9e94795aSAndroid Build Coastguard Worker // Skip metadata lines. They are used solely for
124*9e94795aSAndroid Build Coastguard Worker // dependency checking.
125*9e94795aSAndroid Build Coastguard Worker if (use_metadata && lineno % 2 == 0) continue;
126*9e94795aSAndroid Build Coastguard Worker
127*9e94795aSAndroid Build Coastguard Worker char *tok = strtok(buf, " \n");
128*9e94795aSAndroid Build Coastguard Worker if (tok == nullptr) {
129*9e94795aSAndroid Build Coastguard Worker continue;
130*9e94795aSAndroid Build Coastguard Worker } else if (*tok == '/') {
131*9e94795aSAndroid Build Coastguard Worker errx(2, "%s:%d: paths must not be absolute", input_filename, lineno);
132*9e94795aSAndroid Build Coastguard Worker }
133*9e94795aSAndroid Build Coastguard Worker std::string link(tok);
134*9e94795aSAndroid Build Coastguard Worker
135*9e94795aSAndroid Build Coastguard Worker const char *target = strtok(nullptr, " \n");
136*9e94795aSAndroid Build Coastguard Worker if (target == nullptr) {
137*9e94795aSAndroid Build Coastguard Worker target = "";
138*9e94795aSAndroid Build Coastguard Worker } else if (strtok(nullptr, " \n") != nullptr) {
139*9e94795aSAndroid Build Coastguard Worker errx(2, "%s:%d: link or target filename contains space", input_filename, lineno);
140*9e94795aSAndroid Build Coastguard Worker } else if (!allow_relative && target[0] != '/') {
141*9e94795aSAndroid Build Coastguard Worker errx(2, "%s:%d: expected absolute path", input_filename, lineno);
142*9e94795aSAndroid Build Coastguard Worker }
143*9e94795aSAndroid Build Coastguard Worker
144*9e94795aSAndroid Build Coastguard Worker FileInfo *info = &manifest_[link];
145*9e94795aSAndroid Build Coastguard Worker if (target[0] == '\0') {
146*9e94795aSAndroid Build Coastguard Worker // No target means an empty file.
147*9e94795aSAndroid Build Coastguard Worker info->type = FILE_TYPE_REGULAR;
148*9e94795aSAndroid Build Coastguard Worker } else {
149*9e94795aSAndroid Build Coastguard Worker info->type = FILE_TYPE_SYMLINK;
150*9e94795aSAndroid Build Coastguard Worker info->symlink_target = target;
151*9e94795aSAndroid Build Coastguard Worker }
152*9e94795aSAndroid Build Coastguard Worker
153*9e94795aSAndroid Build Coastguard Worker FileInfo parent_info;
154*9e94795aSAndroid Build Coastguard Worker parent_info.type = FILE_TYPE_DIRECTORY;
155*9e94795aSAndroid Build Coastguard Worker
156*9e94795aSAndroid Build Coastguard Worker while (true) {
157*9e94795aSAndroid Build Coastguard Worker int k = link.rfind('/');
158*9e94795aSAndroid Build Coastguard Worker if (k < 0) break;
159*9e94795aSAndroid Build Coastguard Worker link.erase(k, std::string::npos);
160*9e94795aSAndroid Build Coastguard Worker if (!manifest_.insert(std::make_pair(link, parent_info)).second) break;
161*9e94795aSAndroid Build Coastguard Worker }
162*9e94795aSAndroid Build Coastguard Worker }
163*9e94795aSAndroid Build Coastguard Worker if (fclose(outfile) != 0) {
164*9e94795aSAndroid Build Coastguard Worker err(2, "writing to '%s/%s'", output_base_.c_str(),
165*9e94795aSAndroid Build Coastguard Worker temp_filename_.c_str());
166*9e94795aSAndroid Build Coastguard Worker }
167*9e94795aSAndroid Build Coastguard Worker fclose(infile);
168*9e94795aSAndroid Build Coastguard Worker
169*9e94795aSAndroid Build Coastguard Worker // Don't delete the temp manifest file.
170*9e94795aSAndroid Build Coastguard Worker manifest_[temp_filename_].type = FILE_TYPE_REGULAR;
171*9e94795aSAndroid Build Coastguard Worker }
172*9e94795aSAndroid Build Coastguard Worker
CreateRunfiles()173*9e94795aSAndroid Build Coastguard Worker void CreateRunfiles() {
174*9e94795aSAndroid Build Coastguard Worker if (unlink(output_filename_.c_str()) != 0 && errno != ENOENT) {
175*9e94795aSAndroid Build Coastguard Worker err(2, "removing previous file at '%s/%s'", output_base_.c_str(),
176*9e94795aSAndroid Build Coastguard Worker output_filename_.c_str());
177*9e94795aSAndroid Build Coastguard Worker }
178*9e94795aSAndroid Build Coastguard Worker
179*9e94795aSAndroid Build Coastguard Worker ScanTreeAndPrune(".");
180*9e94795aSAndroid Build Coastguard Worker CreateFiles();
181*9e94795aSAndroid Build Coastguard Worker
182*9e94795aSAndroid Build Coastguard Worker // rename output file into place
183*9e94795aSAndroid Build Coastguard Worker if (rename(temp_filename_.c_str(), output_filename_.c_str()) != 0) {
184*9e94795aSAndroid Build Coastguard Worker err(2, "renaming '%s/%s' to '%s/%s'",
185*9e94795aSAndroid Build Coastguard Worker output_base_.c_str(), temp_filename_.c_str(),
186*9e94795aSAndroid Build Coastguard Worker output_base_.c_str(), output_filename_.c_str());
187*9e94795aSAndroid Build Coastguard Worker }
188*9e94795aSAndroid Build Coastguard Worker }
189*9e94795aSAndroid Build Coastguard Worker
190*9e94795aSAndroid Build Coastguard Worker private:
SetupOutputBase()191*9e94795aSAndroid Build Coastguard Worker void SetupOutputBase() {
192*9e94795aSAndroid Build Coastguard Worker struct stat st;
193*9e94795aSAndroid Build Coastguard Worker if (stat(output_base_.c_str(), &st) != 0) {
194*9e94795aSAndroid Build Coastguard Worker // Technically, this will cause problems if the user's umask contains
195*9e94795aSAndroid Build Coastguard Worker // 0200, but we don't care. Anyone who does that deserves what's coming.
196*9e94795aSAndroid Build Coastguard Worker if (mkdir(output_base_.c_str(), 0777) != 0) {
197*9e94795aSAndroid Build Coastguard Worker err(2, "creating directory '%s'", output_base_.c_str());
198*9e94795aSAndroid Build Coastguard Worker }
199*9e94795aSAndroid Build Coastguard Worker } else {
200*9e94795aSAndroid Build Coastguard Worker EnsureDirReadAndWritePerms(output_base_);
201*9e94795aSAndroid Build Coastguard Worker }
202*9e94795aSAndroid Build Coastguard Worker }
203*9e94795aSAndroid Build Coastguard Worker
ScanTreeAndPrune(const std::string & path)204*9e94795aSAndroid Build Coastguard Worker void ScanTreeAndPrune(const std::string &path) {
205*9e94795aSAndroid Build Coastguard Worker // A note on non-empty files:
206*9e94795aSAndroid Build Coastguard Worker // We don't distinguish between empty and non-empty files. That is, if
207*9e94795aSAndroid Build Coastguard Worker // there's a file that has contents, we don't truncate it here, even though
208*9e94795aSAndroid Build Coastguard Worker // the manifest supports creation of empty files, only. Given that
209*9e94795aSAndroid Build Coastguard Worker // .runfiles are *supposed* to be immutable, this shouldn't be a problem.
210*9e94795aSAndroid Build Coastguard Worker EnsureDirReadAndWritePerms(path);
211*9e94795aSAndroid Build Coastguard Worker
212*9e94795aSAndroid Build Coastguard Worker struct dirent *entry;
213*9e94795aSAndroid Build Coastguard Worker DIR *dh = opendir(path.c_str());
214*9e94795aSAndroid Build Coastguard Worker if (!dh) {
215*9e94795aSAndroid Build Coastguard Worker err(2, "opendir '%s'", path.c_str());
216*9e94795aSAndroid Build Coastguard Worker }
217*9e94795aSAndroid Build Coastguard Worker
218*9e94795aSAndroid Build Coastguard Worker errno = 0;
219*9e94795aSAndroid Build Coastguard Worker const std::string prefix = (path == "." ? "" : path + "/");
220*9e94795aSAndroid Build Coastguard Worker while ((entry = readdir(dh)) != nullptr) {
221*9e94795aSAndroid Build Coastguard Worker if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue;
222*9e94795aSAndroid Build Coastguard Worker
223*9e94795aSAndroid Build Coastguard Worker std::string entry_path = prefix + entry->d_name;
224*9e94795aSAndroid Build Coastguard Worker FileInfo actual_info;
225*9e94795aSAndroid Build Coastguard Worker actual_info.type = DentryToFileType(entry_path, entry);
226*9e94795aSAndroid Build Coastguard Worker
227*9e94795aSAndroid Build Coastguard Worker if (actual_info.type == FILE_TYPE_SYMLINK) {
228*9e94795aSAndroid Build Coastguard Worker ReadLinkOrDie(entry_path, &actual_info.symlink_target);
229*9e94795aSAndroid Build Coastguard Worker }
230*9e94795aSAndroid Build Coastguard Worker
231*9e94795aSAndroid Build Coastguard Worker FileInfoMap::iterator expected_it = manifest_.find(entry_path);
232*9e94795aSAndroid Build Coastguard Worker if (expected_it == manifest_.end() ||
233*9e94795aSAndroid Build Coastguard Worker expected_it->second != actual_info) {
234*9e94795aSAndroid Build Coastguard Worker DelTree(entry_path, actual_info.type);
235*9e94795aSAndroid Build Coastguard Worker } else {
236*9e94795aSAndroid Build Coastguard Worker manifest_.erase(expected_it);
237*9e94795aSAndroid Build Coastguard Worker if (actual_info.type == FILE_TYPE_DIRECTORY) {
238*9e94795aSAndroid Build Coastguard Worker ScanTreeAndPrune(entry_path);
239*9e94795aSAndroid Build Coastguard Worker }
240*9e94795aSAndroid Build Coastguard Worker }
241*9e94795aSAndroid Build Coastguard Worker
242*9e94795aSAndroid Build Coastguard Worker errno = 0;
243*9e94795aSAndroid Build Coastguard Worker }
244*9e94795aSAndroid Build Coastguard Worker if (errno != 0) {
245*9e94795aSAndroid Build Coastguard Worker err(2, "reading directory '%s'", path.c_str());
246*9e94795aSAndroid Build Coastguard Worker }
247*9e94795aSAndroid Build Coastguard Worker closedir(dh);
248*9e94795aSAndroid Build Coastguard Worker }
249*9e94795aSAndroid Build Coastguard Worker
CreateFiles()250*9e94795aSAndroid Build Coastguard Worker void CreateFiles() {
251*9e94795aSAndroid Build Coastguard Worker for (FileInfoMap::const_iterator it = manifest_.begin();
252*9e94795aSAndroid Build Coastguard Worker it != manifest_.end(); ++it) {
253*9e94795aSAndroid Build Coastguard Worker const std::string &path = it->first;
254*9e94795aSAndroid Build Coastguard Worker switch (it->second.type) {
255*9e94795aSAndroid Build Coastguard Worker case FILE_TYPE_DIRECTORY:
256*9e94795aSAndroid Build Coastguard Worker if (mkdir(path.c_str(), 0777) != 0) {
257*9e94795aSAndroid Build Coastguard Worker err(2, "mkdir '%s'", path.c_str());
258*9e94795aSAndroid Build Coastguard Worker }
259*9e94795aSAndroid Build Coastguard Worker break;
260*9e94795aSAndroid Build Coastguard Worker case FILE_TYPE_REGULAR:
261*9e94795aSAndroid Build Coastguard Worker {
262*9e94795aSAndroid Build Coastguard Worker int fd = open(path.c_str(), O_CREAT|O_EXCL|O_WRONLY, 0555);
263*9e94795aSAndroid Build Coastguard Worker if (fd < 0) {
264*9e94795aSAndroid Build Coastguard Worker err(2, "creating empty file '%s'", path.c_str());
265*9e94795aSAndroid Build Coastguard Worker }
266*9e94795aSAndroid Build Coastguard Worker close(fd);
267*9e94795aSAndroid Build Coastguard Worker }
268*9e94795aSAndroid Build Coastguard Worker break;
269*9e94795aSAndroid Build Coastguard Worker case FILE_TYPE_SYMLINK:
270*9e94795aSAndroid Build Coastguard Worker {
271*9e94795aSAndroid Build Coastguard Worker const std::string& target = it->second.symlink_target;
272*9e94795aSAndroid Build Coastguard Worker if (symlink(target.c_str(), path.c_str()) != 0) {
273*9e94795aSAndroid Build Coastguard Worker err(2, "symlinking '%s' -> '%s'", path.c_str(), target.c_str());
274*9e94795aSAndroid Build Coastguard Worker }
275*9e94795aSAndroid Build Coastguard Worker }
276*9e94795aSAndroid Build Coastguard Worker break;
277*9e94795aSAndroid Build Coastguard Worker }
278*9e94795aSAndroid Build Coastguard Worker }
279*9e94795aSAndroid Build Coastguard Worker }
280*9e94795aSAndroid Build Coastguard Worker
DentryToFileType(const std::string & path,struct dirent * ent)281*9e94795aSAndroid Build Coastguard Worker FileType DentryToFileType(const std::string &path, struct dirent *ent) {
282*9e94795aSAndroid Build Coastguard Worker #ifdef _DIRENT_HAVE_D_TYPE
283*9e94795aSAndroid Build Coastguard Worker if (ent->d_type != DT_UNKNOWN) {
284*9e94795aSAndroid Build Coastguard Worker if (ent->d_type == DT_DIR) {
285*9e94795aSAndroid Build Coastguard Worker return FILE_TYPE_DIRECTORY;
286*9e94795aSAndroid Build Coastguard Worker } else if (ent->d_type == DT_LNK) {
287*9e94795aSAndroid Build Coastguard Worker return FILE_TYPE_SYMLINK;
288*9e94795aSAndroid Build Coastguard Worker } else {
289*9e94795aSAndroid Build Coastguard Worker return FILE_TYPE_REGULAR;
290*9e94795aSAndroid Build Coastguard Worker }
291*9e94795aSAndroid Build Coastguard Worker } else // NOLINT (the brace is in the next line)
292*9e94795aSAndroid Build Coastguard Worker #endif
293*9e94795aSAndroid Build Coastguard Worker {
294*9e94795aSAndroid Build Coastguard Worker struct stat st;
295*9e94795aSAndroid Build Coastguard Worker LStatOrDie(path, &st);
296*9e94795aSAndroid Build Coastguard Worker if (S_ISDIR(st.st_mode)) {
297*9e94795aSAndroid Build Coastguard Worker return FILE_TYPE_DIRECTORY;
298*9e94795aSAndroid Build Coastguard Worker } else if (S_ISLNK(st.st_mode)) {
299*9e94795aSAndroid Build Coastguard Worker return FILE_TYPE_SYMLINK;
300*9e94795aSAndroid Build Coastguard Worker } else {
301*9e94795aSAndroid Build Coastguard Worker return FILE_TYPE_REGULAR;
302*9e94795aSAndroid Build Coastguard Worker }
303*9e94795aSAndroid Build Coastguard Worker }
304*9e94795aSAndroid Build Coastguard Worker }
305*9e94795aSAndroid Build Coastguard Worker
LStatOrDie(const std::string & path,struct stat * st)306*9e94795aSAndroid Build Coastguard Worker void LStatOrDie(const std::string &path, struct stat *st) {
307*9e94795aSAndroid Build Coastguard Worker if (lstat(path.c_str(), st) != 0) {
308*9e94795aSAndroid Build Coastguard Worker err(2, "lstating file '%s'", path.c_str());
309*9e94795aSAndroid Build Coastguard Worker }
310*9e94795aSAndroid Build Coastguard Worker }
311*9e94795aSAndroid Build Coastguard Worker
StatOrDie(const std::string & path,struct stat * st)312*9e94795aSAndroid Build Coastguard Worker void StatOrDie(const std::string &path, struct stat *st) {
313*9e94795aSAndroid Build Coastguard Worker if (stat(path.c_str(), st) != 0) {
314*9e94795aSAndroid Build Coastguard Worker err(2, "stating file '%s'", path.c_str());
315*9e94795aSAndroid Build Coastguard Worker }
316*9e94795aSAndroid Build Coastguard Worker }
317*9e94795aSAndroid Build Coastguard Worker
ReadLinkOrDie(const std::string & path,std::string * output)318*9e94795aSAndroid Build Coastguard Worker void ReadLinkOrDie(const std::string &path, std::string *output) {
319*9e94795aSAndroid Build Coastguard Worker char readlink_buffer[PATH_MAX];
320*9e94795aSAndroid Build Coastguard Worker int sz = readlink(path.c_str(), readlink_buffer, sizeof(readlink_buffer));
321*9e94795aSAndroid Build Coastguard Worker if (sz < 0) {
322*9e94795aSAndroid Build Coastguard Worker err(2, "reading symlink '%s'", path.c_str());
323*9e94795aSAndroid Build Coastguard Worker }
324*9e94795aSAndroid Build Coastguard Worker // readlink returns a non-null terminated string.
325*9e94795aSAndroid Build Coastguard Worker std::string(readlink_buffer, sz).swap(*output);
326*9e94795aSAndroid Build Coastguard Worker }
327*9e94795aSAndroid Build Coastguard Worker
EnsureDirReadAndWritePerms(const std::string & path)328*9e94795aSAndroid Build Coastguard Worker void EnsureDirReadAndWritePerms(const std::string &path) {
329*9e94795aSAndroid Build Coastguard Worker const int kMode = 0700;
330*9e94795aSAndroid Build Coastguard Worker struct stat st;
331*9e94795aSAndroid Build Coastguard Worker LStatOrDie(path, &st);
332*9e94795aSAndroid Build Coastguard Worker if ((st.st_mode & kMode) != kMode) {
333*9e94795aSAndroid Build Coastguard Worker int new_mode = st.st_mode | kMode;
334*9e94795aSAndroid Build Coastguard Worker if (chmod(path.c_str(), new_mode) != 0) {
335*9e94795aSAndroid Build Coastguard Worker err(2, "chmod '%s'", path.c_str());
336*9e94795aSAndroid Build Coastguard Worker }
337*9e94795aSAndroid Build Coastguard Worker }
338*9e94795aSAndroid Build Coastguard Worker }
339*9e94795aSAndroid Build Coastguard Worker
DelTree(const std::string & path,FileType file_type)340*9e94795aSAndroid Build Coastguard Worker bool DelTree(const std::string &path, FileType file_type) {
341*9e94795aSAndroid Build Coastguard Worker if (file_type != FILE_TYPE_DIRECTORY) {
342*9e94795aSAndroid Build Coastguard Worker if (unlink(path.c_str()) != 0) {
343*9e94795aSAndroid Build Coastguard Worker err(2, "unlinking '%s'", path.c_str());
344*9e94795aSAndroid Build Coastguard Worker return false;
345*9e94795aSAndroid Build Coastguard Worker }
346*9e94795aSAndroid Build Coastguard Worker return true;
347*9e94795aSAndroid Build Coastguard Worker }
348*9e94795aSAndroid Build Coastguard Worker
349*9e94795aSAndroid Build Coastguard Worker EnsureDirReadAndWritePerms(path);
350*9e94795aSAndroid Build Coastguard Worker
351*9e94795aSAndroid Build Coastguard Worker struct dirent *entry;
352*9e94795aSAndroid Build Coastguard Worker DIR *dh = opendir(path.c_str());
353*9e94795aSAndroid Build Coastguard Worker if (!dh) {
354*9e94795aSAndroid Build Coastguard Worker err(2, "opendir '%s'", path.c_str());
355*9e94795aSAndroid Build Coastguard Worker }
356*9e94795aSAndroid Build Coastguard Worker errno = 0;
357*9e94795aSAndroid Build Coastguard Worker while ((entry = readdir(dh)) != nullptr) {
358*9e94795aSAndroid Build Coastguard Worker if (!strcmp(entry->d_name, ".") || !strcmp(entry->d_name, "..")) continue;
359*9e94795aSAndroid Build Coastguard Worker const std::string entry_path = path + '/' + entry->d_name;
360*9e94795aSAndroid Build Coastguard Worker FileType entry_file_type = DentryToFileType(entry_path, entry);
361*9e94795aSAndroid Build Coastguard Worker DelTree(entry_path, entry_file_type);
362*9e94795aSAndroid Build Coastguard Worker errno = 0;
363*9e94795aSAndroid Build Coastguard Worker }
364*9e94795aSAndroid Build Coastguard Worker if (errno != 0) {
365*9e94795aSAndroid Build Coastguard Worker err(2, "readdir '%s'", path.c_str());
366*9e94795aSAndroid Build Coastguard Worker }
367*9e94795aSAndroid Build Coastguard Worker closedir(dh);
368*9e94795aSAndroid Build Coastguard Worker if (rmdir(path.c_str()) != 0) {
369*9e94795aSAndroid Build Coastguard Worker err(2, "rmdir '%s'", path.c_str());
370*9e94795aSAndroid Build Coastguard Worker }
371*9e94795aSAndroid Build Coastguard Worker return true;
372*9e94795aSAndroid Build Coastguard Worker }
373*9e94795aSAndroid Build Coastguard Worker
374*9e94795aSAndroid Build Coastguard Worker private:
375*9e94795aSAndroid Build Coastguard Worker std::string output_base_;
376*9e94795aSAndroid Build Coastguard Worker std::string output_filename_;
377*9e94795aSAndroid Build Coastguard Worker std::string temp_filename_;
378*9e94795aSAndroid Build Coastguard Worker
379*9e94795aSAndroid Build Coastguard Worker FileInfoMap manifest_;
380*9e94795aSAndroid Build Coastguard Worker };
381*9e94795aSAndroid Build Coastguard Worker
main(int argc,char ** argv)382*9e94795aSAndroid Build Coastguard Worker int main(int argc, char **argv) {
383*9e94795aSAndroid Build Coastguard Worker argv0 = argv[0];
384*9e94795aSAndroid Build Coastguard Worker
385*9e94795aSAndroid Build Coastguard Worker argc--; argv++;
386*9e94795aSAndroid Build Coastguard Worker bool allow_relative = false;
387*9e94795aSAndroid Build Coastguard Worker bool use_metadata = false;
388*9e94795aSAndroid Build Coastguard Worker
389*9e94795aSAndroid Build Coastguard Worker while (argc >= 1) {
390*9e94795aSAndroid Build Coastguard Worker if (strcmp(argv[0], "--allow_relative") == 0) {
391*9e94795aSAndroid Build Coastguard Worker allow_relative = true;
392*9e94795aSAndroid Build Coastguard Worker argc--; argv++;
393*9e94795aSAndroid Build Coastguard Worker } else if (strcmp(argv[0], "--use_metadata") == 0) {
394*9e94795aSAndroid Build Coastguard Worker use_metadata = true;
395*9e94795aSAndroid Build Coastguard Worker argc--; argv++;
396*9e94795aSAndroid Build Coastguard Worker } else {
397*9e94795aSAndroid Build Coastguard Worker break;
398*9e94795aSAndroid Build Coastguard Worker }
399*9e94795aSAndroid Build Coastguard Worker }
400*9e94795aSAndroid Build Coastguard Worker
401*9e94795aSAndroid Build Coastguard Worker if (argc != 2) {
402*9e94795aSAndroid Build Coastguard Worker fprintf(stderr, "usage: %s "
403*9e94795aSAndroid Build Coastguard Worker "[--allow_relative] [--use_metadata] "
404*9e94795aSAndroid Build Coastguard Worker "INPUT RUNFILES\n",
405*9e94795aSAndroid Build Coastguard Worker argv0);
406*9e94795aSAndroid Build Coastguard Worker return 1;
407*9e94795aSAndroid Build Coastguard Worker }
408*9e94795aSAndroid Build Coastguard Worker
409*9e94795aSAndroid Build Coastguard Worker input_filename = argv[0];
410*9e94795aSAndroid Build Coastguard Worker output_base_dir = argv[1];
411*9e94795aSAndroid Build Coastguard Worker
412*9e94795aSAndroid Build Coastguard Worker std::string manifest_file = input_filename;
413*9e94795aSAndroid Build Coastguard Worker if (input_filename[0] != '/') {
414*9e94795aSAndroid Build Coastguard Worker char cwd_buf[PATH_MAX];
415*9e94795aSAndroid Build Coastguard Worker if (getcwd(cwd_buf, sizeof(cwd_buf)) == nullptr) {
416*9e94795aSAndroid Build Coastguard Worker err(2, "getcwd failed");
417*9e94795aSAndroid Build Coastguard Worker }
418*9e94795aSAndroid Build Coastguard Worker manifest_file = std::string(cwd_buf) + '/' + manifest_file;
419*9e94795aSAndroid Build Coastguard Worker }
420*9e94795aSAndroid Build Coastguard Worker
421*9e94795aSAndroid Build Coastguard Worker RunfilesCreator runfiles_creator(output_base_dir);
422*9e94795aSAndroid Build Coastguard Worker runfiles_creator.ReadManifest(manifest_file, allow_relative, use_metadata);
423*9e94795aSAndroid Build Coastguard Worker runfiles_creator.CreateRunfiles();
424*9e94795aSAndroid Build Coastguard Worker
425*9e94795aSAndroid Build Coastguard Worker return 0;
426*9e94795aSAndroid Build Coastguard Worker }
427