/* -*- 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 # include # 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 # endif // !defined(ANDROID) #endif // defined(XP_UNIX) #if defined(XP_LINUX) # include #endif // defined(XP_LINUX) #if defined(XP_MACOSX) # include "copyfile.h" #endif // defined(XP_MACOSX) #if defined(XP_WIN) # include # include # 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 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 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(new Paths); // Initialize paths->libDir nsCOMPtr file; nsresult rv = NS_GetSpecialDirectory(NS_XPCOM_LIBRARY_FILE, getter_AddRefs(file)); if (NS_FAILED(rv)) { return rv; } nsCOMPtr 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 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 aObject, const char* aProperty) { JS::Rooted 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 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 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 aGlobal) { if (!mInitialized) { JS_ReportErrorNumberASCII(aCx, js::GetErrorMessage, nullptr, JSMSG_CANT_OPEN, "OSFileConstants", "initialization has failed"); return false; } JS::Rooted objOS(aCx); if (!(objOS = GetOrCreateObjectProperty(aCx, aGlobal, "OS"))) { return false; } JS::Rooted objConstants(aCx); if (!(objConstants = GetOrCreateObjectProperty(aCx, objOS, "Constants"))) { return false; } // Build OS.Constants.libc JS::Rooted 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 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 objSys(aCx); if (!(objSys = GetOrCreateObjectProperty(aCx, objConstants, "Sys"))) { return false; } nsCOMPtr runtime = do_GetService(XULRUNTIME_SERVICE_CONTRACTID); if (runtime) { nsAutoCString os; DebugOnly rv = runtime->GetOS(os); MOZ_ASSERT(NS_SUCCEEDED(rv)); JSString* strVersion = JS_NewStringCopyZ(aCx, os.get()); if (!strVersion) { return false; } JS::Rooted valVersion(aCx, JS::StringValue(strVersion)); if (!JS_SetProperty(aCx, objSys, "Name", valVersion)) { return false; } } #if defined(DEBUG) JS::Rooted valDebug(aCx, JS::TrueValue()); if (!JS_SetProperty(aCx, objSys, "DEBUG", valDebug)) { return false; } #endif #if defined(HAVE_64BIT_BUILD) JS::Rooted valBits(aCx, JS::Int32Value(64)); #else JS::Rooted 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 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::GetOrCreate() { if (!gInstance) { MOZ_ASSERT(NS_IsMainThread()); RefPtr service = new OSFileConstantsService(); nsresult rv = service->InitOSFileConstants(); if (NS_WARN_IF(NS_FAILED(rv))) { return nullptr; } gInstance = std::move(service); ClearOnShutdown(&gInstance); } RefPtr 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 targetObj(aCx); loader->FindTargetObject(aCx, &targetObj); if (!DefineOSFileConstants(aCx, targetObj)) { return NS_ERROR_FAILURE; } return NS_OK; } } // namespace mozilla