1 // Protocol Buffers - Google's data interchange format
2 // Copyright 2008 Google Inc.
3 // http://code.google.com/p/protobuf/
5 // Licensed under the Apache License, Version 2.0 (the "License");
6 // you may not use this file except in compliance with the License.
7 // You may obtain a copy of the License at
9 // http://www.apache.org/licenses/LICENSE-2.0
11 // Unless required by applicable law or agreed to in writing, software
12 // distributed under the License is distributed on an "AS IS" BASIS,
13 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 // See the License for the specific language governing permissions and
15 // limitations under the License.
17 // Author: kenton@google.com (Kenton Varda)
18 // emulates google3/file/base/file.cc
20 #include <google/protobuf/testing/file.h>
23 #include <sys/types.h>
25 #define WIN32_LEAN_AND_MEAN // yeah, right
26 #include <windows.h> // Find*File(). :(
39 #define mkdir(name, mode) mkdir(name)
40 // Windows doesn't have symbolic links.
43 #define F_OK 00 // not defined by MSVC for whatever reason
47 bool File::Exists(const string
& name
) {
48 return access(name
.c_str(), F_OK
) == 0;
51 bool File::ReadFileToString(const string
& name
, string
* output
) {
53 FILE* file
= fopen(name
.c_str(), "rb");
54 if (file
== NULL
) return false;
57 size_t n
= fread(buffer
, 1, sizeof(buffer
), file
);
59 output
->append(buffer
, n
);
62 int error
= ferror(file
);
63 if (fclose(file
) != 0) return false;
67 void File::ReadFileToStringOrDie(const string
& name
, string
* output
) {
68 GOOGLE_CHECK(ReadFileToString(name
, output
)) << "Could not read: " << name
;
71 void File::WriteStringToFileOrDie(const string
& contents
, const string
& name
) {
72 FILE* file
= fopen(name
.c_str(), "wb");
73 GOOGLE_CHECK(file
!= NULL
);
74 GOOGLE_CHECK_EQ(fwrite(contents
.data(), 1, contents
.size(), file
),
76 GOOGLE_CHECK(fclose(file
) == 0);
79 bool File::CreateDir(const string
& name
, int mode
) {
80 return mkdir(name
.c_str(), mode
) == 0;
83 bool File::RecursivelyCreateDir(const string
& path
, int mode
) {
84 if (CreateDir(path
, mode
)) return true;
86 // Try creating the parent.
87 string::size_type slashpos
= path
.find_first_of('/');
88 if (slashpos
== string::npos
) {
93 return RecursivelyCreateDir(path
.substr(0, slashpos
), mode
) &&
94 CreateDir(path
, mode
);
97 void File::DeleteRecursively(const string
& name
,
98 void* dummy1
, void* dummy2
) {
99 // We don't care too much about error checking here since this is only used
100 // in tests to delete temporary directories that are under /tmp anyway.
103 // This interface is so weird.
104 WIN32_FIND_DATA find_data
;
105 HANDLE find_handle
= FindFirstFile((name
+ "/*").c_str(), &find_data
);
106 if (find_handle
== INVALID_HANDLE_VALUE
) {
107 // Just delete it, whatever it is.
108 DeleteFile(name
.c_str());
109 RemoveDirectory(name
.c_str());
114 string entry_name
= find_data
.cFileName
;
115 if (entry_name
!= "." && entry_name
!= "..") {
116 string path
= name
+ "/" + entry_name
;
117 if (find_data
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
) {
118 DeleteRecursively(path
, NULL
, NULL
);
119 RemoveDirectory(path
.c_str());
121 DeleteFile(path
.c_str());
124 } while(FindNextFile(find_handle
, &find_data
));
125 FindClose(find_handle
);
127 RemoveDirectory(name
.c_str());
129 // Use opendir()! Yay!
130 // lstat = Don't follow symbolic links.
132 if (lstat(name
.c_str(), &stats
) != 0) return;
134 if (S_ISDIR(stats
.st_mode
)) {
135 DIR* dir
= opendir(name
.c_str());
138 struct dirent
* entry
= readdir(dir
);
139 if (entry
== NULL
) break;
140 string entry_name
= entry
->d_name
;
141 if (entry_name
!= "." && entry_name
!= "..") {
142 DeleteRecursively(name
+ "/" + entry_name
, NULL
, NULL
);
150 } else if (S_ISREG(stats
.st_mode
)) {
151 remove(name
.c_str());
156 } // namespace protobuf
157 } // namespace google