| // Copyright 2014 The Crashpad Authors. All rights reserved. |
| // |
| // Licensed under the Apache License, Version 2.0 (the "License"); |
| // you may not use this file except in compliance with the License. |
| // You may obtain a copy of the License at |
| // |
| // http://www.apache.org/licenses/LICENSE-2.0 |
| // |
| // Unless required by applicable law or agreed to in writing, software |
| // distributed under the License is distributed on an "AS IS" BASIS, |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| // See the License for the specific language governing permissions and |
| // limitations under the License. |
| |
| #include "util/mac/xattr.h" |
| |
| #include <errno.h> |
| #include <stdint.h> |
| #include <sys/types.h> |
| #include <sys/xattr.h> |
| |
| #include "base/logging.h" |
| #include "base/numerics/safe_conversions.h" |
| #include "base/strings/string_number_conversions.h" |
| #include "base/strings/stringprintf.h" |
| |
| namespace crashpad { |
| |
| XattrStatus ReadXattr(const base::FilePath& file, |
| const base::StringPiece& name, |
| std::string* value) { |
| // First get the size of the attribute value. |
| ssize_t buffer_size = getxattr(file.value().c_str(), name.data(), nullptr, |
| 0, 0, 0); |
| if (buffer_size < 0) { |
| if (errno == ENOATTR) |
| return XattrStatus::kNoAttribute; |
| PLOG(ERROR) << "getxattr size " << name << " on file " << file.value(); |
| return XattrStatus::kOtherError; |
| } |
| |
| // Resize the buffer and read into it. |
| value->resize(buffer_size); |
| if (!value->empty()) { |
| ssize_t bytes_read = getxattr(file.value().c_str(), name.data(), |
| &(*value)[0], value->size(), |
| 0, 0); |
| if (bytes_read < 0) { |
| PLOG(ERROR) << "getxattr " << name << " on file " << file.value(); |
| return XattrStatus::kOtherError; |
| } |
| DCHECK_EQ(bytes_read, buffer_size); |
| } |
| |
| return XattrStatus::kOK; |
| } |
| |
| bool WriteXattr(const base::FilePath& file, |
| const base::StringPiece& name, |
| const std::string& value) { |
| int rv = setxattr(file.value().c_str(), name.data(), value.c_str(), |
| value.length(), 0, 0); |
| PLOG_IF(ERROR, rv != 0) << "setxattr " << name << " on file " |
| << file.value(); |
| return rv == 0; |
| } |
| |
| XattrStatus ReadXattrBool(const base::FilePath& file, |
| const base::StringPiece& name, |
| bool* value) { |
| std::string tmp; |
| XattrStatus status; |
| if ((status = ReadXattr(file, name, &tmp)) != XattrStatus::kOK) |
| return status; |
| if (tmp == "1") { |
| *value = true; |
| return XattrStatus::kOK; |
| } else if (tmp == "0") { |
| *value = false; |
| return XattrStatus::kOK; |
| } else { |
| LOG(ERROR) << "ReadXattrBool " << name << " on file " << file.value() |
| << " could not be interpreted as boolean"; |
| return XattrStatus::kOtherError; |
| } |
| } |
| |
| bool WriteXattrBool(const base::FilePath& file, |
| const base::StringPiece& name, |
| bool value) { |
| return WriteXattr(file, name, (value ? "1" : "0")); |
| } |
| |
| XattrStatus ReadXattrInt(const base::FilePath& file, |
| const base::StringPiece& name, |
| int* value) { |
| std::string tmp; |
| XattrStatus status; |
| if ((status = ReadXattr(file, name, &tmp)) != XattrStatus::kOK) |
| return status; |
| if (!base::StringToInt(tmp, value)) { |
| LOG(ERROR) << "ReadXattrInt " << name << " on file " << file.value() |
| << " could not be converted to an int"; |
| return XattrStatus::kOtherError; |
| } |
| return XattrStatus::kOK; |
| } |
| |
| bool WriteXattrInt(const base::FilePath& file, |
| const base::StringPiece& name, |
| int value) { |
| std::string tmp = base::StringPrintf("%d", value); |
| return WriteXattr(file, name, tmp); |
| } |
| |
| XattrStatus ReadXattrTimeT(const base::FilePath& file, |
| const base::StringPiece& name, |
| time_t* value) { |
| // time_t on macOS is defined as a long, but it will be read into an int64_t |
| // here, since there is no string conversion method for long. |
| std::string tmp; |
| XattrStatus status; |
| if ((status = ReadXattr(file, name, &tmp)) != XattrStatus::kOK) |
| return status; |
| |
| int64_t encoded_value; |
| if (!base::StringToInt64(tmp, &encoded_value)) { |
| LOG(ERROR) << "ReadXattrTimeT " << name << " on file " << file.value() |
| << " could not be converted to an int"; |
| return XattrStatus::kOtherError; |
| } |
| |
| *value = base::saturated_cast<time_t>(encoded_value); |
| if (!base::IsValueInRangeForNumericType<time_t>(encoded_value)) { |
| LOG(ERROR) << "ReadXattrTimeT " << name << " on file " << file.value() |
| << " read over-sized value and will saturate"; |
| return XattrStatus::kOtherError; |
| } |
| |
| return XattrStatus::kOK; |
| } |
| |
| bool WriteXattrTimeT(const base::FilePath& file, |
| const base::StringPiece& name, |
| time_t value) { |
| std::string tmp = base::StringPrintf("%ld", value); |
| return WriteXattr(file, name, tmp); |
| } |
| |
| XattrStatus RemoveXattr(const base::FilePath& file, |
| const base::StringPiece& name) { |
| int rv = removexattr(file.value().c_str(), name.data(), 0); |
| if (rv != 0) { |
| if (errno == ENOATTR) |
| return XattrStatus::kNoAttribute; |
| PLOG(ERROR) << "removexattr " << name << " on file " << file.value(); |
| return XattrStatus::kOtherError; |
| } |
| return XattrStatus::kOK; |
| } |
| |
| } // namespace crashpad |