blob: 6d24ce69678923de967e652e287e6ae9c98827de [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you 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 <fts.h>
#include <sys/stat.h>
#include <string>
#include <string.h>
#include <mesos/docker/spec.hpp>
#include <stout/error.hpp>
#include <stout/nothing.hpp>
#include <stout/os.hpp>
#include <stout/path.hpp>
#include <stout/strings.hpp>
#include <stout/try.hpp>
#include <stout/os/rm.hpp>
#include <stout/os/strerror.hpp>
#include <stout/os/xattr.hpp>
#include "slave/containerizer/mesos/provisioner/utils.hpp"
using std::string;
namespace mesos {
namespace internal {
namespace slave {
#ifdef __linux__
// This function is used to convert AUFS whiteouts to OverlayFS whiteouts and
// the AUFS whiteouts will be removed after the conversion is done. Whiteout is
// for hiding directories and files in the lower level layers. AUFS whiteout is
// the whiteout standard in Docker, and it relies on '.wh..wh..opq' to hide
// directory and '.wh.<filename>' to hide file, whereas OverlayFS relies on
// setting an extended attribute 'trusted.overlay.opaque' on the directory to
// hide it and creating character device with 0/0 device number to hide file.
// See the links below for more details:
// http://aufs.sourceforge.net/aufs.html
// https://www.kernel.org/doc/Documentation/filesystems/overlayfs.txt
Try<Nothing> convertWhiteouts(const string& directory)
{
char* rootfs[] = {const_cast<char*>(directory.c_str()), nullptr};
FTS* tree = ::fts_open(rootfs, FTS_NOCHDIR | FTS_PHYSICAL, nullptr);
if (tree == nullptr) {
return Error("Failed to open '" + directory + "': " + os::strerror(errno));
}
for (FTSENT *node = ::fts_read(tree);
node != nullptr; node = ::fts_read(tree)) {
if (node->fts_info != FTS_F) {
continue;
}
if (!strings::startsWith(node->fts_name, docker::spec::WHITEOUT_PREFIX)) {
continue;
}
const Path path = Path(node->fts_path);
if (node->fts_name == string(docker::spec::WHITEOUT_OPAQUE_PREFIX)) {
Try<Nothing> setxattr = os::setxattr(
path.dirname(),
"trusted.overlay.opaque",
"y",
0);
if (setxattr.isError()) {
::fts_close(tree);
return Error(
"Failed to set extended attribute 'trusted.overlay.opaque'"
" for the directory '" + path.dirname() + "': " +
setxattr.error());
}
} else {
const string originalPath = path::join(
path.dirname(),
path.basename().substr(strlen(docker::spec::WHITEOUT_PREFIX)));
Try<Nothing> mknod = os::mknod(originalPath, S_IFCHR, 0);
if (mknod.isError()) {
::fts_close(tree);
return Error(
"Failed to create character device '" +
originalPath + "': " + mknod.error());
}
}
// Remove the AUFS whiteout file.
Try<Nothing> rm = os::rm(path.string());
if (rm.isError()) {
::fts_close(tree);
return Error(
"Failed to remove AUFS whiteout file '" +
path.string() + "': " + rm.error());
}
}
if (errno != 0) {
Error error = ErrnoError();
::fts_close(tree);
return error;
}
if (::fts_close(tree) != 0) {
return Error(
"Failed to stop traversing file system: " + os::strerror(errno));
}
return Nothing();
}
#endif
} // namespace slave {
} // namespace internal {
} // namespace mesos {