blob: 5b700ca7ec5127102b8d63cdafec41dda6b554ef [file] [log] [blame]
// Copyright (c) 2012 The WebM project authors. All Rights Reserved.
//
// Use of this source code is governed by a BSD-style license
// that can be found in the LICENSE file in the root of the source
// tree. An additional intellectual property rights grant can be found
// in the file PATENTS. All contributing project authors may
// be found in the AUTHORS file in the root of the source tree.
#include "keystone_util.h"
#include <fcntl.h>
#include <pwd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h>
#include <utime.h>
#include <cstdio>
#include <cstdlib>
#include <memory>
#include <string>
#include "bundle_info.h"
// Returns path to user home directory. Checks both environment and password
// database; password database value takes precendence when it differs from
// value returned by |getenv|. Path returned always ends with '/'.
std::string ReadHomeDirectoryPath() {
// Read HOME value from environment.
const char* ptr_env_home_dir = getenv("HOME");
std::string home_dir = ptr_env_home_dir;
// Check with password database for home directory. No guarantee that HOME
// environment variable is set or valid.
// Obtain max size for |passwd| struct from |sysconf|.
struct passwd passwd_entry = {0};
const size_t passwd_buf_size = sysconf(_SC_GETPW_R_SIZE_MAX);
if (passwd_buf_size > 0) {
char* const passwd_buf = new (std::nothrow) char[passwd_buf_size];
if (passwd_buf) {
struct passwd* ptr_passwd_entry = NULL;
const int result = getpwuid_r(getuid(),
&passwd_entry,
passwd_buf,
passwd_buf_size,
&ptr_passwd_entry);
if (!result && ptr_passwd_entry == &passwd_entry) {
const std::string passwd_home_dir = passwd_entry.pw_dir;
if (home_dir != passwd_home_dir) {
home_dir = passwd_home_dir;
}
}
delete[] passwd_buf;
}
}
if (!home_dir.empty() && home_dir[home_dir.size()] != '/') {
home_dir.append("/");
}
return home_dir;
}
// Returns true when |path| exists.
bool PathExists(const std::string& path) {
struct stat path_stat = {0};
const int status = stat(path.c_str(), &path_stat);
return status == 0;
}
// Returns true when |path| exists and is a directory.
bool PathIsDirectory(const std::string& path) {
if (PathExists(path)) {
struct stat path_stat = {0};
const int status = stat(path.c_str(), &path_stat);
if (status == 0 && S_ISDIR(path_stat.st_mode)) {
return true;
}
}
return false;
}
// Appends activity directory to string returned by |ReadHomeDirectoryPath()|
// and returns result.
std::string GenerateActivityDirectoryPath() {
const std::string home_dir = ReadHomeDirectoryPath();
if (home_dir.empty() || !PathIsDirectory(home_dir)) {
// Return an empty string: can't really do anything without a valid
// |home_dir|.
return std::string();
}
const std::string kActivityDirectory =
"Library/Google/GoogleSoftwareUpdate/Actives/";
return home_dir + kActivityDirectory;
}
// Creates directory specified by |path|. Creates parent directories if
// necessary. Returns 0 when successful.
int CreateDirectory(const std::string& path) {
if (path.empty()) {
return -1;
}
// Search |path| for /'s, and create all directories encountered.
// Start at |pos| 1: assume filesystem root exists.
typedef std::string::size_type size_type;
for (size_type pos = 1; pos < path.length(); ++pos) {
pos = path.find('/', pos);
if (pos != std::string::npos) {
// Copy from start through occurence of '/';
const std::string directory = path.substr(0, pos);
if (!PathExists(directory)) {
// Make the directory with permissions allowing r/w for everyone.
const mode_t mode_flags =
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
if (mkdir(directory.c_str(), mode_flags)) {
// Could not create directory.
return -1;
}
}
} else {
break;
}
}
return 0;
}
void TouchActivityFile() {
// Generate the activity directory path for the current user, and create it
// if it does not exist.
const std::string activity_dir = GenerateActivityDirectoryPath();
if (!PathIsDirectory(activity_dir)) {
if (CreateDirectory(activity_dir)) {
// Unable to create directory, abandon touch attempt.
return;
}
}
const std::string activity_file = activity_dir + kWebmBundleId;
if (PathExists(activity_file)) {
// There's nothing to do when the file exists. Keystone deletes it each
// time it runs the activity check.
return;
}
// Create |activity_file|.
const int open_flags = O_WRONLY | O_CREAT | O_NONBLOCK | O_NOCTTY;
const mode_t mode_flags =
S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH;
const int file_desc = open(activity_file.c_str(), open_flags, mode_flags);
if (file_desc == -1) {
// |open failed|, give up.
return;
}
close(file_desc);
}