xref: /aosp_15_r20/external/protobuf/src/google/protobuf/testing/file.cc (revision 1b3f573f81763fcece89efc2b6a5209149e44ab8)
1*1b3f573fSAndroid Build Coastguard Worker // Protocol Buffers - Google's data interchange format
2*1b3f573fSAndroid Build Coastguard Worker // Copyright 2008 Google Inc.  All rights reserved.
3*1b3f573fSAndroid Build Coastguard Worker // https://developers.google.com/protocol-buffers/
4*1b3f573fSAndroid Build Coastguard Worker //
5*1b3f573fSAndroid Build Coastguard Worker // Redistribution and use in source and binary forms, with or without
6*1b3f573fSAndroid Build Coastguard Worker // modification, are permitted provided that the following conditions are
7*1b3f573fSAndroid Build Coastguard Worker // met:
8*1b3f573fSAndroid Build Coastguard Worker //
9*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions of source code must retain the above copyright
10*1b3f573fSAndroid Build Coastguard Worker // notice, this list of conditions and the following disclaimer.
11*1b3f573fSAndroid Build Coastguard Worker //     * Redistributions in binary form must reproduce the above
12*1b3f573fSAndroid Build Coastguard Worker // copyright notice, this list of conditions and the following disclaimer
13*1b3f573fSAndroid Build Coastguard Worker // in the documentation and/or other materials provided with the
14*1b3f573fSAndroid Build Coastguard Worker // distribution.
15*1b3f573fSAndroid Build Coastguard Worker //     * Neither the name of Google Inc. nor the names of its
16*1b3f573fSAndroid Build Coastguard Worker // contributors may be used to endorse or promote products derived from
17*1b3f573fSAndroid Build Coastguard Worker // this software without specific prior written permission.
18*1b3f573fSAndroid Build Coastguard Worker //
19*1b3f573fSAndroid Build Coastguard Worker // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
20*1b3f573fSAndroid Build Coastguard Worker // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
21*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
22*1b3f573fSAndroid Build Coastguard Worker // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
23*1b3f573fSAndroid Build Coastguard Worker // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
24*1b3f573fSAndroid Build Coastguard Worker // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
25*1b3f573fSAndroid Build Coastguard Worker // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
26*1b3f573fSAndroid Build Coastguard Worker // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
27*1b3f573fSAndroid Build Coastguard Worker // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
28*1b3f573fSAndroid Build Coastguard Worker // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29*1b3f573fSAndroid Build Coastguard Worker // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
30*1b3f573fSAndroid Build Coastguard Worker 
31*1b3f573fSAndroid Build Coastguard Worker // Author: [email protected] (Kenton Varda)
32*1b3f573fSAndroid Build Coastguard Worker // emulates google3/file/base/file.cc
33*1b3f573fSAndroid Build Coastguard Worker 
34*1b3f573fSAndroid Build Coastguard Worker #include <google/protobuf/testing/file.h>
35*1b3f573fSAndroid Build Coastguard Worker #include <stdio.h>
36*1b3f573fSAndroid Build Coastguard Worker #include <sys/stat.h>
37*1b3f573fSAndroid Build Coastguard Worker #include <sys/types.h>
38*1b3f573fSAndroid Build Coastguard Worker #ifdef _MSC_VER
39*1b3f573fSAndroid Build Coastguard Worker #define WIN32_LEAN_AND_MEAN  // yeah, right
40*1b3f573fSAndroid Build Coastguard Worker #include <windows.h>         // Find*File().  :(
41*1b3f573fSAndroid Build Coastguard Worker // #include <direct.h>
42*1b3f573fSAndroid Build Coastguard Worker #else
43*1b3f573fSAndroid Build Coastguard Worker #include <dirent.h>
44*1b3f573fSAndroid Build Coastguard Worker #include <unistd.h>
45*1b3f573fSAndroid Build Coastguard Worker #endif
46*1b3f573fSAndroid Build Coastguard Worker #include <errno.h>
47*1b3f573fSAndroid Build Coastguard Worker 
48*1b3f573fSAndroid Build Coastguard Worker #include <google/protobuf/io/io_win32.h>
49*1b3f573fSAndroid Build Coastguard Worker #include <google/protobuf/stubs/logging.h>
50*1b3f573fSAndroid Build Coastguard Worker 
51*1b3f573fSAndroid Build Coastguard Worker namespace google {
52*1b3f573fSAndroid Build Coastguard Worker namespace protobuf {
53*1b3f573fSAndroid Build Coastguard Worker 
54*1b3f573fSAndroid Build Coastguard Worker #ifdef _WIN32
55*1b3f573fSAndroid Build Coastguard Worker // Windows doesn't have symbolic links.
56*1b3f573fSAndroid Build Coastguard Worker #define lstat stat
57*1b3f573fSAndroid Build Coastguard Worker // DO NOT include <io.h>, instead create functions in io_win32.{h,cc} and import
58*1b3f573fSAndroid Build Coastguard Worker // them like we do below.
59*1b3f573fSAndroid Build Coastguard Worker #endif
60*1b3f573fSAndroid Build Coastguard Worker 
61*1b3f573fSAndroid Build Coastguard Worker #ifdef _WIN32
62*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::io::win32::access;
63*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::io::win32::chdir;
64*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::io::win32::fopen;
65*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::io::win32::mkdir;
66*1b3f573fSAndroid Build Coastguard Worker using google::protobuf::io::win32::stat;
67*1b3f573fSAndroid Build Coastguard Worker #endif
68*1b3f573fSAndroid Build Coastguard Worker 
Exists(const std::string & name)69*1b3f573fSAndroid Build Coastguard Worker bool File::Exists(const std::string& name) {
70*1b3f573fSAndroid Build Coastguard Worker   return access(name.c_str(), F_OK) == 0;
71*1b3f573fSAndroid Build Coastguard Worker }
72*1b3f573fSAndroid Build Coastguard Worker 
ReadFileToString(const std::string & name,std::string * output,bool text_mode)73*1b3f573fSAndroid Build Coastguard Worker bool File::ReadFileToString(const std::string& name, std::string* output,
74*1b3f573fSAndroid Build Coastguard Worker                             bool text_mode) {
75*1b3f573fSAndroid Build Coastguard Worker   char buffer[1024];
76*1b3f573fSAndroid Build Coastguard Worker   FILE* file = fopen(name.c_str(), text_mode ? "rt" : "rb");
77*1b3f573fSAndroid Build Coastguard Worker   if (file == NULL) return false;
78*1b3f573fSAndroid Build Coastguard Worker 
79*1b3f573fSAndroid Build Coastguard Worker   while (true) {
80*1b3f573fSAndroid Build Coastguard Worker     size_t n = fread(buffer, 1, sizeof(buffer), file);
81*1b3f573fSAndroid Build Coastguard Worker     if (n <= 0) break;
82*1b3f573fSAndroid Build Coastguard Worker     output->append(buffer, n);
83*1b3f573fSAndroid Build Coastguard Worker   }
84*1b3f573fSAndroid Build Coastguard Worker 
85*1b3f573fSAndroid Build Coastguard Worker   int error = ferror(file);
86*1b3f573fSAndroid Build Coastguard Worker   if (fclose(file) != 0) return false;
87*1b3f573fSAndroid Build Coastguard Worker   return error == 0;
88*1b3f573fSAndroid Build Coastguard Worker }
89*1b3f573fSAndroid Build Coastguard Worker 
ReadFileToStringOrDie(const std::string & name,std::string * output)90*1b3f573fSAndroid Build Coastguard Worker void File::ReadFileToStringOrDie(const std::string& name, std::string* output) {
91*1b3f573fSAndroid Build Coastguard Worker   GOOGLE_CHECK(ReadFileToString(name, output)) << "Could not read: " << name;
92*1b3f573fSAndroid Build Coastguard Worker }
93*1b3f573fSAndroid Build Coastguard Worker 
WriteStringToFile(const std::string & contents,const std::string & name)94*1b3f573fSAndroid Build Coastguard Worker bool File::WriteStringToFile(const std::string& contents,
95*1b3f573fSAndroid Build Coastguard Worker                              const std::string& name) {
96*1b3f573fSAndroid Build Coastguard Worker   FILE* file = fopen(name.c_str(), "wb");
97*1b3f573fSAndroid Build Coastguard Worker   if (file == NULL) {
98*1b3f573fSAndroid Build Coastguard Worker     GOOGLE_LOG(ERROR) << "fopen(" << name << ", \"wb\"): " << strerror(errno);
99*1b3f573fSAndroid Build Coastguard Worker     return false;
100*1b3f573fSAndroid Build Coastguard Worker   }
101*1b3f573fSAndroid Build Coastguard Worker 
102*1b3f573fSAndroid Build Coastguard Worker   if (fwrite(contents.data(), 1, contents.size(), file) != contents.size()) {
103*1b3f573fSAndroid Build Coastguard Worker     GOOGLE_LOG(ERROR) << "fwrite(" << name << "): " << strerror(errno);
104*1b3f573fSAndroid Build Coastguard Worker     fclose(file);
105*1b3f573fSAndroid Build Coastguard Worker     return false;
106*1b3f573fSAndroid Build Coastguard Worker   }
107*1b3f573fSAndroid Build Coastguard Worker 
108*1b3f573fSAndroid Build Coastguard Worker   if (fclose(file) != 0) {
109*1b3f573fSAndroid Build Coastguard Worker     return false;
110*1b3f573fSAndroid Build Coastguard Worker   }
111*1b3f573fSAndroid Build Coastguard Worker   return true;
112*1b3f573fSAndroid Build Coastguard Worker }
113*1b3f573fSAndroid Build Coastguard Worker 
WriteStringToFileOrDie(const std::string & contents,const std::string & name)114*1b3f573fSAndroid Build Coastguard Worker void File::WriteStringToFileOrDie(const std::string& contents,
115*1b3f573fSAndroid Build Coastguard Worker                                   const std::string& name) {
116*1b3f573fSAndroid Build Coastguard Worker   FILE* file = fopen(name.c_str(), "wb");
117*1b3f573fSAndroid Build Coastguard Worker   GOOGLE_CHECK(file != NULL)
118*1b3f573fSAndroid Build Coastguard Worker       << "fopen(" << name << ", \"wb\"): " << strerror(errno);
119*1b3f573fSAndroid Build Coastguard Worker   GOOGLE_CHECK_EQ(fwrite(contents.data(), 1, contents.size(), file),
120*1b3f573fSAndroid Build Coastguard Worker                   contents.size())
121*1b3f573fSAndroid Build Coastguard Worker       << "fwrite(" << name << "): " << strerror(errno);
122*1b3f573fSAndroid Build Coastguard Worker   GOOGLE_CHECK(fclose(file) == 0)
123*1b3f573fSAndroid Build Coastguard Worker       << "fclose(" << name << "): " << strerror(errno);
124*1b3f573fSAndroid Build Coastguard Worker }
125*1b3f573fSAndroid Build Coastguard Worker 
CreateDir(const std::string & name,int mode)126*1b3f573fSAndroid Build Coastguard Worker bool File::CreateDir(const std::string& name, int mode) {
127*1b3f573fSAndroid Build Coastguard Worker   if (!name.empty()) {
128*1b3f573fSAndroid Build Coastguard Worker     GOOGLE_CHECK_OK(name[name.size() - 1] != '.');
129*1b3f573fSAndroid Build Coastguard Worker   }
130*1b3f573fSAndroid Build Coastguard Worker   return mkdir(name.c_str(), mode) == 0;
131*1b3f573fSAndroid Build Coastguard Worker }
132*1b3f573fSAndroid Build Coastguard Worker 
RecursivelyCreateDir(const std::string & path,int mode)133*1b3f573fSAndroid Build Coastguard Worker bool File::RecursivelyCreateDir(const std::string& path, int mode) {
134*1b3f573fSAndroid Build Coastguard Worker   if (CreateDir(path, mode)) return true;
135*1b3f573fSAndroid Build Coastguard Worker 
136*1b3f573fSAndroid Build Coastguard Worker   if (Exists(path)) return false;
137*1b3f573fSAndroid Build Coastguard Worker 
138*1b3f573fSAndroid Build Coastguard Worker   // Try creating the parent.
139*1b3f573fSAndroid Build Coastguard Worker   std::string::size_type slashpos = path.find_last_of('/');
140*1b3f573fSAndroid Build Coastguard Worker   if (slashpos == std::string::npos) {
141*1b3f573fSAndroid Build Coastguard Worker     // No parent given.
142*1b3f573fSAndroid Build Coastguard Worker     return false;
143*1b3f573fSAndroid Build Coastguard Worker   }
144*1b3f573fSAndroid Build Coastguard Worker 
145*1b3f573fSAndroid Build Coastguard Worker   return RecursivelyCreateDir(path.substr(0, slashpos), mode) &&
146*1b3f573fSAndroid Build Coastguard Worker          CreateDir(path, mode);
147*1b3f573fSAndroid Build Coastguard Worker }
148*1b3f573fSAndroid Build Coastguard Worker 
DeleteRecursively(const std::string & name,void * dummy1,void * dummy2)149*1b3f573fSAndroid Build Coastguard Worker void File::DeleteRecursively(const std::string& name, void* dummy1,
150*1b3f573fSAndroid Build Coastguard Worker                              void* dummy2) {
151*1b3f573fSAndroid Build Coastguard Worker   if (name.empty()) return;
152*1b3f573fSAndroid Build Coastguard Worker 
153*1b3f573fSAndroid Build Coastguard Worker   // We don't care too much about error checking here since this is only used
154*1b3f573fSAndroid Build Coastguard Worker   // in tests to delete temporary directories that are under /tmp anyway.
155*1b3f573fSAndroid Build Coastguard Worker 
156*1b3f573fSAndroid Build Coastguard Worker #ifdef _MSC_VER
157*1b3f573fSAndroid Build Coastguard Worker   // This interface is so weird.
158*1b3f573fSAndroid Build Coastguard Worker   WIN32_FIND_DATAA find_data;
159*1b3f573fSAndroid Build Coastguard Worker   HANDLE find_handle = FindFirstFileA((name + "/*").c_str(), &find_data);
160*1b3f573fSAndroid Build Coastguard Worker   if (find_handle == INVALID_HANDLE_VALUE) {
161*1b3f573fSAndroid Build Coastguard Worker     // Just delete it, whatever it is.
162*1b3f573fSAndroid Build Coastguard Worker     DeleteFileA(name.c_str());
163*1b3f573fSAndroid Build Coastguard Worker     RemoveDirectoryA(name.c_str());
164*1b3f573fSAndroid Build Coastguard Worker     return;
165*1b3f573fSAndroid Build Coastguard Worker   }
166*1b3f573fSAndroid Build Coastguard Worker 
167*1b3f573fSAndroid Build Coastguard Worker   do {
168*1b3f573fSAndroid Build Coastguard Worker     std::string entry_name = find_data.cFileName;
169*1b3f573fSAndroid Build Coastguard Worker     if (entry_name != "." && entry_name != "..") {
170*1b3f573fSAndroid Build Coastguard Worker       std::string path = name + "/" + entry_name;
171*1b3f573fSAndroid Build Coastguard Worker       if (find_data.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) {
172*1b3f573fSAndroid Build Coastguard Worker         DeleteRecursively(path, NULL, NULL);
173*1b3f573fSAndroid Build Coastguard Worker         RemoveDirectoryA(path.c_str());
174*1b3f573fSAndroid Build Coastguard Worker       } else {
175*1b3f573fSAndroid Build Coastguard Worker         DeleteFileA(path.c_str());
176*1b3f573fSAndroid Build Coastguard Worker       }
177*1b3f573fSAndroid Build Coastguard Worker     }
178*1b3f573fSAndroid Build Coastguard Worker   } while(FindNextFileA(find_handle, &find_data));
179*1b3f573fSAndroid Build Coastguard Worker   FindClose(find_handle);
180*1b3f573fSAndroid Build Coastguard Worker 
181*1b3f573fSAndroid Build Coastguard Worker   RemoveDirectoryA(name.c_str());
182*1b3f573fSAndroid Build Coastguard Worker #else
183*1b3f573fSAndroid Build Coastguard Worker   // Use opendir()!  Yay!
184*1b3f573fSAndroid Build Coastguard Worker   // lstat = Don't follow symbolic links.
185*1b3f573fSAndroid Build Coastguard Worker   struct stat stats;
186*1b3f573fSAndroid Build Coastguard Worker   if (lstat(name.c_str(), &stats) != 0) return;
187*1b3f573fSAndroid Build Coastguard Worker 
188*1b3f573fSAndroid Build Coastguard Worker   if (S_ISDIR(stats.st_mode)) {
189*1b3f573fSAndroid Build Coastguard Worker     DIR* dir = opendir(name.c_str());
190*1b3f573fSAndroid Build Coastguard Worker     if (dir != NULL) {
191*1b3f573fSAndroid Build Coastguard Worker       while (true) {
192*1b3f573fSAndroid Build Coastguard Worker         struct dirent* entry = readdir(dir);
193*1b3f573fSAndroid Build Coastguard Worker         if (entry == NULL) break;
194*1b3f573fSAndroid Build Coastguard Worker         std::string entry_name = entry->d_name;
195*1b3f573fSAndroid Build Coastguard Worker         if (entry_name != "." && entry_name != "..") {
196*1b3f573fSAndroid Build Coastguard Worker           DeleteRecursively(name + "/" + entry_name, NULL, NULL);
197*1b3f573fSAndroid Build Coastguard Worker         }
198*1b3f573fSAndroid Build Coastguard Worker       }
199*1b3f573fSAndroid Build Coastguard Worker     }
200*1b3f573fSAndroid Build Coastguard Worker 
201*1b3f573fSAndroid Build Coastguard Worker     closedir(dir);
202*1b3f573fSAndroid Build Coastguard Worker     rmdir(name.c_str());
203*1b3f573fSAndroid Build Coastguard Worker 
204*1b3f573fSAndroid Build Coastguard Worker   } else if (S_ISREG(stats.st_mode)) {
205*1b3f573fSAndroid Build Coastguard Worker     remove(name.c_str());
206*1b3f573fSAndroid Build Coastguard Worker   }
207*1b3f573fSAndroid Build Coastguard Worker #endif
208*1b3f573fSAndroid Build Coastguard Worker }
209*1b3f573fSAndroid Build Coastguard Worker 
ChangeWorkingDirectory(const std::string & new_working_directory)210*1b3f573fSAndroid Build Coastguard Worker bool File::ChangeWorkingDirectory(const std::string& new_working_directory) {
211*1b3f573fSAndroid Build Coastguard Worker   return chdir(new_working_directory.c_str()) == 0;
212*1b3f573fSAndroid Build Coastguard Worker }
213*1b3f573fSAndroid Build Coastguard Worker 
214*1b3f573fSAndroid Build Coastguard Worker }  // namespace protobuf
215*1b3f573fSAndroid Build Coastguard Worker }  // namespace google
216