Add keystone 7 Day Active (7DA) support.
Touch a file with the same name as our bundle identifier in the
updater actives directory.
Change-Id: Ie24a6fbcd3ad733bf9cae1e465746c5bb869bed6
diff --git a/VP8Decoder.c b/VP8Decoder.c
index 13a4bc3..ffd99a8 100644
--- a/VP8Decoder.c
+++ b/VP8Decoder.c
@@ -20,6 +20,7 @@
#include "vpx/vpx_codec_impl_top.h"
#include "vpx/vpx_codec_impl_bottom.h"
#include "vpx/vp8dx.h"
+#include "keystone_util.h"
#include "log.h"
#include "VP8CodecVersion.h"
@@ -89,8 +90,10 @@
// Component Open Request - Required
pascal ComponentResult VP8_Decoder_Open(VP8DecoderGlobals glob, ComponentInstance self)
{
- dbg_printf("[vp8d - %08lx] VP8_Decoder_Open\n", (UInt32) glob);
ComponentResult err;
+ dbg_printf("[vp8d - %08lx] VP8_Decoder_Open\n", (UInt32) glob);
+
+ TouchActivityFile();
// Allocate memory for our globals, set them up and inform the component manager that we've done so
glob = calloc(sizeof(VP8DecoderGlobalsRecord), 1);
diff --git a/VP8Encoder.c b/VP8Encoder.c
index fbb6ddf..7516867 100644
--- a/VP8Encoder.c
+++ b/VP8Encoder.c
@@ -21,16 +21,15 @@
#include <ImageCodec.h>
#endif
+#include "keystone_util.h"
#include "log.h"
#include "Raw_debug.h"
-
#include "VP8CodecVersion.h"
#include "VP8Encoder.h"
#include "VP8EncoderEncode.h"
#include "VP8EncoderGui.h"
-
// Setup required for ComponentDispatchHelper.c
#define IMAGECODEC_BASENAME() VP8_Encoder_
#define IMAGECODEC_GLOBALS() VP8EncoderGlobals storage
@@ -71,6 +70,8 @@
ComponentResult err = noErr;
dbg_printf("[vp8e - %08lx] Open Called\n", (UInt32)glob);
+ TouchActivityFile();
+
glob = calloc(sizeof(VP8EncoderGlobalsRecord), 1);
if (! glob)
diff --git a/WebM.xcodeproj/project.pbxproj b/WebM.xcodeproj/project.pbxproj
index e95b20a..d3b0360 100644
--- a/WebM.xcodeproj/project.pbxproj
+++ b/WebM.xcodeproj/project.pbxproj
@@ -12,6 +12,7 @@
10C2262C122D91CC00359ACF /* WebMImport.r in Rez */ = {isa = PBXBuildFile; fileRef = 10C2262B122D91CC00359ACF /* WebMImport.r */; };
374E201D13FD898300A14F1C /* libwebm.a in Frameworks */ = {isa = PBXBuildFile; fileRef = 374E201813FD891100A14F1C /* libwebm.a */; };
374E203513FD8B4400A14F1C /* libvpx.a in Frameworks */ = {isa = PBXBuildFile; fileRef = BB98158C11FF19600031AA75 /* libvpx.a */; };
+ 6A0610C114F72EFB003AC5D2 /* keystone_util.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 6A0610C014F72EFB003AC5D2 /* keystone_util.cpp */; };
8D01CCCA0486CAD60068D4B7 /* InfoPlist.strings in Resources */ = {isa = PBXBuildFile; fileRef = 089C167DFE841241C02AAC07 /* InfoPlist.strings */; };
8D01CCCE0486CAD60068D4B7 /* Carbon.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 08EA7FFBFE8413EDC02AAC07 /* Carbon.framework */; };
BB124AE012392B0300A26F24 /* VP8EncoderGui.c in Sources */ = {isa = PBXBuildFile; fileRef = BB124ADF12392B0300A26F24 /* VP8EncoderGui.c */; };
@@ -76,6 +77,8 @@
10D73AE6124D4A2A00673FEC /* mkvreaderqt.hpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.h; path = mkvreaderqt.hpp; sourceTree = "<group>"; };
374E1CE713FD7BFB00A14F1C /* libvpx.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libvpx.xcodeproj; path = external/libvpx.xcodeproj; sourceTree = "<group>"; };
374E201313FD891100A14F1C /* libwebm.xcodeproj */ = {isa = PBXFileReference; lastKnownFileType = "wrapper.pb-project"; name = libwebm.xcodeproj; path = external/libwebm.xcodeproj; sourceTree = "<group>"; };
+ 6A0610BF14F72EFB003AC5D2 /* keystone_util.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = keystone_util.h; sourceTree = "<group>"; };
+ 6A0610C014F72EFB003AC5D2 /* keystone_util.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = keystone_util.cpp; sourceTree = "<group>"; };
6A0610C214F731A4003AC5D2 /* bundle_info.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = bundle_info.h; sourceTree = "<group>"; };
8D01CCD10486CAD60068D4B7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist; path = Info.plist; sourceTree = "<group>"; };
8D01CCD20486CAD60068D4B7 /* AWebM.component */ = {isa = PBXFileReference; explicitFileType = wrapper.cfbundle; includeInIndex = 0; path = AWebM.component; sourceTree = BUILT_PRODUCTS_DIR; };
@@ -308,6 +311,8 @@
BB9815BC11FF1C5F0031AA75 /* Raw_debug.h */,
BB9815BD11FF1C5F0031AA75 /* VP8Codec_Prefix.pch */,
BB9815BE11FF1C5F0031AA75 /* VP8CodecVersion.h */,
+ 6A0610BF14F72EFB003AC5D2 /* keystone_util.h */,
+ 6A0610C014F72EFB003AC5D2 /* keystone_util.cpp */,
6A0610C214F731A4003AC5D2 /* bundle_info.h */,
);
name = Common;
@@ -457,6 +462,7 @@
BBB2D454125E08A100F54FBA /* VP8EncoderEncode.c in Sources */,
103EF9A5128B2DC60032CEE6 /* WebMImport.cpp in Sources */,
103EF9A6128B2DCB0032CEE6 /* mkvreaderqt.cpp in Sources */,
+ 6A0610C114F72EFB003AC5D2 /* keystone_util.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;
};
diff --git a/WebMExport.c b/WebMExport.c
index 7abb59d..f9644ba 100644
--- a/WebMExport.c
+++ b/WebMExport.c
@@ -13,6 +13,7 @@
#include <QuickTimeComponents.h>
#endif
+#include "keystone_util.h"
#include "log.h"
#include "WebMExportStructs.h"
#include "WebMExportVersions.h"
@@ -81,6 +82,8 @@
dbg_printf("[WebM -- %08lx] Open()\n", (UInt32) store);
+ TouchActivityFile();
+
store = (WebMExportGlobalsPtr) NewPtrClear(sizeof(WebMExportGlobals));
err = MemError();
diff --git a/WebMImport.cpp b/WebMImport.cpp
index 3b046b2..4b16b01 100644
--- a/WebMImport.cpp
+++ b/WebMImport.cpp
@@ -41,6 +41,7 @@
#include "mkvparser.hpp"
#include "mkvreaderqt.hpp"
+#include "keystone_util.h"
#include "log.h"
@@ -206,6 +207,8 @@
OSErr err;
dbg_printf("[WebM Import] >> [%08lx] :: Open()\n", (UInt32) store);
+ TouchActivityFile();
+
store = (WebMImportGlobals) NewPtrClear(sizeof(WebMImportGlobalsRec));
if ((err = MemError()) == noErr) {
store->self = self;
diff --git a/keystone_util.cpp b/keystone_util.cpp
new file mode 100644
index 0000000..5b700ca
--- /dev/null
+++ b/keystone_util.cpp
@@ -0,0 +1,157 @@
+// 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);
+}
diff --git a/keystone_util.h b/keystone_util.h
new file mode 100644
index 0000000..78d0c90
--- /dev/null
+++ b/keystone_util.h
@@ -0,0 +1,25 @@
+// 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.
+
+#if !defined WEBMQUICKTIME_KEYSTONE_UTIL_H_
+#define WEBMQUICKTIME_KEYSTONE_UTIL_H_
+
+#if defined __cplusplus
+extern "C" {
+#endif
+
+// Touches the file |kWebmBundleId| in
+// $HOME/Library/Google/GoogleSoftwareUpdate/Actives. Creates the directories
+// in the path when necessary.
+void TouchActivityFile();
+
+#if defined __cplusplus
+} // extern "C"
+#endif
+
+#endif // WEBMQUICKTIME_KEYSTONE_UTIL_H_