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_