Exemplo n.º 1
1
FileDescriptor openFileHandle(const char *path,
                              const OpenFileHandleOptions &opts) {
#ifndef _WIN32
  int flags = (!opts.followSymlinks ? O_NOFOLLOW : 0) |
              (opts.closeOnExec ? O_CLOEXEC : 0) |
#ifdef O_PATH
              (opts.metaDataOnly ? O_PATH : 0) |
#endif
              ((opts.readContents && opts.writeContents)
                   ? O_RDWR
                   : (opts.writeContents ? O_WRONLY
                                         : opts.readContents ? O_RDONLY : 0)) |
              (opts.create ? O_CREAT : 0) |
              (opts.exclusiveCreate ? O_EXCL : 0) |
              (opts.truncate ? O_TRUNC : 0);

  auto fd = open(path, flags);
  if (fd == -1) {
    int err = errno;
    throw std::system_error(
        err, std::generic_category(), to<std::string>("open: ", path));
  }
  FileDescriptor file(fd);
#else // _WIN32
  DWORD access = 0, share = 0, create = 0, attrs = 0;
  DWORD err;
  auto sec = SECURITY_ATTRIBUTES();

  if (!strcmp(path, "/dev/null")) {
    path = "NUL:";
  }

  auto wpath = w_string_piece(path).asWideUNC();

  if (opts.metaDataOnly) {
    access = 0;
  } else {
    if (opts.writeContents) {
      access |= GENERIC_WRITE;
    }
    if (opts.readContents) {
      access |= GENERIC_READ;
    }
  }

  // We want more posix-y behavior by default
  share = FILE_SHARE_DELETE | FILE_SHARE_READ | FILE_SHARE_WRITE;

  sec.nLength = sizeof(sec);
  sec.bInheritHandle = TRUE;
  if (opts.closeOnExec) {
    sec.bInheritHandle = FALSE;
  }

  if (opts.create && opts.exclusiveCreate) {
    create = CREATE_NEW;
  } else if (opts.create && opts.truncate) {
    create = CREATE_ALWAYS;
  } else if (opts.create) {
    create = OPEN_ALWAYS;
  } else if (opts.truncate) {
    create = TRUNCATE_EXISTING;
  } else {
    create = OPEN_EXISTING;
  }

  attrs = FILE_FLAG_POSIX_SEMANTICS | FILE_FLAG_BACKUP_SEMANTICS;
  if (!opts.followSymlinks) {
    attrs |= FILE_FLAG_OPEN_REPARSE_POINT;
  }

  FileDescriptor file(intptr_t(
      CreateFileW(wpath.c_str(), access, share, &sec, create, attrs, nullptr)));
  err = GetLastError();
  if (!file) {
    throw std::system_error(
        err,
        std::system_category(),
        std::string("CreateFileW for openFileHandle: ") + path);
  }

#endif

  if (!opts.strictNameChecks) {
    return file;
  }

  auto opened = file.getOpenedPath();
  if (w_string_piece(opened).pathIsEqual(path)) {
#if !CAN_OPEN_SYMLINKS
    CaseSensitivity caseSensitive = opts.caseSensitive;
    if (caseSensitive == CaseSensitivity::Unknown) {
      caseSensitive = getCaseSensitivityForPath(path);
    }
    if (caseSensitive == CaseSensitivity::CaseInSensitive) {
      // We need to perform one extra check for case-insensitive
      // paths to make sure that we didn't accidentally open
      // the wrong case name.
      checkCanonicalBaseName(path);
    }
#endif
    return file;
  }

  throw std::system_error(
      ENOENT, std::generic_category(),
      to<std::string>("open(", path,
                      "): opened path doesn't match canonical path ", opened));
}
Exemplo n.º 2
0
void test_split() {
  {
    std::vector<std::string> expected{"a", "b", "c"};
    std::vector<std::string> result;
    w_string_piece("a:b:c").split(result, ':');

    ok(expected == result, "split ok");
  }

  {
    std::vector<w_string> expected{"a", "b", "c"};
    std::vector<w_string> result;
    w_string_piece("a:b:c").split(result, ':');

    ok(expected == result, "split ok (w_string)");
  }

  {
    std::vector<std::string> expected{"a", "b", "c"};
    std::vector<std::string> result;
    w_string_piece("a:b:c:").split(result, ':');

    ok(expected == result, "split doesn't create empty last element");
  }

  {
    std::vector<std::string> expected{"a", "b", "", "c"};
    std::vector<std::string> result;
    w_string_piece("a:b::c:").split(result, ':');

    ok(expected == result, "split does create empty element");
  }
}
Exemplo n.º 3
0
/** Checks that the basename component of the input path exactly
 * matches the canonical case of the path on disk.
 * It only makes sense to call this function on a case insensitive filesystem.
 * If the case does not match, throws an exception. */
static void checkCanonicalBaseName(const char *path) {
#ifdef __APPLE__
  struct attrlist attrlist;
  struct {
    uint32_t len;
    attrreference_t ref;
    char canonical_name[WATCHMAN_NAME_MAX];
  } vomit;
  w_string_piece pathPiece(path);
  auto base = pathPiece.baseName();

  memset(&attrlist, 0, sizeof(attrlist));
  attrlist.bitmapcount = ATTR_BIT_MAP_COUNT;
  attrlist.commonattr = ATTR_CMN_NAME;

  if (getattrlist(path, &attrlist, &vomit, sizeof(vomit), FSOPT_NOFOLLOW) ==
      -1) {
    throw std::system_error(errno, std::generic_category(),
                            to<std::string>("checkCanonicalBaseName(", path,
                                            "): getattrlist failed"));
  }

  w_string_piece name(((char *)&vomit.ref) + vomit.ref.attr_dataoffset);
  if (name != base) {
    throw std::system_error(
        ENOENT, std::generic_category(),
        to<std::string>("checkCanonicalBaseName(", path, "): (", name,
                        ") doesn't match canonical base (", base, ")"));
  }
#else
  // Older Linux and BSDish systems are in this category.
  // This is the awful portable fallback used in the absence of
  // a system specific way to detect this.
  w_string_piece pathPiece(path);
  auto parent = pathPiece.dirName().asWString();
  auto dir = w_dir_open(parent.c_str());
  auto base = pathPiece.baseName();

  while (true) {
    auto ent = dir->readDir();
    if (!ent) {
      // We didn't find an entry that exactly matched -> fail
      throw std::system_error(
          ENOENT, std::generic_category(),
          to<std::string>("checkCanonicalBaseName(", path,
                          "): no match found in parent dir"));
    }
    // Note: we don't break out early if we get a case-insensitive match
    // because the dir may contain multiple representations of the same
    // name.  For example, Bash-for-Windows has dirs that contain both
    // "pod" and "Pod" dirs in its perl installation.  We want to make
    // sure that we've observed all of the entries in the dir before
    // giving up.
    if (w_string_piece(ent->d_name) == base) {
      // Exact match; all is good!
      return;
    }
  }
#endif
}
Exemplo n.º 4
0
w_string_piece w_string_piece::dirName() const {
  for (auto end = e_; end >= s_; --end) {
    if (is_slash(*end)) {
      /* found the end of the parent dir */
      return w_string_piece(s_, end - s_);
    }
  }
  return nullptr;
}
Exemplo n.º 5
0
w_string_piece w_string_piece::baseName() const {
  for (auto end = e_; end >= s_; --end) {
    if (is_slash(*end)) {
      /* found the end of the parent dir */
      return w_string_piece(end + 1, e_ - (end + 1));
    }
  }

  return *this;
}
Exemplo n.º 6
0
void test_basename_dirname() {
  auto str = w_string_piece("foo/bar").baseName().asWString();
  ok(str == "bar", "basename of foo/bar is bar: %s", str.c_str());

  str = w_string_piece("foo/bar").dirName().asWString();
  ok(str == "foo", "dirname of foo/bar is foo: %s", str.c_str());

  str = w_string_piece("foo").dirName().asWString();
  ok(str == "", "dirname of foo is nothing: %s", str.c_str());

  str = w_string_piece("foo").baseName().asWString();
  ok(str == "foo", "basename of foo is foo: %s", str.c_str());

  str = w_string_piece("foo\\bar").baseName().asWString();
#ifdef _WIN32
  ok(str == "bar", "basename of foo\\bar is bar: %s", str.c_str());
#else
  ok(str == "foo\\bar", "basename of foo\\bar is foo\\bar: %s", str.c_str());
#endif

  str = w_string_piece("foo\\bar").dirName().asWString();
#ifdef _WIN32
  ok(str == "foo", "dirname of foo\\bar is foo: %s", str.c_str());
#else
  ok(str == "", "dirname of foo\\bar is nothing: %s", str.c_str());
#endif
}
Exemplo n.º 7
0
void InMemoryView::globGenerator(w_query* query, struct w_query_ctx* ctx)
    const {
  w_string_t *relative_root;

  if (query->relative_root) {
    relative_root = query->relative_root;
  } else {
    relative_root = root_path;
  }

  auto view = view_.rlock();

  const auto dir = resolveDir(view, relative_root);
  if (!dir) {
    throw QueryExecError(watchman::to<std::string>(
        "glob_generator could not resolve ",
        w_string_piece(relative_root),
        ", check your "
        "relative_root parameter!"));
  }

  globGeneratorTree(ctx, query->glob_tree.get(), dir);
}
Exemplo n.º 8
0
void test_operator() {
  ok(w_string_piece("a") < w_string_piece("b"), "a < b");
  ok(w_string_piece("a") < w_string_piece("ba"), "a < ba");
  ok(w_string_piece("aa") < w_string_piece("b"), "aa < b");
  ok(!(w_string_piece("b") < w_string_piece("a")), "b not < a");
  ok(!(w_string_piece("a") < w_string_piece("a")), "a not < a");
  ok(w_string_piece("A") < w_string_piece("a"), "A < a");
}