nsresult
nsXREDirProvider::GetSysUserExtensionsDirectory(nsIFile** aFile)
{
  nsCOMPtr<nsIFile> localDir;
  nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), false);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = AppendSysUserExtensionPath(localDir);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = EnsureDirectoryExists(localDir);
  NS_ENSURE_SUCCESS(rv, rv);

  localDir.forget(aFile);
  return NS_OK;
}
nsresult
nsXREDirProvider::GetUserDataDirectory(nsILocalFile** aFile, bool aLocal)
{
  nsCOMPtr<nsILocalFile> localDir;
  nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), aLocal);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = AppendProfilePath(localDir);
  NS_ENSURE_SUCCESS(rv, rv);

#ifdef DEBUG_jungshik
  nsCAutoString cwd;
  localDir->GetNativePath(cwd);
  printf("nsXREDirProvider::GetUserDataDirectory: %s\n", cwd.get());
#endif
  rv = EnsureDirectoryExists(localDir);
  NS_ENSURE_SUCCESS(rv, rv);

  NS_ADDREF(*aFile = localDir);
  return NS_OK;
}
nsresult
nsXREDirProvider::GetUserDataDirectory(nsIFile** aFile, bool aLocal,
                                       const nsACString* aProfileName,
                                       const nsACString* aAppName,
                                       const nsACString* aVendorName)
{
  nsCOMPtr<nsIFile> localDir;
  nsresult rv = GetUserDataDirectoryHome(getter_AddRefs(localDir), aLocal);
  NS_ENSURE_SUCCESS(rv, rv);

  rv = AppendProfilePath(localDir, aProfileName, aAppName, aVendorName, aLocal);
  NS_ENSURE_SUCCESS(rv, rv);

#ifdef DEBUG_jungshik
  nsAutoCString cwd;
  localDir->GetNativePath(cwd);
  printf("nsXREDirProvider::GetUserDataDirectory: %s\n", cwd.get());
#endif
  rv = EnsureDirectoryExists(localDir);
  NS_ENSURE_SUCCESS(rv, rv);

  localDir.forget(aFile);
  return NS_OK;
}
nsresult
nsXREDirProvider::GetUpdateRootDir(nsIFile* *aResult)
{
  nsCOMPtr<nsIFile> updRoot;
#if defined(MOZ_WIDGET_GONK)

  nsresult rv = NS_NewNativeLocalFile(nsDependentCString("/data/local"),
                                      true,
                                      getter_AddRefs(updRoot));
  NS_ENSURE_SUCCESS(rv, rv);

#else
  nsCOMPtr<nsIFile> appFile;
  bool per = false;
  nsresult rv = GetFile(XRE_EXECUTABLE_FILE, &per, getter_AddRefs(appFile));
  NS_ENSURE_SUCCESS(rv, rv);
  rv = appFile->GetParent(getter_AddRefs(updRoot));
  NS_ENSURE_SUCCESS(rv, rv);

#ifdef XP_MACOSX
  nsCOMPtr<nsIFile> appRootDirFile;
  nsCOMPtr<nsIFile> localDir;
  nsAutoString appDirPath;
  if (NS_FAILED(appFile->GetParent(getter_AddRefs(appRootDirFile))) ||
      NS_FAILED(appRootDirFile->GetPath(appDirPath)) ||
      NS_FAILED(GetUserDataDirectoryHome(getter_AddRefs(localDir), true))) {
    return NS_ERROR_FAILURE;
  }

  int32_t dotIndex = appDirPath.RFind(".app");
  if (dotIndex == kNotFound) {
    dotIndex = appDirPath.Length();
  }
  appDirPath = Substring(appDirPath, 1, dotIndex - 1);

  bool hasVendor = gAppData->vendor && strlen(gAppData->vendor) != 0;
  if (hasVendor || gAppData->name) {
    if (NS_FAILED(localDir->AppendNative(nsDependentCString(hasVendor ?
                                           gAppData->vendor :
                                           gAppData->name)))) {
      return NS_ERROR_FAILURE;
    }
  } else if (NS_FAILED(localDir->AppendNative(NS_LITERAL_CSTRING("Mozilla")))) {
    return NS_ERROR_FAILURE;
  }

  if (NS_FAILED(localDir->Append(NS_LITERAL_STRING("updates"))) ||
      NS_FAILED(localDir->AppendRelativePath(appDirPath))) {
    return NS_ERROR_FAILURE;
  }

  localDir.forget(aResult);
  return NS_OK;

#elif XP_WIN
  nsAutoString pathHash;
  bool pathHashResult = false;
  bool hasVendor = gAppData->vendor && strlen(gAppData->vendor) != 0;

  nsAutoString appDirPath;
  if (SUCCEEDED(updRoot->GetPath(appDirPath))) {

    // Figure out where we should check for a cached hash value. If the
    // application doesn't have the nsXREAppData vendor value defined check
    // under SOFTWARE\Mozilla.
    wchar_t regPath[1024] = { L'\0' };
    swprintf_s(regPath, mozilla::ArrayLength(regPath), L"SOFTWARE\\%S\\%S\\TaskBarIDs",
               (hasVendor ? gAppData->vendor : "Mozilla"), MOZ_APP_BASENAME);

    // If we pre-computed the hash, grab it from the registry.
    pathHashResult = GetCachedHash(HKEY_LOCAL_MACHINE,
                                   nsDependentString(regPath), appDirPath,
                                   pathHash);
    if (!pathHashResult) {
      pathHashResult = GetCachedHash(HKEY_CURRENT_USER,
                                     nsDependentString(regPath), appDirPath,
                                     pathHash);
    }
  }

  // Get the local app data directory and if a vendor name exists append it.
  // If only a product name exists, append it.  If neither exist fallback to
  // old handling.  We don't use the product name on purpose because we want a
  // shared update directory for different apps run from the same path.
  nsCOMPtr<nsIFile> localDir;
  if (pathHashResult && (hasVendor || gAppData->name) &&
      NS_SUCCEEDED(GetUserDataDirectoryHome(getter_AddRefs(localDir), true)) &&
      NS_SUCCEEDED(localDir->AppendNative(nsDependentCString(hasVendor ?
                                          gAppData->vendor : gAppData->name))) &&
      NS_SUCCEEDED(localDir->Append(NS_LITERAL_STRING("updates"))) &&
      NS_SUCCEEDED(localDir->Append(pathHash))) {
    localDir.forget(aResult);
    return NS_OK;
  }

  nsAutoString appPath;
  rv = updRoot->GetPath(appPath);
  NS_ENSURE_SUCCESS(rv, rv);

  // AppDir may be a short path. Convert to long path to make sure
  // the consistency of the update folder location
  nsString longPath;
  wchar_t* buf;

  uint32_t bufLength = longPath.GetMutableData(&buf, MAXPATHLEN);
  NS_ENSURE_TRUE(bufLength >= MAXPATHLEN, NS_ERROR_OUT_OF_MEMORY);

  DWORD len = GetLongPathNameW(appPath.get(), buf, bufLength);

  // Failing GetLongPathName() is not fatal.
  if (len <= 0 || len >= bufLength)
    longPath.Assign(appPath);
  else
    longPath.SetLength(len);

  // Use <UserLocalDataDir>\updates\<relative path to app dir from
  // Program Files> if app dir is under Program Files to avoid the
  // folder virtualization mess on Windows Vista
  nsAutoString programFiles;
  rv = GetShellFolderPath(CSIDL_PROGRAM_FILES, programFiles);
  NS_ENSURE_SUCCESS(rv, rv);

  programFiles.Append('\\');
  uint32_t programFilesLen = programFiles.Length();

  nsAutoString programName;
  if (_wcsnicmp(programFiles.get(), longPath.get(), programFilesLen) == 0) {
    programName = Substring(longPath, programFilesLen);
  } else {
    // We need the update root directory to live outside of the installation
    // directory, because otherwise the updater writing the log file can cause
    // the directory to be locked, which prevents it from being replaced after
    // background updates.
    programName.AssignASCII(MOZ_APP_NAME);
  }

  rv = GetUserLocalDataDirectory(getter_AddRefs(updRoot));
  NS_ENSURE_SUCCESS(rv, rv);

  rv = updRoot->AppendRelativePath(programName);
  NS_ENSURE_SUCCESS(rv, rv);

#endif // XP_WIN
#endif
  updRoot.forget(aResult);
  return NS_OK;
}