mirror of
https://github.com/RPCS3/llvm-mirror.git
synced 2024-11-26 12:43:36 +01:00
f73c5e8b40
As of binutils 2.36, GNU strip calls chown(2) for "sudo strip foo" and "sudo strip foo -o foo", but no "sudo strip foo -o bar" or "sudo strip foo -o ./foo". In other words, while "sudo strip foo -o bar" creates a new file bar with root access, "sudo strip foo" will keep the owner and group of foo unchanged. Currently llvm-objcopy and llvm-strip behave differently, always changing the owner and gropu to root. The discrepancy prevents Chrome OS from migrating to llvm-objcopy and llvm-strip as they change file ownership and cause intended users/groups to lose access when invoked by sudo with the following sequence (recommended in man page of GNU strip). 1.<Link the executable as normal.> 1.<Copy "foo" to "foo.full"> 1.<Run "strip --strip-debug foo"> 1.<Run "objcopy --add-gnu-debuglink=foo.full foo"> This patch makes llvm-objcopy and llvm-strip follow GNU's behavior. Link: crbug.com/1108880
85 lines
2.8 KiB
C++
85 lines
2.8 KiB
C++
//===- Buffer.cpp ---------------------------------------------------------===//
|
|
//
|
|
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
|
|
// See https://llvm.org/LICENSE.txt for license information.
|
|
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
|
|
//
|
|
//===----------------------------------------------------------------------===//
|
|
|
|
#include "Buffer.h"
|
|
#include "llvm/Support/FileOutputBuffer.h"
|
|
#include "llvm/Support/FileSystem.h"
|
|
#include "llvm/Support/MemoryBuffer.h"
|
|
#include "llvm/Support/Process.h"
|
|
#include <memory>
|
|
|
|
namespace llvm {
|
|
namespace objcopy {
|
|
|
|
Buffer::~Buffer() {}
|
|
|
|
static Error createEmptyFile(StringRef FileName) {
|
|
// Create an empty tempfile and atomically swap it in place with the desired
|
|
// output file.
|
|
Expected<sys::fs::TempFile> Temp =
|
|
sys::fs::TempFile::create(FileName + ".temp-empty-%%%%%%%");
|
|
return Temp ? Temp->keep(FileName) : Temp.takeError();
|
|
}
|
|
|
|
Error FileBuffer::allocate(size_t Size) {
|
|
// When a 0-sized file is requested, skip allocation but defer file
|
|
// creation/truncation until commit() to avoid side effects if something
|
|
// happens between allocate() and commit().
|
|
if (Size == 0) {
|
|
EmptyFile = true;
|
|
return Error::success();
|
|
}
|
|
|
|
Expected<std::unique_ptr<FileOutputBuffer>> BufferOrErr =
|
|
FileOutputBuffer::create(getName(), Size,
|
|
KeepOwnership
|
|
? FileOutputBuffer::F_executable |
|
|
FileOutputBuffer::F_keep_ownership
|
|
: FileOutputBuffer::F_executable,
|
|
UserID, GroupID);
|
|
// FileOutputBuffer::create() returns an Error that is just a wrapper around
|
|
// std::error_code. Wrap it in FileError to include the actual filename.
|
|
if (!BufferOrErr)
|
|
return createFileError(getName(), BufferOrErr.takeError());
|
|
Buf = std::move(*BufferOrErr);
|
|
return Error::success();
|
|
}
|
|
|
|
Error FileBuffer::commit() {
|
|
if (EmptyFile)
|
|
return createEmptyFile(getName());
|
|
|
|
assert(Buf && "allocate() not called before commit()!");
|
|
Error Err = Buf->commit();
|
|
// FileOutputBuffer::commit() returns an Error that is just a wrapper around
|
|
// std::error_code. Wrap it in FileError to include the actual filename.
|
|
return Err ? createFileError(getName(), std::move(Err)) : std::move(Err);
|
|
}
|
|
|
|
uint8_t *FileBuffer::getBufferStart() {
|
|
return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
|
|
}
|
|
|
|
Error MemBuffer::allocate(size_t Size) {
|
|
Buf = WritableMemoryBuffer::getNewMemBuffer(Size, getName());
|
|
return Error::success();
|
|
}
|
|
|
|
Error MemBuffer::commit() { return Error::success(); }
|
|
|
|
uint8_t *MemBuffer::getBufferStart() {
|
|
return reinterpret_cast<uint8_t *>(Buf->getBufferStart());
|
|
}
|
|
|
|
std::unique_ptr<WritableMemoryBuffer> MemBuffer::releaseMemoryBuffer() {
|
|
return std::move(Buf);
|
|
}
|
|
|
|
} // end namespace objcopy
|
|
} // end namespace llvm
|