• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2010 The Android Open Source Project
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *      http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include <android-base/logging.h>
18 #include <fcntl.h>
19 #include <sys/stat.h>
20 #include <sys/types.h>
21 
22 #include <cstddef>
23 #include <cstring>
24 #include <memory>
25 
26 #include "base/zip_archive.h"
27 #include "os.h"
28 #include "unix_file/fd_file.h"
29 
30 namespace art {
31 
Invalid()32 FileWithRange FileWithRange::Invalid() { return {.file = nullptr, .start = 0, .length = 0}; }
33 
OpenFileForReading(const char * name)34 File* OS::OpenFileForReading(const char* name) {
35   return OpenFileWithFlags(name, O_RDONLY);
36 }
37 
OpenFileReadWrite(const char * name)38 File* OS::OpenFileReadWrite(const char* name) {
39   return OpenFileWithFlags(name, O_RDWR);
40 }
41 
CreateEmptyFile(const char * name,int extra_flags)42 static File* CreateEmptyFile(const char* name, int extra_flags) {
43   // In case the file exists, unlink it so we get a new file. This is necessary as the previous
44   // file may be in use and must not be changed.
45   unlink(name);
46 
47   return OS::OpenFileWithFlags(name, O_CREAT | extra_flags);
48 }
49 
CreateEmptyFile(const char * name)50 File* OS::CreateEmptyFile(const char* name) {
51   return art::CreateEmptyFile(name, O_RDWR | O_TRUNC);
52 }
53 
CreateEmptyFileWriteOnly(const char * name)54 File* OS::CreateEmptyFileWriteOnly(const char* name) {
55 #ifdef _WIN32
56   int flags = O_WRONLY | O_TRUNC;
57 #else
58   int flags = O_WRONLY | O_TRUNC | O_NOFOLLOW | O_CLOEXEC;
59 #endif
60   return art::CreateEmptyFile(name, flags);
61 }
62 
OpenFileWithFlags(const char * name,int flags,bool auto_flush)63 File* OS::OpenFileWithFlags(const char* name, int flags, bool auto_flush) {
64   CHECK(name != nullptr);
65   bool read_only = ((flags & O_ACCMODE) == O_RDONLY);
66   bool check_usage = !read_only && auto_flush;
67   std::unique_ptr<File> file(
68       new File(name, flags,  S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH, check_usage));
69   if (!file->IsOpened()) {
70     return nullptr;
71   }
72   return file.release();
73 }
74 
FileExists(const char * name,bool check_file_type)75 bool OS::FileExists(const char* name, bool check_file_type) {
76   struct stat st;
77   if (stat(name, &st) == 0) {
78     if (check_file_type) {
79       return S_ISREG(st.st_mode);  // TODO: Deal with symlinks?
80     } else {
81       return true;
82     }
83   } else {
84     return false;
85   }
86 }
87 
DirectoryExists(const char * name)88 bool OS::DirectoryExists(const char* name) {
89   struct stat st;
90   if (stat(name, &st) == 0) {
91     return S_ISDIR(st.st_mode);  // TODO: Deal with symlinks?
92   } else {
93     return false;
94   }
95 }
96 
GetFileSizeBytes(const char * name)97 int64_t OS::GetFileSizeBytes(const char* name) {
98   struct stat st;
99   if (stat(name, &st) == 0) {
100     return st.st_size;  // TODO: Deal with symlinks? According to the documentation,
101                         // the st_size for a symlink is "the length of the pathname
102                         // it contains, without a terminating null byte."
103   } else {
104     return -1;
105   }
106 }
107 
OpenFileDirectlyOrFromZip(const std::string & name_and_zip_entry,const char * zip_separator,size_t alignment,std::string * error_msg)108 FileWithRange OS::OpenFileDirectlyOrFromZip(const std::string& name_and_zip_entry,
109                                             const char* zip_separator,
110                                             size_t alignment,
111                                             std::string* error_msg) {
112   std::string filename = name_and_zip_entry;
113   std::string zip_entry_name;
114   size_t pos = filename.find(zip_separator);
115   if (pos != std::string::npos) {
116     zip_entry_name = filename.substr(pos + strlen(zip_separator));
117     filename.resize(pos);
118     if (filename.empty() || zip_entry_name.empty()) {
119       *error_msg = ART_FORMAT("Malformed zip path '{}'", name_and_zip_entry);
120       return FileWithRange::Invalid();
121     }
122   }
123 
124   std::unique_ptr<File> file(OS::OpenFileForReading(filename.c_str()));
125   if (file == nullptr) {
126     *error_msg = ART_FORMAT("Failed to open '{}' for reading: {}", filename, strerror(errno));
127     return FileWithRange::Invalid();
128   }
129 
130   off_t start = 0;
131   int64_t total_file_length = file->GetLength();
132   if (total_file_length < 0) {
133     *error_msg = ART_FORMAT("Failed to get file length of '{}': {}", filename, strerror(errno));
134     return FileWithRange::Invalid();
135   }
136   size_t length = total_file_length;
137 
138   if (!zip_entry_name.empty()) {
139     std::unique_ptr<ZipArchive> zip_archive(
140         ZipArchive::OpenFromOwnedFd(file->Fd(), filename.c_str(), error_msg));
141     if (zip_archive == nullptr) {
142       *error_msg = ART_FORMAT("Failed to open '{}' as zip", filename);
143       return FileWithRange::Invalid();
144     }
145     std::unique_ptr<ZipEntry> zip_entry(zip_archive->Find(zip_entry_name.c_str(), error_msg));
146     if (zip_entry == nullptr) {
147       *error_msg = ART_FORMAT("Failed to find entry '{}' in zip '{}'", zip_entry_name, filename);
148       return FileWithRange::Invalid();
149     }
150     if (!zip_entry->IsUncompressed() || !zip_entry->IsAlignedTo(alignment)) {
151       *error_msg =
152           ART_FORMAT("The entry '{}' in zip '{}' must be uncompressed and aligned to {} bytes",
153                      zip_entry_name,
154                      filename,
155                      alignment);
156       return FileWithRange::Invalid();
157     }
158     start = zip_entry->GetOffset();
159     length = zip_entry->GetUncompressedLength();
160     if (start + length > static_cast<size_t>(total_file_length)) {
161       *error_msg = ART_FORMAT(
162           "Invalid zip entry offset or length (offset: {}, length: {}, total_file_length: {})",
163           start,
164           length,
165           total_file_length);
166       return FileWithRange::Invalid();
167     }
168   }
169 
170   return {.file = std::move(file), .start = start, .length = length};
171 }
172 
173 }  // namespace art
174