<commit_before>/**
 * This file is part of the CernVM File System.
 *
 * Runs mount/umount commands and removes scratch space on behalf of a
 * repository owner.  Server-only utility.
 *
 * This binary does not use the cvmfs infrastructure code to stay lean.
 */

#include <sys/stat.h>
#include <sys/xattr.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>

#include <cstdlib>
#include <cstdio>
#include <cstring>

#include <string>

#include "platform.h"

using namespace std;  // NOLINT

const char *kSpoolArea = "/var/spool/cvmfs";

enum RemountType {
  kRemountRdonly,
  kRemountRw
};

static void GetCredentials(uid_t *calling_uid, uid_t *effective_uid) {
  *calling_uid = getuid();
  *effective_uid = geteuid();
}

static void ExecAsRoot(const char *binary,
                       const char *arg1, const char *arg2, const char *arg3)
{
  char *argv[] = { strdup(binary),
                   arg1 ? strdup(arg1) : NULL,
                   arg2 ? strdup(arg2) : NULL,
                   arg3 ? strdup(arg3) : NULL,
                   NULL };
  char *environ[] = { NULL };

  int retval = setuid(0);
  if (retval != 0) {
    fprintf(stderr, "failed to gain root privileges (%d)\n", errno);
    exit(1);
  }

  execve(binary, argv, environ);
  fprintf(stderr, "failed to run %s... (%d)\n", binary, errno);
  exit(1);
}

static void Remount(const string &path, const RemountType how) {
  string remount_option = "remount,";
  switch (how) {
    case kRemountRw:
      remount_option += "rw";
      break;
    case kRemountRdonly:
      remount_option += "ro";
      break;
    default:
      fprintf(stderr, "internal error\n");
      exit(1);
  }

  ExecAsRoot("/bin/mount", "-o", remount_option.c_str(), path.c_str());
}

static void Mount(const string &path) {
  ExecAsRoot("/bin/mount", path.c_str(), NULL, NULL);
}

static void Umount(const string &path) {
  ExecAsRoot("/bin/umount", path.c_str(), NULL, NULL);
}

static void KillCvmfs(const string &fqrn) {
  // prevent exploitation like:
  // fqrn = ../../../../usr/home/file_with_xattr_user.pid
  if (fqrn.find("/") != string::npos || fqrn.find("\\") != string::npos) {
    fprintf(stderr, "go away!\n");
    exit(1);
  }
  string pid;
  const string mountpoint = string(kSpoolArea) + "/" + fqrn + "/rdonly";
  const bool retval = platform_getxattr(mountpoint.c_str(), "user.pid", &pid);
  if (!retval) {
    exit(1);
  }
  ExecAsRoot("/bin/kill", "-9", pid.c_str(), NULL);
}

static bool ClearWorkingDir() {
  int retval;
  DIR *dirp = opendir(".");
  if (dirp == NULL)
    return false;
  platform_dirent64 *dirent;
  while ((dirent = platform_readdir(dirp)) != NULL) {
    if ((strcmp(dirent->d_name, ".") == 0) || (strcmp(dirent->d_name, "..") == 0))
      continue;

    platform_stat64 info;
    retval = platform_lstat(dirent->d_name, &info);
    if (retval != 0) {
      closedir(dirp);
      return false;
    }

    if (S_ISDIR(info.st_mode)) {
      // Recursion
      retval = chdir(dirent->d_name);
      if (retval != 0) {
        closedir(dirp);
        return false;
      }
      retval = ClearWorkingDir();
      if (!retval) {
        closedir(dirp);
        return false;
      }
      retval = chdir("..");
      if (retval != 0) {
        closedir(dirp);
        return false;
      }
      retval = rmdir(dirent->d_name);
      if (retval != 0) {
        closedir(dirp);
        return false;
      }
    } else {
      retval = unlink(dirent->d_name);
      if (retval != 0) {
        closedir(dirp);
        return false;
      }
    }
  }
  closedir(dirp);
  return true;
}

static void Usage(const string &exe, FILE *output) {
  fprintf(output,
    "Usage: %s lock|open|rw_mount|rw_umount|rdonly_mount|rdonly_umount|clear_scratch "
    "fqrn\n"
    "Example: %s rw_umount atlas.cern.ch\n"
    "This binary is typically called by cvmfs_server.\n",
    exe.c_str(), exe.c_str());
}

int main(int argc, char *argv[]) {
  umask(077);
  int retval;

  // Figure out real and effective uid
  uid_t calling_uid, effective_uid, repository_uid;
  GetCredentials(&calling_uid, &effective_uid);
  if (effective_uid != 0) {
    fprintf(stderr, "Needs to run as root\n");
    return 1;
  }

  // Arguments
  if (argc != 3) {
    Usage(argv[0], stderr);
    return 1;
  }
  const string command = argv[1];
  const string fqrn = argv[2];

  // Verify if repository exists
  platform_stat64 info;
  retval = platform_lstat((string(kSpoolArea) + "/" + fqrn).c_str(), &info);
  if (retval != 0) {
    fprintf(stderr, "unknown repository: %s\n", fqrn.c_str());
    return 1;
  }
  repository_uid = info.st_uid;

  // Verify if caller uid matches
  if ((calling_uid != 0) && (calling_uid != repository_uid)) {
    fprintf(stderr, "called as %d, repository owned by %d\n",
            calling_uid, repository_uid);
    return 1;
  }

  if (command == "lock") {
    Remount("/cvmfs/" + fqrn, kRemountRdonly);
  } else if (command == "open") {
    Remount("/cvmfs/" + fqrn, kRemountRw);
  } else if (command == "kill_cvmfs") {
    KillCvmfs(fqrn);
  } else if (command == "rw_mount") {
    Mount("/cvmfs/" + fqrn);
  } else if (command == "rw_umount") {
    Umount("/cvmfs/" + fqrn);
  } else if (command == "rdonly_mount") {
    Mount(string(kSpoolArea) + "/" + fqrn + "/rdonly");
  } else if (command == "rdonly_umount") {
    Umount(string(kSpoolArea) + "/" + fqrn + "/rdonly");
  } else if (command == "clear_scratch") {
    const string scratch_area = string(kSpoolArea) + "/" + fqrn + "/scratch";
    retval = chdir(scratch_area.c_str());
    if (retval != 0) {
      fprintf(stderr, "failed to chdir to %s\n", scratch_area.c_str());
      return 1;
    }
    retval = ClearWorkingDir();
    if (!retval) {
      fprintf(stderr, "failed to clear %s\n", scratch_area.c_str());
      return 1;
    }
  } else {
    Usage(argv[0], stderr);
    return 1;
  }

  return 0;
}
<commit_msg>add *_lazy_umount to cvmfs_suid_helper<commit_after>/**
 * This file is part of the CernVM File System.
 *
 * Runs mount/umount commands and removes scratch space on behalf of a
 * repository owner.  Server-only utility.
 *
 * This binary does not use the cvmfs infrastructure code to stay lean.
 */

#include <sys/stat.h>
#include <sys/xattr.h>
#include <dirent.h>
#include <unistd.h>
#include <errno.h>

#include <cstdlib>
#include <cstdio>
#include <cstring>

#include <string>

#include "platform.h"

using namespace std;  // NOLINT

const char *kSpoolArea = "/var/spool/cvmfs";

enum RemountType {
  kRemountRdonly,
  kRemountRw
};

static void GetCredentials(uid_t *calling_uid, uid_t *effective_uid) {
  *calling_uid = getuid();
  *effective_uid = geteuid();
}

static void ExecAsRoot(const char *binary,
                       const char *arg1, const char *arg2, const char *arg3)
{
  char *argv[] = { strdup(binary),
                   arg1 ? strdup(arg1) : NULL,
                   arg2 ? strdup(arg2) : NULL,
                   arg3 ? strdup(arg3) : NULL,
                   NULL };
  char *environ[] = { NULL };

  int retval = setuid(0);
  if (retval != 0) {
    fprintf(stderr, "failed to gain root privileges (%d)\n", errno);
    exit(1);
  }

  execve(binary, argv, environ);
  fprintf(stderr, "failed to run %s... (%d)\n", binary, errno);
  exit(1);
}

static void Remount(const string &path, const RemountType how) {
  string remount_option = "remount,";
  switch (how) {
    case kRemountRw:
      remount_option += "rw";
      break;
    case kRemountRdonly:
      remount_option += "ro";
      break;
    default:
      fprintf(stderr, "internal error\n");
      exit(1);
  }

  ExecAsRoot("/bin/mount", "-o", remount_option.c_str(), path.c_str());
}

static void Mount(const string &path) {
  ExecAsRoot("/bin/mount", path.c_str(), NULL, NULL);
}

static void Umount(const string &path) {
  ExecAsRoot("/bin/umount", path.c_str(), NULL, NULL);
}

static void LazyUmount(const string &path) {
  ExecAsRoot("/bin/umount", "-l", path.c_str(), NULL);
}

static void KillCvmfs(const string &fqrn) {
  // prevent exploitation like:
  // fqrn = ../../../../usr/home/file_with_xattr_user.pid
  if (fqrn.find("/") != string::npos || fqrn.find("\\") != string::npos) {
    fprintf(stderr, "go away!\n");
    exit(1);
  }
  string pid;
  const string mountpoint = string(kSpoolArea) + "/" + fqrn + "/rdonly";
  const bool retval = platform_getxattr(mountpoint.c_str(), "user.pid", &pid);
  if (!retval) {
    exit(1);
  }
  ExecAsRoot("/bin/kill", "-9", pid.c_str(), NULL);
}

static bool ClearWorkingDir() {
  int retval;
  DIR *dirp = opendir(".");
  if (dirp == NULL)
    return false;
  platform_dirent64 *dirent;
  while ((dirent = platform_readdir(dirp)) != NULL) {
    if ((strcmp(dirent->d_name, ".") == 0) || (strcmp(dirent->d_name, "..") == 0))
      continue;

    platform_stat64 info;
    retval = platform_lstat(dirent->d_name, &info);
    if (retval != 0) {
      closedir(dirp);
      return false;
    }

    if (S_ISDIR(info.st_mode)) {
      // Recursion
      retval = chdir(dirent->d_name);
      if (retval != 0) {
        closedir(dirp);
        return false;
      }
      retval = ClearWorkingDir();
      if (!retval) {
        closedir(dirp);
        return false;
      }
      retval = chdir("..");
      if (retval != 0) {
        closedir(dirp);
        return false;
      }
      retval = rmdir(dirent->d_name);
      if (retval != 0) {
        closedir(dirp);
        return false;
      }
    } else {
      retval = unlink(dirent->d_name);
      if (retval != 0) {
        closedir(dirp);
        return false;
      }
    }
  }
  closedir(dirp);
  return true;
}

static void Usage(const string &exe, FILE *output) {
  fprintf(output,
    "Usage: %s lock|open|rw_mount|rw_umount|rdonly_mount|rdonly_umount|clear_scratch "
    "fqrn\n"
    "Example: %s rw_umount atlas.cern.ch\n"
    "This binary is typically called by cvmfs_server.\n",
    exe.c_str(), exe.c_str());
}

int main(int argc, char *argv[]) {
  umask(077);
  int retval;

  // Figure out real and effective uid
  uid_t calling_uid, effective_uid, repository_uid;
  GetCredentials(&calling_uid, &effective_uid);
  if (effective_uid != 0) {
    fprintf(stderr, "Needs to run as root\n");
    return 1;
  }

  // Arguments
  if (argc != 3) {
    Usage(argv[0], stderr);
    return 1;
  }
  const string command = argv[1];
  const string fqrn = argv[2];

  // Verify if repository exists
  platform_stat64 info;
  retval = platform_lstat((string(kSpoolArea) + "/" + fqrn).c_str(), &info);
  if (retval != 0) {
    fprintf(stderr, "unknown repository: %s\n", fqrn.c_str());
    return 1;
  }
  repository_uid = info.st_uid;

  // Verify if caller uid matches
  if ((calling_uid != 0) && (calling_uid != repository_uid)) {
    fprintf(stderr, "called as %d, repository owned by %d\n",
            calling_uid, repository_uid);
    return 1;
  }

  if (command == "lock") {
    Remount("/cvmfs/" + fqrn, kRemountRdonly);
  } else if (command == "open") {
    Remount("/cvmfs/" + fqrn, kRemountRw);
  } else if (command == "kill_cvmfs") {
    KillCvmfs(fqrn);
  } else if (command == "rw_mount") {
    Mount("/cvmfs/" + fqrn);
  } else if (command == "rw_umount") {
    Umount("/cvmfs/" + fqrn);
  } else if (command == "rw_lazy_umount") {
    LazyUmount("/cvmfs/" + fqrn);
  } else if (command == "rdonly_mount") {
    Mount(string(kSpoolArea) + "/" + fqrn + "/rdonly");
  } else if (command == "rdonly_umount") {
    Umount(string(kSpoolArea) + "/" + fqrn + "/rdonly");
  } else if (command == "rdonly_lazy_umount") {
    LazyUmount(string(kSpoolArea) + "/" + fqrn + "/rdonly");
  } else if (command == "clear_scratch") {
    const string scratch_area = string(kSpoolArea) + "/" + fqrn + "/scratch";
    retval = chdir(scratch_area.c_str());
    if (retval != 0) {
      fprintf(stderr, "failed to chdir to %s\n", scratch_area.c_str());
      return 1;
    }
    retval = ClearWorkingDir();
    if (!retval) {
      fprintf(stderr, "failed to clear %s\n", scratch_area.c_str());
      return 1;
    }
  } else {
    Usage(argv[0], stderr);
    return 1;
  }

  return 0;
}
<|endoftext|>


<commit_before>/*
Library EDK - How to use Extensible Development Kit
Copyright (C) 2013 Eduardo Moura Sales Martins
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
email: edimartin@gmail.com.br

AV: Walmor M. de Souza 392 Casa
Gravatai RS Brazil 94065100
*/

//Include the Window
#include "edk/Window.h"
//Include the View to render Graphics
#include "edk/ViewGU2D.h"
//Include the FontMap render
#include "edk/fonts/FontMap.h"

class RenderView: public edk::ViewGU2D{
public:
    RenderView(){}
    ~RenderView(){}
    void load(){
        this->camera.position.x = 7;
        this->camera.position.y = -0.5f;
        this->camera.setSize(16.f,10.f);
        //create the message
        text.createStringMap("Hello EDK World");
    }
    void unload(){
        //remove the message
        text.deleteMap();
    }
    //render the scene in the vew
    void drawScene(){
        //draw the message
        text.draw();
    }
private:
    edk::fonts::FontMap text;
};

int main(){
    edk::Window win;
    //create the window with the buttons
    win.createWindow(800,600,"EDK HELLO WORLD",EDK_WINDOW_BUTTONS);
    //set the background color fo the window
    win.cleanColor = edk::color3ui8(0,0,0);

    //Create a view to draw the scene
    RenderView view;
    view.backgroundColor = edk::color4f32(1,1,1,1); //set the viewColor
    view.frame.origin = edk::vec2f32(50,50);        //set the view position inside the Window View
    view.frame.size = edk::size2f32(700,500);       //set the size of the View

    //add the view in the Window
    win.addSubview(&view);

    //Loop
    while(win.isOpened()){
        //Clean the Windows
        win.clean();
        //load the Window Events
        win.loadEvents();
        //update the Views with the events pre-loaded
        win.updateViews();

        //check if click to close de Window
        if(win.eventButtonClose()){
            //close the window
            win.closeWindow();
        }
        //test if release the ESC key
        if(win.eventGetKeyReleaseSize()){
            for(edk::uint32 i=0u;i<win.eventGetKeyReleaseSize();i++){
                if(win.eventGetKeyRelease(i) == edk::key::escape){
                    //close Window
                    win.closeWindow();
                }
            }
        }
        //draw the View's
        win.drawView();
        //render the scene
        win.render();
    }
    //remove the view from window
    win.removeSubview(&view);
    return 0;
}

<commit_msg>Forgot to change the helloEDK main<commit_after>/*
Library EDK - How to use Extensible Development Kit
Copyright (C) 2013 Eduardo Moura Sales Martins
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Lesser General Public
License as published by the Free Software Foundation; either
version 2.1 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Lesser General Public License for more details.
You should have received a copy of the GNU Lesser General Public
License along with this library; if not, write to the Free Software
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
email: edimartin@gmail.com.br

AV: Walmor M. de Souza 392 Casa
Gravatai RS Brazil 94065100
*/

//Include the Window
#include "edk/Window.h"
//Include the View to render Graphics
#include "edk/ViewGU2D.h"
//Include the FontMap render
#include "edk/fonts/FontMap.h"

class RenderView: public edk::ViewGU2D{
public:
    RenderView(){}
    ~RenderView(){}
    void load(edk::rectf32){
        this->camera.position.x = 7;
        this->camera.position.y = -0.5f;
        this->camera.setSize(16.f,10.f);
        //create the message
        text.createStringMap("Hello EDK World");
    }
    void unload(){
        //remove the message
        text.deleteMap();
    }
    //render the scene in the vew
    void drawScene(edk::rectf32){
        //draw the message
        text.draw();
    }
private:
    edk::fonts::FontMap text;
};

int main(){
    edk::Window win;
    //create the window with the buttons
    win.createWindow(800,600,"EDK HELLO WORLD",EDK_WINDOW_BUTTONS);
    //set the background color fo the window
    win.cleanColor = edk::color3ui8(0,0,0);

    //Create a view to draw the scene
    RenderView view;
    view.backgroundColor = edk::color4f32(1,1,1,1); //set the viewColor
    view.frame.origin = edk::vec2f32(50,50);        //set the view position inside the Window View
    view.frame.size = edk::size2f32(700,500);       //set the size of the View

    //add the view in the Window
    win.addSubview(&view);

    //Loop
    while(win.isOpened()){
        //Clean the Windows
        win.clean();
        //load the Window Events
        win.loadEvents();
        //update the Views with the events pre-loaded
        win.updateViews();

        //check if click to close de Window
        if(win.eventButtonClose()){
            //close the window
            win.closeWindow();
        }
        //test if release the ESC key
        if(win.eventGetKeyReleaseSize()){
            for(edk::uint32 i=0u;i<win.eventGetKeyReleaseSize();i++){
                if(win.eventGetKeyRelease(i) == edk::key::escape){
                    //close Window
                    win.closeWindow();
                }
            }
        }
        //draw the View's
        win.drawView();
        //render the scene
        win.render();
    }
    //remove the view from window
    win.removeSubview(&view);
    return 0;
}

<|endoftext|>


<commit_before>/**
 * This file is part of the CernVM File System.
 */

#include "cvmfs_config.h"
#include "cmd_abort.h"

#include <cstdio>
#include <string>

#include "logging.h"
#include "publish/cmd_util.h"
#include "publish/except.h"
#include "publish/repository.h"
#include "publish/settings.h"
#include "util/pointer.h"
#include "util/posix.h"
#include "util/string.h"
#include "whitelist.h"

namespace publish {

int CmdAbort::Main(const Options &options) {
  SettingsBuilder builder;
  UniquePtr<SettingsPublisher> settings;
  try {
    settings = builder.CreateSettingsPublisher(
      options.plain_args().empty() ? "" : options.plain_args()[0].value_str,
      true /* needs_managed */);
  } catch (const EPublish &e) {
    if ((e.failure() == EPublish::kFailRepositoryNotFound) ||
        (e.failure() == EPublish::kFailRepositoryType))
    {
      LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "CernVM-FS error: %s",
               e.msg().c_str());
      return 1;
    }
    throw;
  }

  if (settings->transaction().in_enter_session()) {
    throw EPublish(
      "aborting a transaction is unsupported within the ephemeral "
      "writable shell",
      EPublish::kFailInvocation);
  }

  if (!SwitchCredentials(settings->owner_uid(), settings->owner_gid(),
                         false /* temporarily */))
  {
    throw EPublish("No write permission to repository",
                   EPublish::kFailPermission);
  }

  if (HasPrefix(GetCurrentWorkingDirectory() + "/",
                settings->transaction().spool_area().union_mnt() + "/",
                false /* ignore_case */))
  {
    LogCvmfs(kLogCvmfs, kLogStdout,
             "Current working directory is in %s.  Please release, "
             "e.g. by 'cd $HOME'.",
             settings->transaction().spool_area().union_mnt().c_str());
    return 1;
  }

  if (!options.Has("force")) {
    LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak,
             "You are about to DISCARD ALL CHANGES OF THE CURRENT TRANSACTION "
             "for %s!  Are you sure (y/N)? ", settings->fqrn().c_str());
    char answer[2];
    fgets(answer, 2, stdin);
    if ((answer[0] != 'Y') && (answer[0] != 'y'))
      return EINTR;
  }

  std::vector<LsofEntry> lsof_entries =
    Lsof(settings->transaction().spool_area().union_mnt());
  if (!lsof_entries.empty()) {
    if (options.Has("force")) {
      LogCvmfs(kLogCvmfs, kLogStdout,
               "WARNING: Open file descriptors on %s (possible race!)"
               "\nThe following lsof report might show the culprit:\n",
               settings->transaction().spool_area().union_mnt().c_str());
    } else {
      LogCvmfs(kLogCvmfs, kLogStdout,
               "\nWARNING! There are open read-only file descriptors in %s\n"
               "  --> This is potentially harmful and might cause problems "
               "later on.\n"
               "      We can anyway perform the requested operation, but this "
               "will most likely\n"
               "      break other processes with open file descriptors on %s!\n"
               "\n"
               "      The following lsof report might show the processes with "
               "open file handles\n",
               settings->transaction().spool_area().union_mnt().c_str(),
               settings->transaction().spool_area().union_mnt().c_str());
    }

    for (unsigned i = 0; i < lsof_entries.size(); ++i) {
      std::string owner_name;
      GetUserNameOf(lsof_entries[i].owner, &owner_name);
      LogCvmfs(kLogCvmfs, kLogStdout, "%s %d %s %s",
               lsof_entries[i].executable.c_str(),
               lsof_entries[i].pid,
               owner_name.c_str(),
               lsof_entries[i].path.c_str());
    }

    if (!options.Has("force")) {
      LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak,
               "\n         Do you want to proceed anyway? (y/N) ");
      char answer[2];
      fgets(answer, 2, stdin);
      if ((answer[0] != 'Y') && (answer[0] != 'y'))
        return EINTR;
    }
  }

  UniquePtr<Publisher> publisher;
  publisher = new Publisher(*settings);

  LogCvmfs(kLogCvmfs, kLogSyslog, "(%s) aborting transaction",
           settings->fqrn().c_str());

  int rvi = CallServerHook("abort_before_hook", settings->fqrn());
  if (rvi != 0) {
    LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
             "abort hook failed, not aborting");
    return rvi;
  }

  try {
    publisher->Abort();
  } catch (const EPublish &e) {
    if (e.failure() == EPublish::kFailTransactionState) {
      LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s", e.msg().c_str());
      return EINVAL;
    }
  }

  rvi = CallServerHook("abort_after_hook", settings->fqrn());
  if (rvi != 0) {
    LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
             "post abort hook failed");
    return rvi;
  }

  return 0;
}

} // namespace publish
<commit_msg>[publish] Fix lsof report in abort<commit_after>/**
 * This file is part of the CernVM File System.
 */

#include "cvmfs_config.h"
#include "cmd_abort.h"

#include <cstdio>
#include <string>

#include "logging.h"
#include "publish/cmd_util.h"
#include "publish/except.h"
#include "publish/repository.h"
#include "publish/settings.h"
#include "util/pointer.h"
#include "util/posix.h"
#include "util/string.h"
#include "whitelist.h"

namespace publish {

int CmdAbort::Main(const Options &options) {
  SettingsBuilder builder;
  UniquePtr<SettingsPublisher> settings;
  try {
    settings = builder.CreateSettingsPublisher(
      options.plain_args().empty() ? "" : options.plain_args()[0].value_str,
      true /* needs_managed */);
  } catch (const EPublish &e) {
    if ((e.failure() == EPublish::kFailRepositoryNotFound) ||
        (e.failure() == EPublish::kFailRepositoryType))
    {
      LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "CernVM-FS error: %s",
               e.msg().c_str());
      return 1;
    }
    throw;
  }

  if (settings->transaction().in_enter_session()) {
    throw EPublish(
      "aborting a transaction is unsupported within the ephemeral "
      "writable shell",
      EPublish::kFailInvocation);
  }

  if (!SwitchCredentials(settings->owner_uid(), settings->owner_gid(),
                         false /* temporarily */))
  {
    throw EPublish("No write permission to repository",
                   EPublish::kFailPermission);
  }

  if (HasPrefix(GetCurrentWorkingDirectory() + "/",
                settings->transaction().spool_area().union_mnt() + "/",
                false /* ignore_case */))
  {
    LogCvmfs(kLogCvmfs, kLogStdout,
             "Current working directory is in %s.  Please release, "
             "e.g. by 'cd $HOME'.",
             settings->transaction().spool_area().union_mnt().c_str());
    return 1;
  }

  if (!options.Has("force")) {
    LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak,
             "You are about to DISCARD ALL CHANGES OF THE CURRENT TRANSACTION "
             "for %s!  Are you sure (y/N)? ", settings->fqrn().c_str());
    char answer[3];
    fgets(answer, 3, stdin);
    if ((answer[0] != 'Y') && (answer[0] != 'y'))
      return EINTR;
  }

  std::vector<LsofEntry> lsof_entries =
    Lsof(settings->transaction().spool_area().union_mnt());
  if (!lsof_entries.empty()) {
    if (options.Has("force")) {
      LogCvmfs(kLogCvmfs, kLogStdout,
               "WARNING: Open file descriptors on %s (possible race!)"
               "\nThe following lsof report might show the culprit:\n",
               settings->transaction().spool_area().union_mnt().c_str());
    } else {
      LogCvmfs(kLogCvmfs, kLogStdout,
               "\nWARNING! There are open read-only file descriptors in %s\n"
               "  --> This is potentially harmful and might cause problems "
               "later on.\n"
               "      We can anyway perform the requested operation, but this "
               "will most likely\n"
               "      break other processes with open file descriptors on %s!\n"
               "\n"
               "      The following lsof report might show the processes with "
               "open file handles\n",
               settings->transaction().spool_area().union_mnt().c_str(),
               settings->transaction().spool_area().union_mnt().c_str());
    }

    for (unsigned i = 0; i < lsof_entries.size(); ++i) {
      std::string owner_name;
      GetUserNameOf(lsof_entries[i].owner, &owner_name);
      LogCvmfs(kLogCvmfs, kLogStdout, "%s %d %s %s",
               lsof_entries[i].executable.c_str(),
               lsof_entries[i].pid,
               owner_name.c_str(),
               lsof_entries[i].path.c_str());
    }

    if (!options.Has("force")) {
      LogCvmfs(kLogCvmfs, kLogStdout | kLogNoLinebreak,
               "\n      Do you want to proceed anyway? (y/N) ");
      char answer[3];
      fgets(answer, 3, stdin);
      if ((answer[0] != 'Y') && (answer[0] != 'y'))
        return EINTR;
    }
  }

  UniquePtr<Publisher> publisher;
  publisher = new Publisher(*settings);

  LogCvmfs(kLogCvmfs, kLogSyslog, "(%s) aborting transaction",
           settings->fqrn().c_str());

  int rvi = CallServerHook("abort_before_hook", settings->fqrn());
  if (rvi != 0) {
    LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
             "abort hook failed, not aborting");
    return rvi;
  }

  try {
    publisher->Abort();
  } catch (const EPublish &e) {
    if (e.failure() == EPublish::kFailTransactionState) {
      LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr, "%s", e.msg().c_str());
      return EINVAL;
    }
  }

  rvi = CallServerHook("abort_after_hook", settings->fqrn());
  if (rvi != 0) {
    LogCvmfs(kLogCvmfs, kLogStderr | kLogSyslogErr,
             "post abort hook failed");
    return rvi;
  }

  return 0;
}

} // namespace publish
<|endoftext|>


<commit_before>// dllmain.cpp : Defines the entry point for the DLL application.
// Programmed by jasonfish4
/* The excessive use of global variables is due to me not wanting to consume stack space, overuse registers, etc...
within an exception signaling function */

#define _CRT_SECURE_NO_DEPRECATE

#include "stdafx.h"
#include "Dispatcher\rvdbg.h"
#include "Dispatcher\exceptiondispatcher.h"
#include "dbgredefs.h"
#include "debugoutput.h"
#include <winsock.h>
#include <cstdlib>
#include <string>
#include <unordered_map>
#include <array>
#include <iostream>
#include <sstream>

#pragma comment(lib, "wsock32.lib")
typedef void(*str_comparator_function)();
void protocol_gui_func();
void str_breakpoint();
void str_imode();
void str_pmode();
void str_dbg_get();
void str_dbg_display_regs();
void str_xmmf_display();
void str_xmmd_display();
void str_dbg_run();

const char* g_module_name; // Name of the image
const char* g_ext_module_name; // Name of the copy image
const char* g_file_path; // File location to copy image
std::uint32_t g_server;
std::uint8_t g_protocol_interface;
std::uint32_t symbol;
sockaddr_in g_server_address;
std::array<void*, 2> g_threads;

const std::unordered_map<char, rvdbg::sse_register> xmm_register_map = {
	{ '0', rvdbg::sse_register::xmm0 },
	{ '1', rvdbg::sse_register::xmm1 },
	{ '2', rvdbg::sse_register::xmm2 },
	{ '3', rvdbg::sse_register::xmm3 },
	{ '4', rvdbg::sse_register::xmm4 },
	{ '5', rvdbg::sse_register::xmm5 },
	{ '6', rvdbg::sse_register::xmm6 },
	{ '7', rvdbg::sse_register::xmm7 }
};

const std::unordered_map<char, rvdbg::gp_reg_32> general_register_map = {
	{ '0', rvdbg::gp_reg_32::eax },
	{ '1', rvdbg::gp_reg_32::ebx },
	{ '2', rvdbg::gp_reg_32::ecx },
	{ '3', rvdbg::gp_reg_32::edx },
	{ '4', rvdbg::gp_reg_32::edi },
	{ '5', rvdbg::gp_reg_32::esi },
	{ '6', rvdbg::gp_reg_32::ebp },
	{ '7', rvdbg::gp_reg_32::esp },
	{ '8', rvdbg::gp_reg_32::eip }
};

const std::unordered_map<std::string, str_comparator_function> opt_func_table = {
	{ std::string("**ProtocolGUI"), &protocol_gui_func },
	{ std::string("!Breakpoint"), &str_breakpoint },
	{ std::string("imode"), &str_imode },
	{ std::string("pmode"), &str_pmode },
	{ std::string("!DbgGet"), &str_dbg_get },
	{ std::string("!DbgDisplayRegisters"), &str_dbg_display_regs },
	{ std::string("!xmm-f"), &str_xmmf_display },
	{ std::string("!xmm-d"), &str_xmmd_display },
	{ std::string("!DbgRun"), &str_dbg_run },
};

void register_value(char key, std::uint32_t value)
{
	rvdbg::set_register(static_cast<std::uint32_t>(general_register_map.at(key)), value);
}

void register_value_fp(char key, bool precision, double value)
{
	rvdbg::set_register_fp(static_cast<std::uint32_t>(xmm_register_map.at(key)), precision, value);
}

void protocol_gui_func()
{
	g_protocol_interface = 1;
}

void str_imode()
{
	rvdbg::set_exception_mode(dispatcher::exception_type::immediate_exception);
}

void str_pmode()
{
	rvdbg::set_exception_mode(dispatcher::exception_type::page_exception);
}

void str_dbg_get()
{
	dbg_io::send_dbg_get(g_server, rvdbg::get_exception_mode(), rvdbg::get_current_section());
}

void str_dbg_display_regs()
{
	dbg_io::send_dbg_registers(g_server, g_protocol_interface, rvdbg::get_dbg_exception_address(), rvdbg::get_registers());
}

void str_xmmf_display()
{
	dbg_io::send_dbg_registers(g_server, 2, rvdbg::get_dbg_exception_address(), rvdbg::get_registers());
}

void str_xmmd_display()
{
	dbg_io::send_dbg_registers(g_server, 3, rvdbg::get_dbg_exception_address(), rvdbg::get_registers());
}

void str_dbg_run()
{
	if (rvdbg::is_aeh_present())
	{
		rvdbg::continue_debugger();
	}
}

void str_breakpoint()
{
	std::size_t exception_element = dispatcher::check_sector(rvdbg::get_sector());
	MEMORY_BASIC_INFORMATION mbi;
	if (VirtualQuery(reinterpret_cast<void*>(symbol), &mbi, sizeof(mbi)) != dbg_redef::nullval)
	{
		if (mbi.Protect != static_cast<unsigned long>(dbg_redef::page_protection::page_na))
		{
			dispatcher::add_exception(rvdbg::get_sector(), exception_element, rvdbg::get_exception_mode(), symbol);
		}
	}
}

void str_get(std::array<char, 128>& snbuffer, std::size_t index)
{
	if (index < rvdbg::get_sector_size())
	{
		std::snprintf(snbuffer.data(), snbuffer.size(), "$    symbol: 0x%02X\r\n    index:%d\r\n", symbol, index);
		send(g_server, snbuffer.data(), snbuffer.size(), 0);
	}
	else
	{
		send(g_server, "$    symbol not registered", sizeof("$    symbol not registered"), 0);
	}
}

void dbg_undo(std::size_t index)
{
	if (index < rvdbg::get_sector_size())
	{
		std::uint32_t old_protect;
		switch (rvdbg::get_exception_mode())
		{
		case dispatcher::exception_type::immediate_exception:
			VirtualProtect(reinterpret_cast<void*>(rvdbg::get_sector()[index].dbg_exception_address),
				1, static_cast<unsigned long>(dbg_redef::page_protection::page_xrw), reinterpret_cast<unsigned long*>(&old_protect));

			*reinterpret_cast<std::uint32_t*>(rvdbg::get_sector()[index].dbg_exception_address) = (rvdbg::get_sector()[index].save_code);

			VirtualProtect(reinterpret_cast<void*>(rvdbg::get_sector()[index].dbg_exception_address), 1,
				old_protect, reinterpret_cast<unsigned long*>(&old_protect));

			dispatcher::unlock_sector(rvdbg::get_sector(), index);
			break;

		case dispatcher::exception_type::access_exception:
			/* UNIMPLEMENTED */
		case dispatcher::exception_type::page_exception:
			VirtualProtect(reinterpret_cast<void*>(rvdbg::get_sector()[index].dbg_exception_address), 1,
				rvdbg::get_sector()[index].save_code, reinterpret_cast<unsigned long*>(&old_protect));

			dispatcher::unlock_sector(rvdbg::get_sector(), index);
			break;
		}
	}
}

unsigned long __stdcall dbg_synchronization(void* lpParam)
{
	while (true)
	{
		if (rvdbg::debugger == false)
		{
			EnterCriticalSection(&rvdbg::repr);
			SleepConditionVariableCS(&rvdbg::reprcondition, &rvdbg::repr, dbg_redef::infinite);
			LeaveCriticalSection(&rvdbg::repr);
		}
		if (rvdbg::debugger == true)
		{
			send(g_server, "!DbgModeOn", strlen("!DbgModeOn"), 0);
			rvdbg::debugger = false;
		}
	}
}

unsigned long __stdcall dispatch_initializer(void* lpParam)
{
	WSAData wsa_data;
	WSAStartup(MAKEWORD(2, 2), &wsa_data);

	g_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	g_server_address = { 0 };
	g_server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
	g_server_address.sin_port = htons(8888);
	g_server_address.sin_family = AF_INET;
	connect(g_server, reinterpret_cast<sockaddr*>(&g_server_address), sizeof(g_server_address));

	rvdbg::attach_debugger();
	rvdbg::set_module(false, g_module_name, g_ext_module_name);
	rvdbg::set_pause_mode(rvdbg::suspension_mode::suspend_all);
	rvdbg::assign_thread(g_threads[0]);
	rvdbg::assign_thread(g_threads[1]);

	std::array<char, 128> buffer;
	std::array<char, 128> snbuffer;
	std::istringstream dbg_conversion_stream;

	while (true)
	{
		buffer.fill('\0');
		snbuffer.fill('\0');
		recv(g_server, buffer.data(), buffer.size(), 0);

		std::string receiver;
		receiver = std::string(buffer.data());

		try
		{
			str_comparator_function local_func = opt_func_table.at(receiver);
			local_func();
		}
		catch (std::out_of_range& e)
		{
			std::cerr << "end of map reached, string being compared is used for parsing\n";

			if (receiver.substr(0, std::string("!Symbol @").size()) == std::string("!Symbol @"))
			{
				if (!receiver.substr(sizeof("!Symbol @ "), receiver.size()).empty())
				{
					std::sscanf(receiver.substr(sizeof("!Symbol @ "), receiver.size()).c_str(), "%X", &symbol);
				}
			}

			else if (receiver.substr(0, std::string("!setreg").size()) == std::string("!setreg"))
			{
				std::uint32_t regv;
				dbg_conversion_stream.str(receiver.substr(std::string("!setreg ? ").size(), receiver.size()));
				dbg_conversion_stream >> std::hex >> regv;
				register_value(receiver.at(std::string("!setreg ").size()), regv);
			}

			else if (receiver.substr(0, std::string("!fsetreg").size()) == std::string("!fsetreg"))
			{
				double regv;
				dbg_conversion_stream.str(receiver.substr(std::string("!fsetreg ? ").size(), receiver.size()));
				dbg_conversion_stream >> regv;
				register_value_fp(receiver.at(std::string("!fsetreg ").size()), 0, regv);
			}

			else if (receiver.substr(0, std::string("!dsetreg").size()) == std::string("!dsetreg"))
			{
				double regv;
				dbg_conversion_stream.str((receiver.substr(std::string("!dsetreg ? ").size(), receiver.size())));
				dbg_conversion_stream >> regv;
				register_value_fp(receiver.at(std::string("!dsetreg ").size()), 1, regv);
			}

			else if (receiver.substr(0, std::string("!Undo ").size()) == std::string("!Undo "))
			{
				std::size_t index;
				dbg_conversion_stream.str(receiver.substr(std::string("!Undo ").size(), receiver.size()));
				dbg_conversion_stream >> index;
				dbg_undo(index);
			}

			else if (receiver == std::string("!Get"))
			{
				std::size_t index = dispatcher::search_sector(rvdbg::get_sector(), symbol);
				str_get(snbuffer, index);
			}

			else if (receiver == std::string("!Exit"))
			{
				str_dbg_run();
				break;
			}
		}
	}

	rvdbg::detach_debugger();
	rvdbg::remove_thread(g_threads[0]);
	rvdbg::remove_thread(g_threads[1]);
	closesocket(g_server);
	WSACleanup();
	TerminateThread(g_threads[0], 0);
	return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, std::uint32_t  ul_reason_for_call, void* lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:

		if (use_module) // currently off by default
		{
			dll_inject(GetCurrentProcessId(), g_file_path);
		}

		AllocConsole();
		freopen("CONOUT$", "w", stdout);
		freopen("CONOUT$", "w", stderr);
		InitializeCriticalSection(&rvdbg::repr);
		InitializeConditionVariable(&rvdbg::reprcondition);
		g_threads[0] = CreateThread(0, 0, dbg_synchronization, 0, 0, 0);
		g_threads[1] = CreateThread(0, 0, dispatch_initializer, 0, 0, 0);
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}
<commit_msg>Update dllmain.cpp<commit_after>// dllmain.cpp : Defines the entry point for the DLL application.
// Programmed by jasonfish4
/* The excessive use of global variables is due to me not wanting to consume stack space, overuse registers, etc...
within an exception signaling function */

#define _CRT_SECURE_NO_DEPRECATE

#include "stdafx.h"
#include "Dispatcher\rvdbg.h"
#include "Dispatcher\exceptiondispatcher.h"
#include "dbgredefs.h"
#include "debugoutput.h"
#include <winsock.h>
#include <cstdlib>
#include <string>
#include <unordered_map>
#include <array>
#include <iostream>
#include <sstream>

#pragma comment(lib, "wsock32.lib")
typedef void(*str_comparator_function)();
void protocol_gui_func();
void str_breakpoint();
void str_imode();
void str_pmode();
void str_dbg_get();
void str_dbg_display_regs();
void str_xmmf_display();
void str_xmmd_display();
void str_dbg_run();

const char* g_module_name; // Name of the image
const char* g_ext_module_name; // Name of the copy image
const char* g_file_path; // File location to copy image
std::uint32_t g_server;
std::uint8_t g_protocol_interface;
std::uint32_t symbol;
sockaddr_in g_server_address;
std::array<void*, 2> g_threads;

const std::unordered_map<char, rvdbg::sse_register> xmm_register_map = {
	{ '0', rvdbg::sse_register::xmm0 },
	{ '1', rvdbg::sse_register::xmm1 },
	{ '2', rvdbg::sse_register::xmm2 },
	{ '3', rvdbg::sse_register::xmm3 },
	{ '4', rvdbg::sse_register::xmm4 },
	{ '5', rvdbg::sse_register::xmm5 },
	{ '6', rvdbg::sse_register::xmm6 },
	{ '7', rvdbg::sse_register::xmm7 }
};

const std::unordered_map<char, rvdbg::gp_reg_32> general_register_map = {
	{ '0', rvdbg::gp_reg_32::eax },
	{ '1', rvdbg::gp_reg_32::ebx },
	{ '2', rvdbg::gp_reg_32::ecx },
	{ '3', rvdbg::gp_reg_32::edx },
	{ '4', rvdbg::gp_reg_32::edi },
	{ '5', rvdbg::gp_reg_32::esi },
	{ '6', rvdbg::gp_reg_32::ebp },
	{ '7', rvdbg::gp_reg_32::esp },
	{ '8', rvdbg::gp_reg_32::eip }
};

const std::unordered_map<std::string, str_comparator_function> opt_func_table = {
	{ std::string("**ProtocolGUI"), &protocol_gui_func },
	{ std::string("!Breakpoint"), &str_breakpoint },
	{ std::string("imode"), &str_imode },
	{ std::string("pmode"), &str_pmode },
	{ std::string("!DbgGet"), &str_dbg_get },
	{ std::string("!DbgDisplayRegisters"), &str_dbg_display_regs },
	{ std::string("!xmm-f"), &str_xmmf_display },
	{ std::string("!xmm-d"), &str_xmmd_display },
	{ std::string("!DbgRun"), &str_dbg_run },
};

void register_value(char key, std::uint32_t value)
{
	rvdbg::set_register(static_cast<std::uint32_t>(general_register_map.at(key)), value);
}

void register_value_fp(char key, bool precision, double value)
{
	rvdbg::set_register_fp(static_cast<std::uint32_t>(xmm_register_map.at(key)), precision, value);
}

void protocol_gui_func()
{
	g_protocol_interface = 1;
}

void str_imode()
{
	rvdbg::set_exception_mode(dispatcher::exception_type::immediate_exception);
}

void str_pmode()
{
	rvdbg::set_exception_mode(dispatcher::exception_type::page_exception);
}

void str_dbg_get()
{
	dbg_io::send_dbg_get(g_server, rvdbg::get_exception_mode(), rvdbg::get_current_section());
}

void str_dbg_display_regs()
{
	dbg_io::send_dbg_registers(g_server, g_protocol_interface, rvdbg::get_dbg_exception_address(), rvdbg::get_registers());
}

void str_xmmf_display()
{
	dbg_io::send_dbg_registers(g_server, 2, rvdbg::get_dbg_exception_address(), rvdbg::get_registers());
}

void str_xmmd_display()
{
	dbg_io::send_dbg_registers(g_server, 3, rvdbg::get_dbg_exception_address(), rvdbg::get_registers());
}

void str_dbg_run()
{
	if (rvdbg::is_aeh_present())
	{
		rvdbg::continue_debugger();
	}
}

void str_breakpoint()
{
	std::size_t exception_element = dispatcher::check_sector(rvdbg::get_sector());
	MEMORY_BASIC_INFORMATION mbi;
	if (VirtualQuery(reinterpret_cast<void*>(symbol), &mbi, sizeof(mbi)) != dbg_redef::nullval)
	{
		if (mbi.Protect != static_cast<unsigned long>(dbg_redef::page_protection::page_na))
		{
			dispatcher::add_exception(rvdbg::get_sector(), exception_element, rvdbg::get_exception_mode(), symbol);
		}
	}
}

void str_get(std::array<char, 128>& snbuffer, std::size_t index)
{
	if (index < rvdbg::get_sector_size())
	{
		std::snprintf(snbuffer.data(), snbuffer.size(), "$    symbol: 0x%02X\r\n    index:%d\r\n", symbol, index);
		send(g_server, snbuffer.data(), snbuffer.size(), 0);
	}
	else
	{
		send(g_server, "$    symbol not registered", sizeof("$    symbol not registered"), 0);
	}
}

void dbg_undo(std::size_t index)
{
	if (index < rvdbg::get_sector_size())
	{
		std::uint32_t old_protect;
		switch (rvdbg::get_exception_mode())
		{
		case dispatcher::exception_type::immediate_exception:
			VirtualProtect(reinterpret_cast<void*>(rvdbg::get_sector()[index].dbg_exception_address),
				1, static_cast<unsigned long>(dbg_redef::page_protection::page_xrw), reinterpret_cast<unsigned long*>(&old_protect));

			*reinterpret_cast<std::uint32_t*>(rvdbg::get_sector()[index].dbg_exception_address) = (rvdbg::get_sector()[index].save_code);

			VirtualProtect(reinterpret_cast<void*>(rvdbg::get_sector()[index].dbg_exception_address), 1,
				old_protect, reinterpret_cast<unsigned long*>(&old_protect));

			dispatcher::unlock_sector(rvdbg::get_sector(), index);
			break;

		case dispatcher::exception_type::access_exception:
			/* UNIMPLEMENTED */
		case dispatcher::exception_type::page_exception:
			VirtualProtect(reinterpret_cast<void*>(rvdbg::get_sector()[index].dbg_exception_address), 1,
				rvdbg::get_sector()[index].save_code, reinterpret_cast<unsigned long*>(&old_protect));

			dispatcher::unlock_sector(rvdbg::get_sector(), index);
			break;
		}
	}
}

unsigned long __stdcall dbg_synchronization(void* lpParam)
{
	while (true)
	{
		if (rvdbg::debugger == false)
		{
			EnterCriticalSection(&rvdbg::repr);
			SleepConditionVariableCS(&rvdbg::reprcondition, &rvdbg::repr, dbg_redef::infinite);
			LeaveCriticalSection(&rvdbg::repr);
		}
		else if (rvdbg::debugger == true)
		{
			send(g_server, "!DbgModeOn", strlen("!DbgModeOn"), 0);
			rvdbg::debugger = false;
		}
	}
}

unsigned long __stdcall dispatch_initializer(void* lpParam)
{
	WSAData wsa_data;
	WSAStartup(MAKEWORD(2, 2), &wsa_data);

	g_server = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
	g_server_address = { 0 };
	g_server_address.sin_addr.s_addr = inet_addr("127.0.0.1");
	g_server_address.sin_port = htons(8888);
	g_server_address.sin_family = AF_INET;
	connect(g_server, reinterpret_cast<sockaddr*>(&g_server_address), sizeof(g_server_address));

	rvdbg::attach_debugger();
	rvdbg::set_module(false, g_module_name, g_ext_module_name);
	rvdbg::set_pause_mode(rvdbg::suspension_mode::suspend_all);
	rvdbg::assign_thread(g_threads[0]);
	rvdbg::assign_thread(g_threads[1]);

	std::array<char, 128> buffer;
	std::array<char, 128> snbuffer;
	std::istringstream dbg_conversion_stream;

	while (true)
	{
		buffer.fill('\0');
		snbuffer.fill('\0');
		recv(g_server, buffer.data(), buffer.size(), 0);

		std::string receiver;
		receiver = std::string(buffer.data());

		try
		{
			str_comparator_function local_func = opt_func_table.at(receiver);
			local_func();
		}
		catch (std::out_of_range& e)
		{
			std::cerr << "end of map reached, string being compared is used for parsing\n";

			if (receiver.substr(0, std::string("!Symbol @").size()) == std::string("!Symbol @"))
			{
				if (!receiver.substr(sizeof("!Symbol @ "), receiver.size()).empty())
				{
					std::sscanf(receiver.substr(sizeof("!Symbol @ "), receiver.size()).c_str(), "%X", &symbol);
				}
			}

			else if (receiver.substr(0, std::string("!setreg").size()) == std::string("!setreg"))
			{
				std::uint32_t regv;
				dbg_conversion_stream.str(receiver.substr(std::string("!setreg ? ").size(), receiver.size()));
				dbg_conversion_stream >> std::hex >> regv;
				register_value(receiver.at(std::string("!setreg ").size()), regv);
			}

			else if (receiver.substr(0, std::string("!fsetreg").size()) == std::string("!fsetreg"))
			{
				double regv;
				dbg_conversion_stream.str(receiver.substr(std::string("!fsetreg ? ").size(), receiver.size()));
				dbg_conversion_stream >> regv;
				register_value_fp(receiver.at(std::string("!fsetreg ").size()), 0, regv);
			}

			else if (receiver.substr(0, std::string("!dsetreg").size()) == std::string("!dsetreg"))
			{
				double regv;
				dbg_conversion_stream.str((receiver.substr(std::string("!dsetreg ? ").size(), receiver.size())));
				dbg_conversion_stream >> regv;
				register_value_fp(receiver.at(std::string("!dsetreg ").size()), 1, regv);
			}

			else if (receiver.substr(0, std::string("!Undo ").size()) == std::string("!Undo "))
			{
				std::size_t index;
				dbg_conversion_stream.str(receiver.substr(std::string("!Undo ").size(), receiver.size()));
				dbg_conversion_stream >> index;
				dbg_undo(index);
			}

			else if (receiver == std::string("!Get"))
			{
				std::size_t index = dispatcher::search_sector(rvdbg::get_sector(), symbol);
				str_get(snbuffer, index);
			}

			else if (receiver == std::string("!Exit"))
			{
				str_dbg_run();
				break;
			}
		}
	}

	rvdbg::detach_debugger();
	rvdbg::remove_thread(g_threads[0]);
	rvdbg::remove_thread(g_threads[1]);
	closesocket(g_server);
	WSACleanup();
	TerminateThread(g_threads[0], 0);
	return 0;
}

BOOL APIENTRY DllMain(HMODULE hModule, std::uint32_t  ul_reason_for_call, void* lpReserved)
{
	switch (ul_reason_for_call)
	{
	case DLL_PROCESS_ATTACH:

		if (use_module) // currently off by default
		{
			dll_inject(GetCurrentProcessId(), g_file_path);
		}

		AllocConsole();
		freopen("CONOUT$", "w", stdout);
		freopen("CONOUT$", "w", stderr);
		InitializeCriticalSection(&rvdbg::repr);
		InitializeConditionVariable(&rvdbg::reprcondition);
		g_threads[0] = CreateThread(0, 0, dbg_synchronization, 0, 0, 0);
		g_threads[1] = CreateThread(0, 0, dispatch_initializer, 0, 0, 0);
	case DLL_THREAD_ATTACH:
	case DLL_THREAD_DETACH:
	case DLL_PROCESS_DETACH:
		break;
	}
	return TRUE;
}
<|endoftext|>


<commit_before>//RUN: bash make -C %p/../clang/test/ CLANG=%p/clangTestUnloader.sh
<commit_msg>Adjust to the test with the correct vars.<commit_after>//RUN: make -C %testexecdir/../../clang/ test TESTSUITE=Sema CLANG=%p/clangTestUnloader.sh
<|endoftext|>


<commit_before>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "ModuleSlice.h"

#include "DataSource.h"
#include "pqProxiesWidget.h"
#include "pqCoreUtilities.h"
#include "Utilities.h"

#include "vtkAlgorithm.h"
#include "vtkCommand.h"
#include "vtkNonOrthoImagePlaneWidget.h"
#include "vtkDataObject.h"
#include "vtkNew.h"
#include "vtkProperty.h"
#include "vtkPVArrayInformation.h"
#include "vtkPVDataInformation.h"
#include "vtkPVDataSetAttributesInformation.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkScalarsToColors.h"
#include "vtkSMParaViewPipelineControllerWithRendering.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMPVRepresentationProxy.h"
#include "vtkSMRenderViewProxy.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMSourceProxy.h"
#include "vtkSMTransferFunctionManager.h"
#include "vtkSMTransferFunctionProxy.h"
#include "vtkSMViewProxy.h"

#include <QDebug>

namespace tomviz
{

//-----------------------------------------------------------------------------
ModuleSlice::ModuleSlice(QObject* parentObject) : Superclass(parentObject)
{
}

//-----------------------------------------------------------------------------
ModuleSlice::~ModuleSlice()
{
  this->finalize();
}

//-----------------------------------------------------------------------------
QIcon ModuleSlice::icon() const
{
  return QIcon(":/pqWidgets/Icons/pqSlice24.png");
}

//-----------------------------------------------------------------------------
bool ModuleSlice::initialize(DataSource* data, vtkSMViewProxy* vtkView)
{
  if (!this->Superclass::initialize(data, vtkView))
    {
    return false;
    }

  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;
  vtkSMSourceProxy* producer = data->producer();
  vtkSMSessionProxyManager* pxm = producer->GetSessionProxyManager();

  // Create the pass through filter.
  vtkSmartPointer<vtkSMProxy> proxy;
  proxy.TakeReference(pxm->NewProxy("filters", "PassThrough"));

  // Create the Properties panel proxy
  this->PropsPanelProxy.TakeReference(
      pxm->NewProxy("tomviz_proxies", "NonOrthogonalSlice"));

  pqCoreUtilities::connect(
    this->PropsPanelProxy, vtkCommand::PropertyModifiedEvent,
    this, SLOT(onPropertyChanged()));

  this->PassThrough = vtkSMSourceProxy::SafeDownCast(proxy);
  Q_ASSERT(this->PassThrough);
  controller->PreInitializeProxy(this->PassThrough);
  vtkSMPropertyHelper(this->PassThrough, "Input").Set(producer);
  controller->PostInitializeProxy(this->PassThrough);
  controller->RegisterPipelineProxy(this->PassThrough);

  //Create the widget
  const bool widgetSetup = this->setupWidget(vtkView,producer);

  if(widgetSetup)
    {
    this->Widget->On();
    this->Widget->InteractionOn();
    }

  Q_ASSERT(this->Widget);
  return widgetSetup;
}

//-----------------------------------------------------------------------------
//should only be called from initialize after the PassThrough has been setup
bool ModuleSlice::setupWidget(vtkSMViewProxy* vtkView, vtkSMSourceProxy* producer)
{
  vtkAlgorithm* passThroughAlg = vtkAlgorithm::SafeDownCast(
                                 this->PassThrough->GetClientSideObject());

  vtkRenderWindowInteractor* rwi = vtkView->GetRenderWindow()->GetInteractor();

  //determine the name of the property we are coloring by
  const char* propertyName = producer->GetDataInformation()->
                                       GetPointDataInformation()->
                                       GetArrayInformation(0)->
                                       GetName();

  if(!rwi||!passThroughAlg||!propertyName)
    {
    return false;
    }

  this->Widget = vtkSmartPointer<vtkNonOrthoImagePlaneWidget>::New();

  //set the interactor on the widget to be what the current
  //render window is using
  this->Widget->SetInteractor( rwi );

  //setup the color of the border of the widget
  {
  double color[3] = {1, 0, 0};
  this->Widget->GetPlaneProperty()->SetColor(color);
  }

  //turn texture interpolation to be linear
  this->Widget->TextureInterpolateOn();
  this->Widget->SetResliceInterpolateToLinear();

  //Construct the transfer function proxy for the widget
  vtkSMProxy* lut = this->colorMap();

  //set the widgets lookup table to be the one that the transfer function
  //manager is using
  vtkScalarsToColors* stc =
    vtkScalarsToColors::SafeDownCast(lut->GetClientSideObject());
  this->Widget->SetLookupTable(stc);

  //lastly we set up the input connection
  this->Widget->SetInputConnection(passThroughAlg->GetOutputPort());

  Q_ASSERT(rwi);
  Q_ASSERT(passThroughAlg);
  return true;
}

//-----------------------------------------------------------------------------
void ModuleSlice::updateColorMap()
{
  Q_ASSERT(this->Widget);

  //Construct the transfer function proxy for the widget
  vtkSMProxy* lut = this->colorMap();

  //set the widgets lookup table to be the one that the transfer function
  //manager is using
  vtkScalarsToColors* stc =
    vtkScalarsToColors::SafeDownCast(lut->GetClientSideObject());
  this->Widget->SetLookupTable(stc);
}

//-----------------------------------------------------------------------------
bool ModuleSlice::finalize()
{
  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;
  controller->UnRegisterProxy(this->PassThrough);

  this->PassThrough = NULL;

  if(this->Widget != NULL)
    {
    this->Widget->InteractionOff();
    this->Widget->Off();
    }

  return true;
}

//-----------------------------------------------------------------------------
bool ModuleSlice::setVisibility(bool val)
{
  Q_ASSERT(this->Widget);
  this->Widget->SetEnabled(val ? 1 : 0);
  return true;
}

//-----------------------------------------------------------------------------
bool ModuleSlice::visibility() const
{
  Q_ASSERT(this->Widget);
  return this->Widget->GetEnabled() != 0;
}

//-----------------------------------------------------------------------------
void ModuleSlice::addToPanel(pqProxiesWidget* panel)
{
  QStringList properties;
  properties << "ShowArrow";
  panel->addProxy(this->PropsPanelProxy, "Appearance", properties, true);

  this->Superclass::addToPanel(panel);
}

//-----------------------------------------------------------------------------
bool ModuleSlice::serialize(pugi::xml_node& ns) const
{
  // FIXME: serialize slice properties.
  return this->Superclass::serialize(ns);
}

//-----------------------------------------------------------------------------
bool ModuleSlice::deserialize(const pugi::xml_node& ns)
{
  // FIXME: deserialize slice properties.
  return this->Superclass::deserialize(ns);
}

//-----------------------------------------------------------------------------
void ModuleSlice::onPropertyChanged()
{
  vtkSMPropertyHelper showProperty(this->PropsPanelProxy, "ShowArrow");
  qDebug() << "onPropertyChanged called.";
  qDebug() << showProperty.GetAsInt();
}

}
<commit_msg>Slice now hides the arrow when ShowArrow property is off -- fixes #23<commit_after>/******************************************************************************

  This source file is part of the tomviz project.

  Copyright Kitware, Inc.

  This source code is released under the New BSD License, (the "License").

  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 "ModuleSlice.h"

#include "DataSource.h"
#include "pqProxiesWidget.h"
#include "pqCoreUtilities.h"
#include "Utilities.h"

#include "vtkAlgorithm.h"
#include "vtkCommand.h"
#include "vtkNonOrthoImagePlaneWidget.h"
#include "vtkDataObject.h"
#include "vtkNew.h"
#include "vtkProperty.h"
#include "vtkPVArrayInformation.h"
#include "vtkPVDataInformation.h"
#include "vtkPVDataSetAttributesInformation.h"
#include "vtkRenderWindow.h"
#include "vtkRenderWindowInteractor.h"
#include "vtkScalarsToColors.h"
#include "vtkSMParaViewPipelineControllerWithRendering.h"
#include "vtkSMPropertyHelper.h"
#include "vtkSMPVRepresentationProxy.h"
#include "vtkSMRenderViewProxy.h"
#include "vtkSMSessionProxyManager.h"
#include "vtkSMSourceProxy.h"
#include "vtkSMTransferFunctionManager.h"
#include "vtkSMTransferFunctionProxy.h"
#include "vtkSMViewProxy.h"

#include <QDebug>

namespace tomviz
{

//-----------------------------------------------------------------------------
ModuleSlice::ModuleSlice(QObject* parentObject) : Superclass(parentObject)
{
}

//-----------------------------------------------------------------------------
ModuleSlice::~ModuleSlice()
{
  this->finalize();
}

//-----------------------------------------------------------------------------
QIcon ModuleSlice::icon() const
{
  return QIcon(":/pqWidgets/Icons/pqSlice24.png");
}

//-----------------------------------------------------------------------------
bool ModuleSlice::initialize(DataSource* data, vtkSMViewProxy* vtkView)
{
  if (!this->Superclass::initialize(data, vtkView))
    {
    return false;
    }

  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;
  vtkSMSourceProxy* producer = data->producer();
  vtkSMSessionProxyManager* pxm = producer->GetSessionProxyManager();

  // Create the pass through filter.
  vtkSmartPointer<vtkSMProxy> proxy;
  proxy.TakeReference(pxm->NewProxy("filters", "PassThrough"));

  // Create the Properties panel proxy
  this->PropsPanelProxy.TakeReference(
      pxm->NewProxy("tomviz_proxies", "NonOrthogonalSlice"));

  pqCoreUtilities::connect(
    this->PropsPanelProxy, vtkCommand::PropertyModifiedEvent,
    this, SLOT(onPropertyChanged()));

  this->PassThrough = vtkSMSourceProxy::SafeDownCast(proxy);
  Q_ASSERT(this->PassThrough);
  controller->PreInitializeProxy(this->PassThrough);
  vtkSMPropertyHelper(this->PassThrough, "Input").Set(producer);
  controller->PostInitializeProxy(this->PassThrough);
  controller->RegisterPipelineProxy(this->PassThrough);

  //Create the widget
  const bool widgetSetup = this->setupWidget(vtkView,producer);

  if(widgetSetup)
    {
    this->Widget->On();
    this->Widget->InteractionOn();
    }

  Q_ASSERT(this->Widget);
  return widgetSetup;
}

//-----------------------------------------------------------------------------
//should only be called from initialize after the PassThrough has been setup
bool ModuleSlice::setupWidget(vtkSMViewProxy* vtkView, vtkSMSourceProxy* producer)
{
  vtkAlgorithm* passThroughAlg = vtkAlgorithm::SafeDownCast(
                                 this->PassThrough->GetClientSideObject());

  vtkRenderWindowInteractor* rwi = vtkView->GetRenderWindow()->GetInteractor();

  //determine the name of the property we are coloring by
  const char* propertyName = producer->GetDataInformation()->
                                       GetPointDataInformation()->
                                       GetArrayInformation(0)->
                                       GetName();

  if(!rwi||!passThroughAlg||!propertyName)
    {
    return false;
    }

  this->Widget = vtkSmartPointer<vtkNonOrthoImagePlaneWidget>::New();

  //set the interactor on the widget to be what the current
  //render window is using
  this->Widget->SetInteractor( rwi );

  //setup the color of the border of the widget
  {
  double color[3] = {1, 0, 0};
  this->Widget->GetPlaneProperty()->SetColor(color);
  }

  //turn texture interpolation to be linear
  this->Widget->TextureInterpolateOn();
  this->Widget->SetResliceInterpolateToLinear();

  //Construct the transfer function proxy for the widget
  vtkSMProxy* lut = this->colorMap();

  //set the widgets lookup table to be the one that the transfer function
  //manager is using
  vtkScalarsToColors* stc =
    vtkScalarsToColors::SafeDownCast(lut->GetClientSideObject());
  this->Widget->SetLookupTable(stc);

  //lastly we set up the input connection
  this->Widget->SetInputConnection(passThroughAlg->GetOutputPort());

  Q_ASSERT(rwi);
  Q_ASSERT(passThroughAlg);
  return true;
}

//-----------------------------------------------------------------------------
void ModuleSlice::updateColorMap()
{
  Q_ASSERT(this->Widget);

  //Construct the transfer function proxy for the widget
  vtkSMProxy* lut = this->colorMap();

  //set the widgets lookup table to be the one that the transfer function
  //manager is using
  vtkScalarsToColors* stc =
    vtkScalarsToColors::SafeDownCast(lut->GetClientSideObject());
  this->Widget->SetLookupTable(stc);
}

//-----------------------------------------------------------------------------
bool ModuleSlice::finalize()
{
  vtkNew<vtkSMParaViewPipelineControllerWithRendering> controller;
  controller->UnRegisterProxy(this->PassThrough);

  this->PassThrough = NULL;

  if(this->Widget != NULL)
    {
    this->Widget->InteractionOff();
    this->Widget->Off();
    }

  return true;
}

//-----------------------------------------------------------------------------
bool ModuleSlice::setVisibility(bool val)
{
  Q_ASSERT(this->Widget);
  this->Widget->SetEnabled(val ? 1 : 0);
  return true;
}

//-----------------------------------------------------------------------------
bool ModuleSlice::visibility() const
{
  Q_ASSERT(this->Widget);
  return this->Widget->GetEnabled() != 0;
}

//-----------------------------------------------------------------------------
void ModuleSlice::addToPanel(pqProxiesWidget* panel)
{
  QStringList properties;
  properties << "ShowArrow";
  panel->addProxy(this->PropsPanelProxy, "Appearance", properties, true);

  this->Superclass::addToPanel(panel);
}

//-----------------------------------------------------------------------------
bool ModuleSlice::serialize(pugi::xml_node& ns) const
{
  // FIXME: serialize slice properties.
  return this->Superclass::serialize(ns);
}

//-----------------------------------------------------------------------------
bool ModuleSlice::deserialize(const pugi::xml_node& ns)
{
  // FIXME: deserialize slice properties.
  return this->Superclass::deserialize(ns);
}

//-----------------------------------------------------------------------------
void ModuleSlice::onPropertyChanged()
{
  vtkSMPropertyHelper showProperty(this->PropsPanelProxy, "ShowArrow");
  // Not this: it hides the plane as well as the arrow...
  //this->Widget->SetEnabled(showProperty.GetAsInt());
  this->Widget->SetArrowVisibility(showProperty.GetAsInt());
  this->Widget->SetInteraction(showProperty.GetAsInt());
}

}
<|endoftext|>


<commit_before>// The MIT License (MIT)

// Copyright (c) 2013 Danny Y., Rapptz

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef SOL_USERDATA_HPP
#define SOL_USERDATA_HPP

#include "state.hpp"
#include "function_types.hpp"
#include "demangle.hpp"
#include <vector>

namespace sol {
namespace detail {
template<typename T, typename... Args>
inline std::unique_ptr<T> make_unique(Args&&... args) {
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
} // detail

template<typename T>
class userdata {
private:
    friend table;
    static const std::string classname;
    static const std::string meta;

    std::string luaname;
    std::vector<std::string> functionnames;
    std::vector<std::unique_ptr<base_function>> functions;
    std::vector<luaL_Reg> functiontable;

    template<typename... TTypes>
    struct constructor {
        template<typename... Args>
        static void do_constructor(lua_State* L, T* obj, call_syntax syntax, int, types<Args...>) {
            auto fx = [&obj] (Args&&... args) -> void {
                std::allocator<T> alloc{};
                alloc.construct(obj, std::forward<Args>(args)...);
            };
            stack::get_call(L, 1 + static_cast<int>(syntax), fx, types<Args...>());
       }

        static void match_constructor(lua_State*, T*, call_syntax, int) {
            throw sol_error("No matching constructor for the arguments provided");
        }

        template<typename ...CArgs, typename... Args>
        static void match_constructor(lua_State* L, T* obj, call_syntax syntax, int argcount, types<CArgs...> t, Args&&... args) {
            if (argcount == sizeof...(CArgs)) {
                do_constructor(L, obj, syntax, argcount, t);
                return;
            }
            match_constructor(L, obj, syntax, argcount, std::forward<Args>(args)...);
        }

        static int construct(lua_State* L) {
            call_syntax syntax = stack::get_call_syntax(L, meta);
            int argcount = lua_gettop(L);

            void* udata = lua_newuserdata(L, sizeof(T));
            T* obj = static_cast<T*>(udata);
            match_constructor(L, obj, syntax, argcount - static_cast<int>(syntax), typename std::common_type<TTypes>::type()...);

            luaL_getmetatable(L, meta.c_str());
            lua_setmetatable(L, -2);

            return 1;
        }
    };

    template<std::size_t n>
    struct destructor {
        static int destruct(lua_State* L) {
            userdata_t udata = stack::get<userdata_t>(L, 1);
            T* obj = static_cast<T*>(udata.value);
            std::allocator<T> alloc{};
            alloc.destroy(obj);
            return 0;
        }
    };

    template<std::size_t n>
    void build_function_tables() {}

    template<std::size_t n, typename... Args, typename Ret>
    void build_function_tables(std::string name,Ret T::* func, Args&&... args) {
        typedef typename std::decay<decltype(func)>::type fx_t;
        functionnames.push_back(std::move(name));
        functions.emplace_back(detail::make_unique<userdata_function<fx_t, T>>(std::move(func)));
        functiontable.push_back({ functionnames.back().c_str(), &base_function::userdata<n>::call });
        build_function_tables<n + 1>(std::forward<Args>(args)...);
    }

public:
    template<typename... Args>
    userdata(Args&&... args): userdata(classname, default_constructor, std::forward<Args>(args)...) {}

    template<typename... Args, typename... CArgs>
    userdata(constructors<CArgs...> c, Args&&... args): userdata(classname, std::move(c), std::forward<Args>(args)...) {}

    template<typename... Args, typename... CArgs>
    userdata(std::string name, constructors<CArgs...>, Args&&... args): luaname(std::move(name)) {
        functionnames.reserve(sizeof...(args) + 2);
        functiontable.reserve(sizeof...(args) + 3);
        functions.reserve(sizeof...(args) + 2);
        build_function_tables<0>(std::forward<Args>(args)...);

        functionnames.push_back("new");
        functiontable.push_back({ functionnames.back().c_str(), &constructor<CArgs...>::construct });
        functionnames.push_back("__gc");
        functiontable.push_back({ functionnames.back().c_str(), &destructor<sizeof...(Args) / 2>::destruct });

        functiontable.push_back({ nullptr, nullptr });
    }

    template<typename... Args, typename... CArgs>
    userdata(const char* name, constructors<CArgs...> c, Args&&... args) :
        userdata(std::string(name), std::move(c), std::forward<Args>(args)...) {}

    void register_into(const table& s) {}
};

template<typename T>
const std::string userdata<T>::classname = detail::demangle(typeid(T));

template<typename T>
const std::string userdata<T>::meta = std::string("sol.stateful.").append(classname);

} // sol

#endif // SOL_USERDATA_HPP
<commit_msg>Format changes<commit_after>// The MIT License (MIT)

// Copyright (c) 2013 Danny Y., Rapptz

// Permission is hereby granted, free of charge, to any person obtaining a copy of
// this software and associated documentation files (the "Software"), to deal in
// the Software without restriction, including without limitation the rights to
// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
// the Software, and to permit persons to whom the Software is furnished to do so,
// subject to the following conditions:

// The above copyright notice and this permission notice shall be included in all
// copies or substantial portions of the Software.

// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

#ifndef SOL_USERDATA_HPP
#define SOL_USERDATA_HPP

#include "state.hpp"
#include "function_types.hpp"
#include "demangle.hpp"
#include <vector>

namespace sol {
namespace detail {
template<typename T, typename... Args>
inline std::unique_ptr<T> make_unique(Args&&... args) {
    return std::unique_ptr<T>(new T(std::forward<Args>(args)...));
}
} // detail

template<typename T>
class userdata {
private:
    friend table;
    static const std::string classname;
    static const std::string meta;

    std::string luaname;
    std::vector<std::string> functionnames;
    std::vector<std::unique_ptr<base_function>> functions;
    std::vector<luaL_Reg> functiontable;

    template<typename... TTypes>
    struct constructor {
        template<typename... Args>
        static void do_constructor(lua_State* L, T* obj, call_syntax syntax, int, types<Args...>) {
            auto fx = [&obj] (Args&&... args) -> void {
                std::allocator<T> alloc{};
                alloc.construct(obj, std::forward<Args>(args)...);
            };
            stack::get_call(L, 1 + static_cast<int>(syntax), fx, types<Args...>());
       }

        static void match_constructor(lua_State*, T*, call_syntax, int) {
            throw sol_error("No matching constructor for the arguments provided");
        }

        template<typename ...CArgs, typename... Args>
        static void match_constructor(lua_State* L, T* obj, call_syntax syntax, int argcount, types<CArgs...> t, Args&&... args) {
            if (argcount == sizeof...(CArgs)) {
                do_constructor(L, obj, syntax, argcount, t);
                return;
            }
            match_constructor(L, obj, syntax, argcount, std::forward<Args>(args)...);
        }

        static int construct(lua_State* L) {
            call_syntax syntax = stack::get_call_syntax(L, meta);
            int argcount = lua_gettop(L);

            void* udata = lua_newuserdata(L, sizeof(T));
            T* obj = static_cast<T*>(udata);
            match_constructor(L, obj, syntax, argcount - static_cast<int>(syntax), typename std::common_type<TTypes>::type()...);

            luaL_getmetatable(L, meta.c_str());
            lua_setmetatable(L, -2);

            return 1;
        }
    };

    template<std::size_t N>
    struct destructor {
        static int destruct(lua_State* L) {
            userdata_t udata = stack::get<userdata_t>(L, 1);
            T* obj = static_cast<T*>(udata.value);
            std::allocator<T> alloc{};
            alloc.destroy(obj);
            return 0;
        }
    };

    template<std::size_t N>
    void build_function_tables() {}

    template<std::size_t N, typename... Args, typename Ret>
    void build_function_tables(std::string name, Ret T::* func, Args&&... args) {
        typedef typename std::decay<decltype(func)>::type function_type;
        functionnames.push_back(std::move(name));
        functions.emplace_back(detail::make_unique<userdata_function<function_type, T>>(std::move(func)));
        functiontable.push_back({ functionnames.back().c_str(), &base_function::userdata<N>::call });
        build_function_tables<N + 1>(std::forward<Args>(args)...);
    }

public:
    template<typename... Args>
    userdata(Args&&... args): userdata(classname, default_constructor, std::forward<Args>(args)...) {}

    template<typename... Args, typename... CArgs>
    userdata(constructors<CArgs...> c, Args&&... args): userdata(classname, std::move(c), std::forward<Args>(args)...) {}

    template<typename... Args, typename... CArgs>
    userdata(std::string name, constructors<CArgs...>, Args&&... args): luaname(std::move(name)) {
        functionnames.reserve(sizeof...(args) + 2);
        functiontable.reserve(sizeof...(args) + 3);
        functions.reserve(sizeof...(args) + 2);
        build_function_tables<0>(std::forward<Args>(args)...);

        functionnames.push_back("new");
        functiontable.push_back({ functionnames.back().c_str(), &constructor<CArgs...>::construct });
        functionnames.push_back("__gc");
        functiontable.push_back({ functionnames.back().c_str(), &destructor<sizeof...(Args) / 2>::destruct });

        functiontable.push_back({ nullptr, nullptr });
    }

    template<typename... Args, typename... CArgs>
    userdata(const char* name, constructors<CArgs...> c, Args&&... args) :
        userdata(std::string(name), std::move(c), std::forward<Args>(args)...) {}

    void register_into(const table& s) {}
};

template<typename T>
const std::string userdata<T>::classname = detail::demangle(typeid(T));

template<typename T>
const std::string userdata<T>::meta = std::string("sol.stateful.").append(classname);

} // sol

#endif // SOL_USERDATA_HPP
<|endoftext|>


<commit_before>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "timedemo.h"
#include "listpage.h"
#include "timedemobenchmark.h"
#include "templatepage.h"

#include <MApplication>
#include <MWindow>
#include <MSceneManager>
#include <MApplicationPage>

#include <QApplication>
#include <QTextStream>
#include <QXmlStreamWriter>
#include <QFile>
#include <QTimer>

namespace
{
    const int pageDuration = 5000;
}

Timedemo::Timedemo(ListPage *listPage, const QStringList& demoPageTitles)
    : m_pFrontPage(listPage)
    , m_currentPageIndex(0)
    , m_currentBenchmarkIndex(0)
    , demoPageTitles(demoPageTitles)
    , timingStarted(false)
    , timingStopped(false)
{
    connect(m_pFrontPage, SIGNAL(appeared()), this, SLOT(showFirstPage()));
}

void Timedemo::setOutputCsv(const QString &filename)
{
    m_csvFilename = filename;
}

void Timedemo::setFramelog(const QString &filename)
{
    framelogFilename = filename;
}

void Timedemo::startTiming()
{
    if (timingStopped || timingStarted) {
        qFatal("New timing started, but old one not processed yet.");
    }

    timingStarted = true;
    SwapHook::instance()->startLurking();
}

void Timedemo::stopTiming()
{
    if (timingStopped || !timingStarted) {
        qFatal("Timing already processed or not running yet.");
    }

    SwapHook::instance()->stopLurking();

    QSharedPointer<TimedemoBenchmark> benchmark = demoPages[m_currentPageIndex]->benchmarks()[m_currentBenchmarkIndex];
    BenchmarkResult currentResult(SwapHook::instance()->timestamps(), benchmark->type());
    benchmarkResults[m_currentPageIndex].insert(benchmark->name(), currentResult);

    timingStopped = true;
}

void Timedemo::showFirstPage()
{
    if (demoPageTitles.count() == 0) {
        foreach(TimedemoPage *page, m_pFrontPage->pages) {
            demoPages.append(page);
        }
    } else {
        foreach(const QString title, demoPageTitles) {
            TimedemoPage *page;
            if (title == m_pFrontPage->timedemoTitle()) {
                page = m_pFrontPage;
            } else {
                page = m_pFrontPage->findPageByTimedemoTitle(title);
            }
            if (page) {
                demoPages.append(page);
            }
        }
    }

    if (demoPages.count() == 0) {
        return;
    }

    disconnect(m_pFrontPage, SIGNAL(appeared()), this, SLOT(showFirstPage()));
    m_currentPageIndex = 0;
    benchmarkResults.resize(demoPages.count());

    demoPages[m_currentPageIndex]->createBenchmarks(this);
    beginBenchmark();
}

void Timedemo::beginBenchmark()
{
    if (m_currentBenchmarkIndex >= demoPages[m_currentPageIndex]->benchmarks().count()) {
        // all benchmarks have been processed, switch to the next page
        showNextPage();
        return;
    }

    QSharedPointer<TimedemoBenchmark> benchmark = demoPages[m_currentPageIndex]->benchmarks()[m_currentBenchmarkIndex];
    if (!allBenchmarks.contains(benchmark->name())) {
        allBenchmarks.append(benchmark->name());
    }

    connect(benchmark.data(), SIGNAL(finished()), this, SLOT(benchmarkFinished()));

    benchmark->start();
}

void Timedemo::benchmarkFinished()
{
    if (!timingStopped) {
        qFatal("Benchmark did not stop timing.");
    }

    timingStarted = false;
    timingStopped = false;
    ++m_currentBenchmarkIndex;
    beginBenchmark();
}

void Timedemo::showNextPage()
{
    ++m_currentPageIndex;
    m_currentBenchmarkIndex = 0;

    if (m_currentPageIndex < demoPages.count()) {
        TimedemoPage* currentPage = demoPages[m_currentPageIndex];
        demoPages[m_currentPageIndex]->createBenchmarks(this);

        if (currentPage == m_pFrontPage) {
            // FIXME: the front page needs a special invitation.
            // otherwise it does not show up again
            if (MApplication::activeWindow()) {
                // FIXME: why appearSceneWindowNow() and not appear()?
                MApplication::activeWindow()->sceneManager()->appearSceneWindowNow(demoPages[m_currentPageIndex]);
            }
        }
        beginBenchmark();
    } else {
        // all pages shown, display results:
        displayBenchmarkResults();

        qApp->exit(0);
    }
}

void Timedemo::displayBenchmarkResults()
{
    QTextStream log(stdout, QIODevice::WriteOnly | QIODevice::Text);

    QFile statsCsvFile;
    if (m_csvFilename.isEmpty()) {
        statsCsvFile.setFileName("/dev/null");
    } else {
        statsCsvFile.setFileName(m_csvFilename);
    }

    statsCsvFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
    QTextStream statsCsv(&statsCsvFile);

    int pageTitleWidth = 0;
    const int fpsWidth = 5;
    const int fpsUnitWidth = 5;
    const int runtimeWidth = 5;
    const int runtimeUnitWidth = 2;
    const int benchmarkWidth = fpsWidth + fpsUnitWidth + runtimeWidth + runtimeUnitWidth;
    QHash<QString, int> actualWidth;

    for (int i = 0; i < benchmarkResults.count(); ++i) {
        TimedemoPage *page = demoPages[i];
        QString title = page->timedemoTitle();
        pageTitleWidth = qMax(pageTitleWidth, title.length());
    }
    pageTitleWidth += 2;

    log.setRealNumberNotation(QTextStream::FixedNotation);
    log.setRealNumberPrecision(2);
    log << left << qSetFieldWidth(pageTitleWidth) << "Page name";
    statsCsv << "Page name";

    foreach(const QString& name, allBenchmarks) {
        int width = qMax(benchmarkWidth + 2, name.length() + 2);
        log << qSetFieldWidth(width) << name;
        statsCsv << ", \"" << name << " [fps]\", \"" << name << " [ms]\"";

        actualWidth[name] = width;
    }
    log << qSetFieldWidth(0) << '\n';
    statsCsv << '\n';

    for (int i = 0; i < benchmarkResults.count(); ++i) {
        TimedemoPage *page = demoPages[i];
        QString title = page->timedemoTitle();

        log << qSetFieldWidth(pageTitleWidth) << title;
        statsCsv << "\"" << title << "\"";

        BenchmarkResultHash results = benchmarkResults[i];
        foreach(const QString& name, allBenchmarks) {
            statsCsv << ", ";
            BenchmarkResultHash::const_iterator resultIter = results.find(name);
            if (resultIter != results.constEnd() && resultIter->fps() != 0 && resultIter->runtime() != 0) {
                log << right
                    << qSetFieldWidth(fpsWidth) << resultIter->fps()
                    << qSetFieldWidth(fpsUnitWidth) << "fps |"
                    << qSetFieldWidth(runtimeWidth) << resultIter->runtime()
                    << qSetFieldWidth(runtimeUnitWidth) << "ms"
                    << qSetFieldWidth(actualWidth[name] - benchmarkWidth) << ""
                    << left;
            } else {
                log << qSetFieldWidth(actualWidth[name]) << center << "n/a" << left;
            }
            statsCsv << resultIter->fps() << ", " << resultIter->runtime();
        }
        log << qSetFieldWidth(0) << '\n';
        statsCsv << '\n';
    }

    log.flush();
    statsCsv.flush();
    saveFramelog();
}

void Timedemo::saveFramelog() {
    QFile framelogFile;
    if (framelogFilename.isEmpty()) {
        return;
    } else {
        framelogFile.setFileName(framelogFilename);
    }

    framelogFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
    QXmlStreamWriter framelog(&framelogFile);
    framelog.setAutoFormatting(true);
    framelog.writeStartDocument();
    framelog.writeDTD("<!DOCTYPE timedemo>");
    framelog.writeStartElement("timedemo");

    for (int i = 0; i < benchmarkResults.count(); ++i) {
        framelog.writeStartElement("page");
        TimedemoPage *page = demoPages[i];
        QString title = page->timedemoTitle();

        framelog.writeAttribute("id", title);

        BenchmarkResultHash results = benchmarkResults[i];
        foreach(const QString& name, allBenchmarks) {
            BenchmarkResultHash::const_iterator resultIter = results.find(name);
            if (resultIter == results.end()) {
                continue;
            }
            framelog.writeStartElement("benchmark");
            framelog.writeAttribute("id", name);
            framelog.writeTextElement("type", resultIter->type);
            framelog.writeTextElement("runtime", QString::number(resultIter->runtime()));
            QString timestamps;
            foreach(const timestamp ts, resultIter->timestamps) {
                timestamps.append(QString::number(ts) + ',');
            }
            timestamps.truncate(timestamps.size() - 1);
            framelog.writeTextElement("frames", timestamps);

            // "page"
            framelog.writeEndElement();
        }

        // "benchmark"
        framelog.writeEndElement();
    }

    framelog.writeEndElement();
    framelog.writeEndDocument();

    framelogFile.flush();
}
<commit_msg>Changes: Fix coverity issue 5<commit_after>/***************************************************************************
**
** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
** All rights reserved.
** Contact: Nokia Corporation (directui@nokia.com)
**
** This file is part of libmeegotouch.
**
** If you have questions regarding the use of this file, please contact
** Nokia at directui@nokia.com.
**
** This library is free software; you can redistribute it and/or
** modify it under the terms of the GNU Lesser General Public
** License version 2.1 as published by the Free Software Foundation
** and appearing in the file LICENSE.LGPL included in the packaging
** of this file.
**
****************************************************************************/

#include "timedemo.h"
#include "listpage.h"
#include "timedemobenchmark.h"
#include "templatepage.h"

#include <MApplication>
#include <MWindow>
#include <MSceneManager>
#include <MApplicationPage>

#include <QApplication>
#include <QTextStream>
#include <QXmlStreamWriter>
#include <QFile>
#include <QTimer>

namespace
{
    const int pageDuration = 5000;
}

Timedemo::Timedemo(ListPage *listPage, const QStringList& demoPageTitles)
    : m_pFrontPage(listPage)
    , m_currentPageIndex(0)
    , m_currentBenchmarkIndex(0)
    , demoPageTitles(demoPageTitles)
    , timingStarted(false)
    , timingStopped(false)
{
    connect(m_pFrontPage, SIGNAL(appeared()), this, SLOT(showFirstPage()));
}

void Timedemo::setOutputCsv(const QString &filename)
{
    m_csvFilename = filename;
}

void Timedemo::setFramelog(const QString &filename)
{
    framelogFilename = filename;
}

void Timedemo::startTiming()
{
    if (timingStopped || timingStarted) {
        qFatal("New timing started, but old one not processed yet.");
    }

    timingStarted = true;
    SwapHook::instance()->startLurking();
}

void Timedemo::stopTiming()
{
    if (timingStopped || !timingStarted) {
        qFatal("Timing already processed or not running yet.");
    }

    SwapHook::instance()->stopLurking();

    QSharedPointer<TimedemoBenchmark> benchmark = demoPages[m_currentPageIndex]->benchmarks()[m_currentBenchmarkIndex];
    BenchmarkResult currentResult(SwapHook::instance()->timestamps(), benchmark->type());
    benchmarkResults[m_currentPageIndex].insert(benchmark->name(), currentResult);

    timingStopped = true;
}

void Timedemo::showFirstPage()
{
    if (demoPageTitles.count() == 0) {
        foreach(TimedemoPage *page, m_pFrontPage->pages) {
            demoPages.append(page);
        }
    } else {
        foreach(const QString title, demoPageTitles) {
            TimedemoPage *page;
            if (title == m_pFrontPage->timedemoTitle()) {
                page = m_pFrontPage;
            } else {
                page = m_pFrontPage->findPageByTimedemoTitle(title);
            }
            if (page) {
                demoPages.append(page);
            }
        }
    }

    if (demoPages.count() == 0) {
        return;
    }

    disconnect(m_pFrontPage, SIGNAL(appeared()), this, SLOT(showFirstPage()));
    m_currentPageIndex = 0;
    benchmarkResults.resize(demoPages.count());

    demoPages[m_currentPageIndex]->createBenchmarks(this);
    beginBenchmark();
}

void Timedemo::beginBenchmark()
{
    if (m_currentBenchmarkIndex >= demoPages[m_currentPageIndex]->benchmarks().count()) {
        // all benchmarks have been processed, switch to the next page
        showNextPage();
        return;
    }

    QSharedPointer<TimedemoBenchmark> benchmark = demoPages[m_currentPageIndex]->benchmarks()[m_currentBenchmarkIndex];
    if (!allBenchmarks.contains(benchmark->name())) {
        allBenchmarks.append(benchmark->name());
    }

    connect(benchmark.data(), SIGNAL(finished()), this, SLOT(benchmarkFinished()));

    benchmark->start();
}

void Timedemo::benchmarkFinished()
{
    if (!timingStopped) {
        qFatal("Benchmark did not stop timing.");
    }

    timingStarted = false;
    timingStopped = false;
    ++m_currentBenchmarkIndex;
    beginBenchmark();
}

void Timedemo::showNextPage()
{
    ++m_currentPageIndex;
    m_currentBenchmarkIndex = 0;

    if (m_currentPageIndex < demoPages.count()) {
        TimedemoPage* currentPage = demoPages[m_currentPageIndex];
        demoPages[m_currentPageIndex]->createBenchmarks(this);

        if (currentPage == m_pFrontPage) {
            // FIXME: the front page needs a special invitation.
            // otherwise it does not show up again
            if (MApplication::activeWindow()) {
                // FIXME: why appearSceneWindowNow() and not appear()?
                MApplication::activeWindow()->sceneManager()->appearSceneWindowNow(demoPages[m_currentPageIndex]);
            }
        }
        beginBenchmark();
    } else {
        // all pages shown, display results:
        displayBenchmarkResults();

        qApp->exit(0);
    }
}

void Timedemo::displayBenchmarkResults()
{
    QTextStream log(stdout, QIODevice::WriteOnly | QIODevice::Text);

    QFile statsCsvFile;
    if (m_csvFilename.isEmpty()) {
        statsCsvFile.setFileName("/dev/null");
    } else {
        statsCsvFile.setFileName(m_csvFilename);
    }

    if ( ! statsCsvFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text) )
    {
        qWarning( "failed to open stats file: %s", qPrintable( statsCsvFile.fileName() ) );
    }

    QTextStream statsCsv(&statsCsvFile);

    int pageTitleWidth = 0;
    const int fpsWidth = 5;
    const int fpsUnitWidth = 5;
    const int runtimeWidth = 5;
    const int runtimeUnitWidth = 2;
    const int benchmarkWidth = fpsWidth + fpsUnitWidth + runtimeWidth + runtimeUnitWidth;
    QHash<QString, int> actualWidth;

    for (int i = 0; i < benchmarkResults.count(); ++i) {
        TimedemoPage *page = demoPages[i];
        QString title = page->timedemoTitle();
        pageTitleWidth = qMax(pageTitleWidth, title.length());
    }
    pageTitleWidth += 2;

    log.setRealNumberNotation(QTextStream::FixedNotation);
    log.setRealNumberPrecision(2);
    log << left << qSetFieldWidth(pageTitleWidth) << "Page name";
    statsCsv << "Page name";

    foreach(const QString& name, allBenchmarks) {
        int width = qMax(benchmarkWidth + 2, name.length() + 2);
        log << qSetFieldWidth(width) << name;
        statsCsv << ", \"" << name << " [fps]\", \"" << name << " [ms]\"";

        actualWidth[name] = width;
    }
    log << qSetFieldWidth(0) << '\n';
    statsCsv << '\n';

    for (int i = 0; i < benchmarkResults.count(); ++i) {
        TimedemoPage *page = demoPages[i];
        QString title = page->timedemoTitle();

        log << qSetFieldWidth(pageTitleWidth) << title;
        statsCsv << "\"" << title << "\"";

        BenchmarkResultHash results = benchmarkResults[i];
        foreach(const QString& name, allBenchmarks) {
            statsCsv << ", ";
            BenchmarkResultHash::const_iterator resultIter = results.find(name);
            if (resultIter != results.constEnd() && resultIter->fps() != 0 && resultIter->runtime() != 0) {
                log << right
                    << qSetFieldWidth(fpsWidth) << resultIter->fps()
                    << qSetFieldWidth(fpsUnitWidth) << "fps |"
                    << qSetFieldWidth(runtimeWidth) << resultIter->runtime()
                    << qSetFieldWidth(runtimeUnitWidth) << "ms"
                    << qSetFieldWidth(actualWidth[name] - benchmarkWidth) << ""
                    << left;
            } else {
                log << qSetFieldWidth(actualWidth[name]) << center << "n/a" << left;
            }
            statsCsv << resultIter->fps() << ", " << resultIter->runtime();
        }
        log << qSetFieldWidth(0) << '\n';
        statsCsv << '\n';
    }

    log.flush();
    statsCsv.flush();
    saveFramelog();
}

void Timedemo::saveFramelog() {
    QFile framelogFile;
    if (framelogFilename.isEmpty()) {
        return;
    } else {
        framelogFile.setFileName(framelogFilename);
    }

    framelogFile.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text);
    QXmlStreamWriter framelog(&framelogFile);
    framelog.setAutoFormatting(true);
    framelog.writeStartDocument();
    framelog.writeDTD("<!DOCTYPE timedemo>");
    framelog.writeStartElement("timedemo");

    for (int i = 0; i < benchmarkResults.count(); ++i) {
        framelog.writeStartElement("page");
        TimedemoPage *page = demoPages[i];
        QString title = page->timedemoTitle();

        framelog.writeAttribute("id", title);

        BenchmarkResultHash results = benchmarkResults[i];
        foreach(const QString& name, allBenchmarks) {
            BenchmarkResultHash::const_iterator resultIter = results.find(name);
            if (resultIter == results.end()) {
                continue;
            }
            framelog.writeStartElement("benchmark");
            framelog.writeAttribute("id", name);
            framelog.writeTextElement("type", resultIter->type);
            framelog.writeTextElement("runtime", QString::number(resultIter->runtime()));
            QString timestamps;
            foreach(const timestamp ts, resultIter->timestamps) {
                timestamps.append(QString::number(ts) + ',');
            }
            timestamps.truncate(timestamps.size() - 1);
            framelog.writeTextElement("frames", timestamps);

            // "page"
            framelog.writeEndElement();
        }

        // "benchmark"
        framelog.writeEndElement();
    }

    framelog.writeEndElement();
    framelog.writeEndDocument();

    framelogFile.flush();
}
<|endoftext|>