summaryrefslogtreecommitdiffstats
path: root/dom/system/OSFileConstants.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/system/OSFileConstants.cpp')
-rw-r--r--dom/system/OSFileConstants.cpp983
1 files changed, 983 insertions, 0 deletions
diff --git a/dom/system/OSFileConstants.cpp b/dom/system/OSFileConstants.cpp
new file mode 100644
index 0000000000..fa7e9532af
--- /dev/null
+++ b/dom/system/OSFileConstants.cpp
@@ -0,0 +1,983 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+#include "mozilla/DebugOnly.h"
+
+#include "fcntl.h"
+#include "errno.h"
+
+#include "prsystem.h"
+
+// Short macro to get the size of a member of a
+// given struct at compile time.
+// t is the type of struct, m the name of the
+// member:
+// DOM_SIZEOF_MEMBER(struct mystruct, myint)
+// will give you the size of the type of myint.
+#define DOM_SIZEOF_MEMBER(t, m) sizeof(((t*)0)->m)
+
+#if defined(XP_UNIX)
+# include "unistd.h"
+# include "dirent.h"
+# include "poll.h"
+# include "sys/stat.h"
+# if defined(XP_LINUX)
+# include <sys/prctl.h>
+# include <sys/vfs.h>
+# define statvfs statfs
+# define f_frsize f_bsize
+# else
+# include "sys/statvfs.h"
+# endif // defined(XP_LINUX)
+# if !defined(ANDROID)
+# include "sys/wait.h"
+# include <spawn.h>
+# endif // !defined(ANDROID)
+#endif // defined(XP_UNIX)
+
+#if defined(XP_LINUX)
+# include <linux/fadvise.h>
+#endif // defined(XP_LINUX)
+
+#if defined(XP_MACOSX)
+# include "copyfile.h"
+#endif // defined(XP_MACOSX)
+
+#if defined(XP_WIN)
+# include <windows.h>
+# include <accctrl.h>
+
+# ifndef PATH_MAX
+# define PATH_MAX MAX_PATH
+# endif
+
+#endif // defined(XP_WIN)
+
+#include "jsapi.h"
+#include "jsfriendapi.h"
+#include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
+#include "js/PropertyAndElement.h" // JS_DefineObject, JS_DefineProperty, JS_GetProperty, JS_SetProperty
+#include "BindingUtils.h"
+
+// Used to provide information on the OS
+
+#include "nsThreadUtils.h"
+#include "nsIObserverService.h"
+#include "nsIObserver.h"
+#include "nsDirectoryServiceUtils.h"
+#include "nsIXULRuntime.h"
+#include "nsXPCOMCIDInternal.h"
+#include "nsServiceManagerUtils.h"
+#include "nsString.h"
+#include "nsSystemInfo.h"
+#include "nsDirectoryServiceDefs.h"
+#include "nsXULAppAPI.h"
+#include "nsAppDirectoryServiceDefs.h"
+#include "mozJSModuleLoader.h"
+
+#include "mozilla/ClearOnShutdown.h"
+#include "mozilla/StaticPtr.h"
+#include "mozilla/UniquePtr.h"
+
+#include "OSFileConstants.h"
+#include "nsZipArchive.h"
+
+#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
+ defined(__OpenBSD__)
+# define __dd_fd dd_fd
+#endif
+
+/**
+ * This module defines the basic libc constants (error numbers, open modes,
+ * etc.) used by OS.File and possibly other OS-bound JavaScript libraries.
+ */
+
+namespace mozilla {
+
+namespace {
+
+StaticRefPtr<OSFileConstantsService> gInstance;
+
+} // anonymous namespace
+
+struct OSFileConstantsService::Paths {
+ /**
+ * The name of the directory holding all the libraries (libxpcom, libnss,
+ * etc.)
+ */
+ nsString libDir;
+ nsString tmpDir;
+ nsString profileDir;
+ nsString localProfileDir;
+
+ Paths() {
+ libDir.SetIsVoid(true);
+ tmpDir.SetIsVoid(true);
+ profileDir.SetIsVoid(true);
+ localProfileDir.SetIsVoid(true);
+ }
+};
+
+/**
+ * Return the path to one of the special directories.
+ *
+ * @param aKey The key to the special directory (e.g. "TmpD", "ProfD", ...)
+ * @param aOutPath The path to the special directory. In case of error,
+ * the string is set to void.
+ */
+nsresult GetPathToSpecialDir(const char* aKey, nsString& aOutPath) {
+ nsCOMPtr<nsIFile> file;
+ nsresult rv = NS_GetSpecialDirectory(aKey, getter_AddRefs(file));
+ if (NS_FAILED(rv) || !file) {
+ return rv;
+ }
+
+ return file->GetPath(aOutPath);
+}
+
+/**
+ * In some cases, OSFileConstants may be instantiated before the
+ * profile is setup. In such cases, |OS.Constants.Path.profileDir| and
+ * |OS.Constants.Path.localProfileDir| are undefined. However, we want
+ * to ensure that this does not break existing code, so that future
+ * workers spawned after the profile is setup have these constants.
+ *
+ * For this purpose, we register an observer to set |mPaths->profileDir|
+ * and |mPaths->localProfileDir| once the profile is setup.
+ */
+NS_IMETHODIMP
+OSFileConstantsService::Observe(nsISupports*, const char* aTopic,
+ const char16_t*) {
+ if (!mInitialized) {
+ // Initialization has not taken place, something is wrong,
+ // don't make things worse.
+ return NS_OK;
+ }
+
+ nsresult rv =
+ GetPathToSpecialDir(NS_APP_USER_PROFILE_50_DIR, mPaths->profileDir);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_LOCAL_50_DIR,
+ mPaths->localProfileDir);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ return NS_OK;
+}
+
+/**
+ * Perform the part of initialization that can only be
+ * executed on the main thread.
+ */
+nsresult OSFileConstantsService::InitOSFileConstants() {
+ MOZ_ASSERT(NS_IsMainThread());
+ if (mInitialized) {
+ return NS_OK;
+ }
+
+ UniquePtr<Paths> paths(new Paths);
+
+ // Initialize paths->libDir
+ nsCOMPtr<nsIFile> file;
+ nsresult rv =
+ NS_GetSpecialDirectory(NS_XPCOM_LIBRARY_FILE, getter_AddRefs(file));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ nsCOMPtr<nsIFile> libDir;
+ rv = file->GetParent(getter_AddRefs(libDir));
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ rv = libDir->GetPath(paths->libDir);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ // Setup profileDir and localProfileDir immediately if possible (we
+ // assume that NS_APP_USER_PROFILE_50_DIR and
+ // NS_APP_USER_PROFILE_LOCAL_50_DIR are set simultaneously)
+ rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_50_DIR, paths->profileDir);
+ if (NS_SUCCEEDED(rv)) {
+ rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_LOCAL_50_DIR,
+ paths->localProfileDir);
+ }
+
+ // Otherwise, delay setup of profileDir/localProfileDir until they
+ // become available.
+ if (NS_FAILED(rv)) {
+ nsCOMPtr<nsIObserverService> obsService =
+ do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ rv = obsService->AddObserver(this, "profile-do-change", false);
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+ }
+
+ GetPathToSpecialDir(NS_OS_TEMP_DIR, paths->tmpDir);
+
+ mPaths = std::move(paths);
+
+ // Get the umask from the system-info service.
+ // The property will always be present, but it will be zero on
+ // non-Unix systems.
+ // nsSystemInfo::gUserUmask is initialized by NS_InitXPCOM so we don't need
+ // to initialize the service.
+ mUserUmask = nsSystemInfo::gUserUmask;
+
+ mInitialized = true;
+ return NS_OK;
+}
+
+/**
+ * Define a simple read-only property holding an integer.
+ *
+ * @param name The name of the constant. Used both as the JS name for the
+ * constant and to access its value. Must be defined.
+ *
+ * Produces a |ConstantSpec|.
+ */
+#define INT_CONSTANT(name) \
+ { #name, JS::Int32Value(name) }
+
+/**
+ * Define a simple read-only property holding an unsigned integer.
+ *
+ * @param name The name of the constant. Used both as the JS name for the
+ * constant and to access its value. Must be defined.
+ *
+ * Produces a |ConstantSpec|.
+ */
+#define UINT_CONSTANT(name) \
+ { #name, JS::NumberValue(name) }
+
+/**
+ * End marker for ConstantSpec
+ */
+#define PROP_END \
+ { nullptr, JS::UndefinedValue() }
+
+// Define missing constants for Android
+#if !defined(S_IRGRP)
+# define S_IXOTH 0001
+# define S_IWOTH 0002
+# define S_IROTH 0004
+# define S_IRWXO 0007
+# define S_IXGRP 0010
+# define S_IWGRP 0020
+# define S_IRGRP 0040
+# define S_IRWXG 0070
+# define S_IXUSR 0100
+# define S_IWUSR 0200
+# define S_IRUSR 0400
+# define S_IRWXU 0700
+#endif // !defined(S_IRGRP)
+
+/**
+ * The properties defined in libc.
+ *
+ * If you extend this list of properties, please
+ * separate categories ("errors", "open", etc.),
+ * keep properties organized by alphabetical order
+ * and #ifdef-away properties that are not portable.
+ */
+static const dom::ConstantSpec gLibcProperties[] = {
+ // Arguments for open
+ INT_CONSTANT(O_APPEND),
+#if defined(O_CLOEXEC)
+ INT_CONSTANT(O_CLOEXEC),
+#endif // defined(O_CLOEXEC)
+ INT_CONSTANT(O_CREAT),
+#if defined(O_DIRECTORY)
+ INT_CONSTANT(O_DIRECTORY),
+#endif // defined(O_DIRECTORY)
+#if defined(O_EVTONLY)
+ INT_CONSTANT(O_EVTONLY),
+#endif // defined(O_EVTONLY)
+ INT_CONSTANT(O_EXCL),
+#if defined(O_EXLOCK)
+ INT_CONSTANT(O_EXLOCK),
+#endif // defined(O_EXLOCK)
+#if defined(O_LARGEFILE)
+ INT_CONSTANT(O_LARGEFILE),
+#endif // defined(O_LARGEFILE)
+#if defined(O_NOFOLLOW)
+ INT_CONSTANT(O_NOFOLLOW),
+#endif // defined(O_NOFOLLOW)
+#if defined(O_NONBLOCK)
+ INT_CONSTANT(O_NONBLOCK),
+#endif // defined(O_NONBLOCK)
+ INT_CONSTANT(O_RDONLY),
+ INT_CONSTANT(O_RDWR),
+#if defined(O_RSYNC)
+ INT_CONSTANT(O_RSYNC),
+#endif // defined(O_RSYNC)
+#if defined(O_SHLOCK)
+ INT_CONSTANT(O_SHLOCK),
+#endif // defined(O_SHLOCK)
+#if defined(O_SYMLINK)
+ INT_CONSTANT(O_SYMLINK),
+#endif // defined(O_SYMLINK)
+#if defined(O_SYNC)
+ INT_CONSTANT(O_SYNC),
+#endif // defined(O_SYNC)
+ INT_CONSTANT(O_TRUNC),
+ INT_CONSTANT(O_WRONLY),
+
+#if defined(FD_CLOEXEC)
+ INT_CONSTANT(FD_CLOEXEC),
+#endif // defined(FD_CLOEXEC)
+
+#if defined(AT_EACCESS)
+ INT_CONSTANT(AT_EACCESS),
+#endif // defined(AT_EACCESS)
+#if defined(AT_FDCWD)
+ INT_CONSTANT(AT_FDCWD),
+#endif // defined(AT_FDCWD)
+#if defined(AT_SYMLINK_NOFOLLOW)
+ INT_CONSTANT(AT_SYMLINK_NOFOLLOW),
+#endif // defined(AT_SYMLINK_NOFOLLOW)
+
+#if defined(POSIX_FADV_SEQUENTIAL)
+ INT_CONSTANT(POSIX_FADV_SEQUENTIAL),
+#endif // defined(POSIX_FADV_SEQUENTIAL)
+
+// access
+#if defined(F_OK)
+ INT_CONSTANT(F_OK),
+ INT_CONSTANT(R_OK),
+ INT_CONSTANT(W_OK),
+ INT_CONSTANT(X_OK),
+#endif // defined(F_OK)
+
+ // modes
+ INT_CONSTANT(S_IRGRP),
+ INT_CONSTANT(S_IROTH),
+ INT_CONSTANT(S_IRUSR),
+ INT_CONSTANT(S_IRWXG),
+ INT_CONSTANT(S_IRWXO),
+ INT_CONSTANT(S_IRWXU),
+ INT_CONSTANT(S_IWGRP),
+ INT_CONSTANT(S_IWOTH),
+ INT_CONSTANT(S_IWUSR),
+ INT_CONSTANT(S_IXOTH),
+ INT_CONSTANT(S_IXGRP),
+ INT_CONSTANT(S_IXUSR),
+
+ // seek
+ INT_CONSTANT(SEEK_CUR),
+ INT_CONSTANT(SEEK_END),
+ INT_CONSTANT(SEEK_SET),
+
+#if defined(XP_UNIX)
+ // poll
+ INT_CONSTANT(POLLERR),
+ INT_CONSTANT(POLLHUP),
+ INT_CONSTANT(POLLIN),
+ INT_CONSTANT(POLLNVAL),
+ INT_CONSTANT(POLLOUT),
+
+// wait
+# if defined(WNOHANG)
+ INT_CONSTANT(WNOHANG),
+# endif // defined(WNOHANG)
+
+ // fcntl command values
+ INT_CONSTANT(F_GETLK),
+ INT_CONSTANT(F_SETFD),
+ INT_CONSTANT(F_SETFL),
+ INT_CONSTANT(F_SETLK),
+ INT_CONSTANT(F_SETLKW),
+
+ // flock type values
+ INT_CONSTANT(F_RDLCK),
+ INT_CONSTANT(F_WRLCK),
+ INT_CONSTANT(F_UNLCK),
+
+// splice
+# if defined(SPLICE_F_MOVE)
+ INT_CONSTANT(SPLICE_F_MOVE),
+# endif // defined(SPLICE_F_MOVE)
+# if defined(SPLICE_F_NONBLOCK)
+ INT_CONSTANT(SPLICE_F_NONBLOCK),
+# endif // defined(SPLICE_F_NONBLOCK)
+# if defined(SPLICE_F_MORE)
+ INT_CONSTANT(SPLICE_F_MORE),
+# endif // defined(SPLICE_F_MORE)
+# if defined(SPLICE_F_GIFT)
+ INT_CONSTANT(SPLICE_F_GIFT),
+# endif // defined(SPLICE_F_GIFT)
+#endif // defined(XP_UNIX)
+// copyfile
+#if defined(COPYFILE_DATA)
+ INT_CONSTANT(COPYFILE_DATA),
+ INT_CONSTANT(COPYFILE_EXCL),
+ INT_CONSTANT(COPYFILE_XATTR),
+ INT_CONSTANT(COPYFILE_STAT),
+ INT_CONSTANT(COPYFILE_ACL),
+ INT_CONSTANT(COPYFILE_MOVE),
+#endif // defined(COPYFILE_DATA)
+
+ // error values
+ INT_CONSTANT(EACCES),
+ INT_CONSTANT(EAGAIN),
+ INT_CONSTANT(EBADF),
+ INT_CONSTANT(EEXIST),
+ INT_CONSTANT(EFAULT),
+ INT_CONSTANT(EFBIG),
+ INT_CONSTANT(EINVAL),
+ INT_CONSTANT(EINTR),
+ INT_CONSTANT(EIO),
+ INT_CONSTANT(EISDIR),
+#if defined(ELOOP) // not defined with VC9
+ INT_CONSTANT(ELOOP),
+#endif // defined(ELOOP)
+ INT_CONSTANT(EMFILE),
+ INT_CONSTANT(ENAMETOOLONG),
+ INT_CONSTANT(ENFILE),
+ INT_CONSTANT(ENOENT),
+ INT_CONSTANT(ENOMEM),
+ INT_CONSTANT(ENOSPC),
+ INT_CONSTANT(ENOTDIR),
+ INT_CONSTANT(ENXIO),
+#if defined(EOPNOTSUPP) // not defined with VC 9
+ INT_CONSTANT(EOPNOTSUPP),
+#endif // defined(EOPNOTSUPP)
+#if defined(EOVERFLOW) // not defined with VC 9
+ INT_CONSTANT(EOVERFLOW),
+#endif // defined(EOVERFLOW)
+ INT_CONSTANT(EPERM),
+ INT_CONSTANT(ERANGE),
+ INT_CONSTANT(ENOSYS),
+#if defined(ETIMEDOUT) // not defined with VC 9
+ INT_CONSTANT(ETIMEDOUT),
+#endif // defined(ETIMEDOUT)
+#if defined(EWOULDBLOCK) // not defined with VC 9
+ INT_CONSTANT(EWOULDBLOCK),
+#endif // defined(EWOULDBLOCK)
+ INT_CONSTANT(EXDEV),
+
+#if defined(DT_UNKNOWN)
+ // Constants for |readdir|
+ INT_CONSTANT(DT_UNKNOWN),
+ INT_CONSTANT(DT_FIFO),
+ INT_CONSTANT(DT_CHR),
+ INT_CONSTANT(DT_DIR),
+ INT_CONSTANT(DT_BLK),
+ INT_CONSTANT(DT_REG),
+ INT_CONSTANT(DT_LNK),
+ INT_CONSTANT(DT_SOCK),
+#endif // defined(DT_UNKNOWN)
+
+#if defined(XP_UNIX)
+ // Constants for |stat|
+ INT_CONSTANT(S_IFMT),
+ INT_CONSTANT(S_IFIFO),
+ INT_CONSTANT(S_IFCHR),
+ INT_CONSTANT(S_IFDIR),
+ INT_CONSTANT(S_IFBLK),
+ INT_CONSTANT(S_IFREG),
+ INT_CONSTANT(S_IFLNK), // not defined on minGW
+ INT_CONSTANT(S_IFSOCK), // not defined on minGW
+#endif // defined(XP_UNIX)
+
+ INT_CONSTANT(PATH_MAX),
+
+#if defined(XP_LINUX)
+ // prctl options
+ INT_CONSTANT(PR_CAPBSET_READ),
+#endif
+
+// Constants used to define data structures
+//
+// Many data structures have different fields/sizes/etc. on
+// various OSes / versions of the same OS / platforms. For these
+// data structures, we need to compute and export from C the size
+// and, if necessary, the offset of fields, so as to be able to
+// define the structure in JS.
+
+#if defined(XP_UNIX)
+ // The size of |mode_t|.
+ {"OSFILE_SIZEOF_MODE_T", JS::Int32Value(sizeof(mode_t))},
+
+ // The size of |gid_t|.
+ {"OSFILE_SIZEOF_GID_T", JS::Int32Value(sizeof(gid_t))},
+
+ // The size of |uid_t|.
+ {"OSFILE_SIZEOF_UID_T", JS::Int32Value(sizeof(uid_t))},
+
+ // The size of |time_t|.
+ {"OSFILE_SIZEOF_TIME_T", JS::Int32Value(sizeof(time_t))},
+
+ // The size of |fsblkcnt_t|.
+ {"OSFILE_SIZEOF_FSBLKCNT_T", JS::Int32Value(sizeof(fsblkcnt_t))},
+
+# if !defined(ANDROID)
+ // The size of |posix_spawn_file_actions_t|.
+ {"OSFILE_SIZEOF_POSIX_SPAWN_FILE_ACTIONS_T",
+ JS::Int32Value(sizeof(posix_spawn_file_actions_t))},
+
+ // The size of |posix_spawnattr_t|.
+ {"OSFILE_SIZEOF_POSIX_SPAWNATTR_T",
+ JS::Int32Value(sizeof(posix_spawnattr_t))},
+# endif // !defined(ANDROID)
+
+ // Defining |dirent|.
+ // Size
+ {"OSFILE_SIZEOF_DIRENT", JS::Int32Value(sizeof(dirent))},
+
+ // Defining |flock|.
+ {"OSFILE_SIZEOF_FLOCK", JS::Int32Value(sizeof(struct flock))},
+ {"OSFILE_OFFSETOF_FLOCK_L_START",
+ JS::Int32Value(offsetof(struct flock, l_start))},
+ {"OSFILE_OFFSETOF_FLOCK_L_LEN",
+ JS::Int32Value(offsetof(struct flock, l_len))},
+ {"OSFILE_OFFSETOF_FLOCK_L_PID",
+ JS::Int32Value(offsetof(struct flock, l_pid))},
+ {"OSFILE_OFFSETOF_FLOCK_L_TYPE",
+ JS::Int32Value(offsetof(struct flock, l_type))},
+ {"OSFILE_OFFSETOF_FLOCK_L_WHENCE",
+ JS::Int32Value(offsetof(struct flock, l_whence))},
+
+ // Offset of field |d_name|.
+ {"OSFILE_OFFSETOF_DIRENT_D_NAME",
+ JS::Int32Value(offsetof(struct dirent, d_name))},
+ // An upper bound to the length of field |d_name| of struct |dirent|.
+ // (may not be exact, depending on padding).
+ {"OSFILE_SIZEOF_DIRENT_D_NAME",
+ JS::Int32Value(sizeof(struct dirent) - offsetof(struct dirent, d_name))},
+
+ // Defining |timeval|.
+ {"OSFILE_SIZEOF_TIMEVAL", JS::Int32Value(sizeof(struct timeval))},
+ {"OSFILE_OFFSETOF_TIMEVAL_TV_SEC",
+ JS::Int32Value(offsetof(struct timeval, tv_sec))},
+ {"OSFILE_OFFSETOF_TIMEVAL_TV_USEC",
+ JS::Int32Value(offsetof(struct timeval, tv_usec))},
+
+# if defined(DT_UNKNOWN)
+ // Position of field |d_type| in |dirent|
+ // Not strictly posix, but seems defined on all platforms
+ // except mingw32.
+ {"OSFILE_OFFSETOF_DIRENT_D_TYPE",
+ JS::Int32Value(offsetof(struct dirent, d_type))},
+# endif // defined(DT_UNKNOWN)
+
+// Under MacOS X and BSDs, |dirfd| is a macro rather than a
+// function, so we need a little help to get it to work
+# if defined(dirfd)
+ {"OSFILE_SIZEOF_DIR", JS::Int32Value(sizeof(DIR))},
+
+ {"OSFILE_OFFSETOF_DIR_DD_FD", JS::Int32Value(offsetof(DIR, __dd_fd))},
+# endif
+
+ // Defining |stat|
+
+ {"OSFILE_SIZEOF_STAT", JS::Int32Value(sizeof(struct stat))},
+
+ {"OSFILE_OFFSETOF_STAT_ST_MODE",
+ JS::Int32Value(offsetof(struct stat, st_mode))},
+ {"OSFILE_OFFSETOF_STAT_ST_UID",
+ JS::Int32Value(offsetof(struct stat, st_uid))},
+ {"OSFILE_OFFSETOF_STAT_ST_GID",
+ JS::Int32Value(offsetof(struct stat, st_gid))},
+ {"OSFILE_OFFSETOF_STAT_ST_SIZE",
+ JS::Int32Value(offsetof(struct stat, st_size))},
+
+# if defined(HAVE_ST_ATIMESPEC)
+ {"OSFILE_OFFSETOF_STAT_ST_ATIME",
+ JS::Int32Value(offsetof(struct stat, st_atimespec))},
+ {"OSFILE_OFFSETOF_STAT_ST_MTIME",
+ JS::Int32Value(offsetof(struct stat, st_mtimespec))},
+ {"OSFILE_OFFSETOF_STAT_ST_CTIME",
+ JS::Int32Value(offsetof(struct stat, st_ctimespec))},
+# else
+ {"OSFILE_OFFSETOF_STAT_ST_ATIME",
+ JS::Int32Value(offsetof(struct stat, st_atime))},
+ {"OSFILE_OFFSETOF_STAT_ST_MTIME",
+ JS::Int32Value(offsetof(struct stat, st_mtime))},
+ {"OSFILE_OFFSETOF_STAT_ST_CTIME",
+ JS::Int32Value(offsetof(struct stat, st_ctime))},
+# endif // defined(HAVE_ST_ATIME)
+
+// Several OSes have a birthtime field. For the moment, supporting only Darwin.
+# if defined(_DARWIN_FEATURE_64_BIT_INODE)
+ {"OSFILE_OFFSETOF_STAT_ST_BIRTHTIME",
+ JS::Int32Value(offsetof(struct stat, st_birthtime))},
+# endif // defined(_DARWIN_FEATURE_64_BIT_INODE)
+
+ // Defining |statvfs|
+
+ {"OSFILE_SIZEOF_STATVFS", JS::Int32Value(sizeof(struct statvfs))},
+
+ // We have no guarantee how big "f_frsize" is, so we have to calculate that.
+ {"OSFILE_SIZEOF_STATVFS_F_FRSIZE",
+ JS::Int32Value(DOM_SIZEOF_MEMBER(struct statvfs, f_frsize))},
+ {"OSFILE_OFFSETOF_STATVFS_F_FRSIZE",
+ JS::Int32Value(offsetof(struct statvfs, f_frsize))},
+ {"OSFILE_OFFSETOF_STATVFS_F_BAVAIL",
+ JS::Int32Value(offsetof(struct statvfs, f_bavail))},
+
+#endif // defined(XP_UNIX)
+
+// System configuration
+
+// Under MacOSX, to avoid using deprecated functions that do not
+// match the constants we define in this object (including
+// |sizeof|/|offsetof| stuff, but not only), for a number of
+// functions, we need to use functions with a $INODE64 suffix.
+// That is true on Intel-based mac when the _DARWIN_FEATURE_64_BIT_INODE
+// macro is set. But not on Apple Silicon.
+#if defined(_DARWIN_FEATURE_64_BIT_INODE) && !defined(__aarch64__)
+ {"_DARWIN_INODE64_SYMBOLS", JS::Int32Value(1)},
+#endif // defined(_DARWIN_FEATURE_64_BIT_INODE)
+
+// Similar feature for Linux
+#if defined(_STAT_VER)
+ INT_CONSTANT(_STAT_VER),
+#endif // defined(_STAT_VER)
+
+ PROP_END};
+
+#if defined(XP_WIN)
+/**
+ * The properties defined in windows.h.
+ *
+ * If you extend this list of properties, please
+ * separate categories ("errors", "open", etc.),
+ * keep properties organized by alphabetical order
+ * and #ifdef-away properties that are not portable.
+ */
+static const dom::ConstantSpec gWinProperties[] = {
+ // FormatMessage flags
+ INT_CONSTANT(FORMAT_MESSAGE_FROM_SYSTEM),
+ INT_CONSTANT(FORMAT_MESSAGE_IGNORE_INSERTS),
+
+ // The max length of paths
+ INT_CONSTANT(MAX_PATH),
+
+ // CreateFile desired access
+ INT_CONSTANT(GENERIC_ALL),
+ INT_CONSTANT(GENERIC_EXECUTE),
+ INT_CONSTANT(GENERIC_READ),
+ INT_CONSTANT(GENERIC_WRITE),
+
+ // CreateFile share mode
+ INT_CONSTANT(FILE_SHARE_DELETE),
+ INT_CONSTANT(FILE_SHARE_READ),
+ INT_CONSTANT(FILE_SHARE_WRITE),
+
+ // CreateFile creation disposition
+ INT_CONSTANT(CREATE_ALWAYS),
+ INT_CONSTANT(CREATE_NEW),
+ INT_CONSTANT(OPEN_ALWAYS),
+ INT_CONSTANT(OPEN_EXISTING),
+ INT_CONSTANT(TRUNCATE_EXISTING),
+
+ // CreateFile attributes
+ INT_CONSTANT(FILE_ATTRIBUTE_ARCHIVE),
+ INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
+ INT_CONSTANT(FILE_ATTRIBUTE_HIDDEN),
+ INT_CONSTANT(FILE_ATTRIBUTE_NORMAL),
+ INT_CONSTANT(FILE_ATTRIBUTE_READONLY),
+ INT_CONSTANT(FILE_ATTRIBUTE_REPARSE_POINT),
+ INT_CONSTANT(FILE_ATTRIBUTE_SYSTEM),
+ INT_CONSTANT(FILE_ATTRIBUTE_TEMPORARY),
+ INT_CONSTANT(FILE_FLAG_BACKUP_SEMANTICS),
+
+ // CreateFile error constant
+ {"INVALID_HANDLE_VALUE", JS::Int32Value(INT_PTR(INVALID_HANDLE_VALUE))},
+
+ // CreateFile flags
+ INT_CONSTANT(FILE_FLAG_DELETE_ON_CLOSE),
+
+ // SetFilePointer methods
+ INT_CONSTANT(FILE_BEGIN),
+ INT_CONSTANT(FILE_CURRENT),
+ INT_CONSTANT(FILE_END),
+
+ // SetFilePointer error constant
+ UINT_CONSTANT(INVALID_SET_FILE_POINTER),
+
+ // File attributes
+ INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
+
+ // MoveFile flags
+ INT_CONSTANT(MOVEFILE_COPY_ALLOWED),
+ INT_CONSTANT(MOVEFILE_REPLACE_EXISTING),
+
+ // GetFileAttributes error constant
+ INT_CONSTANT(INVALID_FILE_ATTRIBUTES),
+
+ // GetNamedSecurityInfo and SetNamedSecurityInfo constants
+ INT_CONSTANT(UNPROTECTED_DACL_SECURITY_INFORMATION),
+ INT_CONSTANT(SE_FILE_OBJECT),
+ INT_CONSTANT(DACL_SECURITY_INFORMATION),
+
+ // Errors
+ INT_CONSTANT(ERROR_INVALID_HANDLE),
+ INT_CONSTANT(ERROR_ACCESS_DENIED),
+ INT_CONSTANT(ERROR_DIR_NOT_EMPTY),
+ INT_CONSTANT(ERROR_FILE_EXISTS),
+ INT_CONSTANT(ERROR_ALREADY_EXISTS),
+ INT_CONSTANT(ERROR_FILE_NOT_FOUND),
+ INT_CONSTANT(ERROR_NO_MORE_FILES),
+ INT_CONSTANT(ERROR_PATH_NOT_FOUND),
+ INT_CONSTANT(ERROR_BAD_ARGUMENTS),
+ INT_CONSTANT(ERROR_SHARING_VIOLATION),
+ INT_CONSTANT(ERROR_NOT_SUPPORTED),
+
+ PROP_END};
+#endif // defined(XP_WIN)
+
+/**
+ * Get a field of an object as an object.
+ *
+ * If the field does not exist, create it. If it exists but is not an
+ * object, throw a JS error.
+ */
+JSObject* GetOrCreateObjectProperty(JSContext* cx,
+ JS::Handle<JSObject*> aObject,
+ const char* aProperty) {
+ JS::Rooted<JS::Value> val(cx);
+ if (!JS_GetProperty(cx, aObject, aProperty, &val)) {
+ return nullptr;
+ }
+ if (!val.isUndefined()) {
+ if (val.isObject()) {
+ return &val.toObject();
+ }
+
+ JS_ReportErrorNumberASCII(cx, js::GetErrorMessage, nullptr,
+ JSMSG_UNEXPECTED_TYPE, aProperty,
+ "not an object");
+ return nullptr;
+ }
+ return JS_DefineObject(cx, aObject, aProperty, nullptr, JSPROP_ENUMERATE);
+}
+
+/**
+ * Set a property of an object from a nsString.
+ *
+ * If the nsString is void (i.e. IsVoid is true), do nothing.
+ */
+bool SetStringProperty(JSContext* cx, JS::Handle<JSObject*> aObject,
+ const char* aProperty, const nsString aValue) {
+ if (aValue.IsVoid()) {
+ return true;
+ }
+ JSString* strValue = JS_NewUCStringCopyZ(cx, aValue.get());
+ NS_ENSURE_TRUE(strValue, false);
+ JS::Rooted<JS::Value> valValue(cx, JS::StringValue(strValue));
+ return JS_SetProperty(cx, aObject, aProperty, valValue);
+}
+
+/**
+ * Define OS-specific constants.
+ *
+ * This function creates or uses JS object |OS.Constants| to store
+ * all its constants.
+ */
+bool OSFileConstantsService::DefineOSFileConstants(
+ JSContext* aCx, JS::Handle<JSObject*> aGlobal) {
+ if (!mInitialized) {
+ JS_ReportErrorNumberASCII(aCx, js::GetErrorMessage, nullptr,
+ JSMSG_CANT_OPEN, "OSFileConstants",
+ "initialization has failed");
+ return false;
+ }
+
+ JS::Rooted<JSObject*> objOS(aCx);
+ if (!(objOS = GetOrCreateObjectProperty(aCx, aGlobal, "OS"))) {
+ return false;
+ }
+ JS::Rooted<JSObject*> objConstants(aCx);
+ if (!(objConstants = GetOrCreateObjectProperty(aCx, objOS, "Constants"))) {
+ return false;
+ }
+
+ // Build OS.Constants.libc
+
+ JS::Rooted<JSObject*> objLibc(aCx);
+ if (!(objLibc = GetOrCreateObjectProperty(aCx, objConstants, "libc"))) {
+ return false;
+ }
+ if (!dom::DefineConstants(aCx, objLibc, gLibcProperties)) {
+ return false;
+ }
+
+#if defined(XP_WIN)
+ // Build OS.Constants.Win
+
+ JS::Rooted<JSObject*> objWin(aCx);
+ if (!(objWin = GetOrCreateObjectProperty(aCx, objConstants, "Win"))) {
+ return false;
+ }
+ if (!dom::DefineConstants(aCx, objWin, gWinProperties)) {
+ return false;
+ }
+#endif // defined(XP_WIN)
+
+ // Build OS.Constants.Sys
+
+ JS::Rooted<JSObject*> objSys(aCx);
+ if (!(objSys = GetOrCreateObjectProperty(aCx, objConstants, "Sys"))) {
+ return false;
+ }
+
+ nsCOMPtr<nsIXULRuntime> runtime =
+ do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
+ if (runtime) {
+ nsAutoCString os;
+ DebugOnly<nsresult> rv = runtime->GetOS(os);
+ MOZ_ASSERT(NS_SUCCEEDED(rv));
+
+ JSString* strVersion = JS_NewStringCopyZ(aCx, os.get());
+ if (!strVersion) {
+ return false;
+ }
+
+ JS::Rooted<JS::Value> valVersion(aCx, JS::StringValue(strVersion));
+ if (!JS_SetProperty(aCx, objSys, "Name", valVersion)) {
+ return false;
+ }
+ }
+
+#if defined(DEBUG)
+ JS::Rooted<JS::Value> valDebug(aCx, JS::TrueValue());
+ if (!JS_SetProperty(aCx, objSys, "DEBUG", valDebug)) {
+ return false;
+ }
+#endif
+
+#if defined(HAVE_64BIT_BUILD)
+ JS::Rooted<JS::Value> valBits(aCx, JS::Int32Value(64));
+#else
+ JS::Rooted<JS::Value> valBits(aCx, JS::Int32Value(32));
+#endif // defined (HAVE_64BIT_BUILD)
+ if (!JS_SetProperty(aCx, objSys, "bits", valBits)) {
+ return false;
+ }
+
+ if (!JS_DefineProperty(
+ aCx, objSys, "umask", mUserUmask,
+ JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
+ return false;
+ }
+
+ // Build OS.Constants.Path
+
+ JS::Rooted<JSObject*> objPath(aCx);
+ if (!(objPath = GetOrCreateObjectProperty(aCx, objConstants, "Path"))) {
+ return false;
+ }
+
+ // Locate libxul
+ // Note that we don't actually provide the full path, only the name of the
+ // library, which is sufficient to link to the library using js-ctypes.
+
+#if defined(XP_MACOSX)
+ // Under MacOS X, for some reason, libxul is called simply "XUL",
+ // and we need to provide the full path.
+ nsAutoString libxul;
+ libxul.Append(mPaths->libDir);
+ libxul.AppendLiteral("/XUL");
+#else
+ // On other platforms, libxul is a library "xul" with regular
+ // library prefix/suffix.
+ nsAutoString libxul;
+ libxul.AppendLiteral(MOZ_DLL_PREFIX);
+ libxul.AppendLiteral("xul");
+ libxul.AppendLiteral(MOZ_DLL_SUFFIX);
+#endif // defined(XP_MACOSX)
+
+ if (!SetStringProperty(aCx, objPath, "libxul", libxul)) {
+ return false;
+ }
+
+ if (!SetStringProperty(aCx, objPath, "libDir", mPaths->libDir)) {
+ return false;
+ }
+
+ if (!SetStringProperty(aCx, objPath, "tmpDir", mPaths->tmpDir)) {
+ return false;
+ }
+
+ // Configure profileDir only if it is available at this stage
+ if (!mPaths->profileDir.IsVoid() &&
+ !SetStringProperty(aCx, objPath, "profileDir", mPaths->profileDir)) {
+ return false;
+ }
+
+ // Configure localProfileDir only if it is available at this stage
+ if (!mPaths->localProfileDir.IsVoid() &&
+ !SetStringProperty(aCx, objPath, "localProfileDir",
+ mPaths->localProfileDir)) {
+ return false;
+ }
+
+ return true;
+}
+
+NS_IMPL_ISUPPORTS(OSFileConstantsService, nsIOSFileConstantsService,
+ nsIObserver)
+
+/* static */
+already_AddRefed<OSFileConstantsService> OSFileConstantsService::GetOrCreate() {
+ if (!gInstance) {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ RefPtr<OSFileConstantsService> service = new OSFileConstantsService();
+ nsresult rv = service->InitOSFileConstants();
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return nullptr;
+ }
+
+ gInstance = std::move(service);
+ ClearOnShutdown(&gInstance);
+ }
+
+ RefPtr<OSFileConstantsService> copy = gInstance;
+ return copy.forget();
+}
+
+OSFileConstantsService::OSFileConstantsService()
+ : mInitialized(false), mUserUmask(0) {
+ MOZ_ASSERT(NS_IsMainThread());
+}
+
+OSFileConstantsService::~OSFileConstantsService() {
+ MOZ_ASSERT(NS_IsMainThread());
+}
+
+NS_IMETHODIMP
+OSFileConstantsService::Init(JSContext* aCx) {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsresult rv = InitOSFileConstants();
+ if (NS_FAILED(rv)) {
+ return rv;
+ }
+
+ mozJSModuleLoader* loader = mozJSModuleLoader::Get();
+ JS::Rooted<JSObject*> targetObj(aCx);
+ loader->FindTargetObject(aCx, &targetObj);
+
+ if (!DefineOSFileConstants(aCx, targetObj)) {
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+} // namespace mozilla