Bumping manifests a=b2g-bump
[gecko.git] / dom / system / OSFileConstants.cpp
blob1f5756d0232d28f2fbf4cd8f9878fb45aab79ef6
1 /* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
5 #include "mozilla/DebugOnly.h"
7 #include "fcntl.h"
8 #include "errno.h"
10 #include "prsystem.h"
12 #if defined(XP_UNIX)
13 #include "unistd.h"
14 #include "dirent.h"
15 #include "sys/stat.h"
16 #if defined(ANDROID)
17 #include <sys/vfs.h>
18 #define statvfs statfs
19 #else
20 #include "sys/statvfs.h"
21 #include <spawn.h>
22 #endif // defined(ANDROID)
23 #endif // defined(XP_UNIX)
25 #if defined(XP_LINUX)
26 #include <linux/fadvise.h>
27 #endif // defined(XP_LINUX)
29 #if defined(XP_MACOSX)
30 #include "copyfile.h"
31 #endif // defined(XP_MACOSX)
33 #if defined(XP_WIN)
34 #include <windows.h>
35 #include <accctrl.h>
37 #define PATH_MAX MAX_PATH
39 #endif // defined(XP_WIN)
41 #include "jsapi.h"
42 #include "jsfriendapi.h"
43 #include "BindingUtils.h"
45 // Used to provide information on the OS
47 #include "nsThreadUtils.h"
48 #include "nsIObserverService.h"
49 #include "nsIObserver.h"
50 #include "nsDirectoryServiceUtils.h"
51 #include "nsIXULRuntime.h"
52 #include "nsIPropertyBag2.h"
53 #include "nsXPCOMCIDInternal.h"
54 #include "nsServiceManagerUtils.h"
55 #include "nsString.h"
56 #include "nsAutoPtr.h"
57 #include "nsDirectoryServiceDefs.h"
58 #include "nsXULAppAPI.h"
59 #include "nsAppDirectoryServiceDefs.h"
60 #include "mozJSComponentLoader.h"
62 #include "OSFileConstants.h"
63 #include "nsIOSFileConstantsService.h"
64 #include "nsZipArchive.h"
66 #if defined(__DragonFly__) || defined(__FreeBSD__) \
67 || defined(__NetBSD__) || defined(__OpenBSD__)
68 #define __dd_fd dd_fd
69 #endif
71 /**
72 * This module defines the basic libc constants (error numbers, open modes,
73 * etc.) used by OS.File and possibly other OS-bound JavaScript libraries.
77 namespace mozilla {
79 // Use an anonymous namespace to hide the symbols and avoid any collision
80 // with, for instance, |extern bool gInitialized;|
81 namespace {
82 /**
83 * |true| if this module has been initialized, |false| otherwise
85 bool gInitialized = false;
87 struct Paths {
88 /**
89 * The name of the directory holding all the libraries (libxpcom, libnss, etc.)
91 nsString libDir;
92 nsString tmpDir;
93 nsString profileDir;
94 nsString localProfileDir;
95 /**
96 * The user's home directory
98 nsString homeDir;
99 /**
100 * The user's desktop directory, if there is one. Otherwise this is
101 * the same as homeDir.
103 nsString desktopDir;
105 * The user's 'application data' directory.
106 * Windows:
107 * HOME = Documents and Settings\$USER\Application Data
108 * UAppData = $HOME[\$vendor]\$name
110 * Unix:
111 * HOME = ~
112 * UAppData = $HOME/.[$vendor/]$name
114 * Mac:
115 * HOME = ~
116 * UAppData = $HOME/Library/Application Support/$name
118 nsString userApplicationDataDir;
120 #if defined(XP_WIN)
122 * The user's application data directory.
124 nsString winAppDataDir;
126 * The programs subdirectory in the user's start menu directory.
128 nsString winStartMenuProgsDir;
129 #endif // defined(XP_WIN)
131 #if defined(XP_MACOSX)
133 * The user's Library directory.
135 nsString macUserLibDir;
137 * The Application directory, that stores applications installed in the
138 * system.
140 nsString macLocalApplicationsDir;
142 * The user's trash directory.
144 nsString macTrashDir;
145 #endif // defined(XP_MACOSX)
147 Paths()
149 libDir.SetIsVoid(true);
150 tmpDir.SetIsVoid(true);
151 profileDir.SetIsVoid(true);
152 localProfileDir.SetIsVoid(true);
153 homeDir.SetIsVoid(true);
154 desktopDir.SetIsVoid(true);
155 userApplicationDataDir.SetIsVoid(true);
157 #if defined(XP_WIN)
158 winAppDataDir.SetIsVoid(true);
159 winStartMenuProgsDir.SetIsVoid(true);
160 #endif // defined(XP_WIN)
162 #if defined(XP_MACOSX)
163 macUserLibDir.SetIsVoid(true);
164 macLocalApplicationsDir.SetIsVoid(true);
165 macTrashDir.SetIsVoid(true);
166 #endif // defined(XP_MACOSX)
171 * System directories.
173 Paths* gPaths = nullptr;
176 * (Unix) the umask, which goes in OS.Constants.Sys but
177 * can only be looked up (via the system-info service)
178 * on the main thread.
180 uint32_t gUserUmask = 0;
184 * Return the path to one of the special directories.
186 * @param aKey The key to the special directory (e.g. "TmpD", "ProfD", ...)
187 * @param aOutPath The path to the special directory. In case of error,
188 * the string is set to void.
190 nsresult GetPathToSpecialDir(const char *aKey, nsString& aOutPath)
192 nsCOMPtr<nsIFile> file;
193 nsresult rv = NS_GetSpecialDirectory(aKey, getter_AddRefs(file));
194 if (NS_FAILED(rv) || !file) {
195 return rv;
198 return file->GetPath(aOutPath);
202 * In some cases, OSFileConstants may be instantiated before the
203 * profile is setup. In such cases, |OS.Constants.Path.profileDir| and
204 * |OS.Constants.Path.localProfileDir| are undefined. However, we want
205 * to ensure that this does not break existing code, so that future
206 * workers spawned after the profile is setup have these constants.
208 * For this purpose, we register an observer to set |gPaths->profileDir|
209 * and |gPaths->localProfileDir| once the profile is setup.
211 class DelayedPathSetter MOZ_FINAL: public nsIObserver
213 ~DelayedPathSetter() {}
215 NS_DECL_ISUPPORTS
216 NS_DECL_NSIOBSERVER
218 DelayedPathSetter() {}
221 NS_IMPL_ISUPPORTS(DelayedPathSetter, nsIObserver)
223 NS_IMETHODIMP
224 DelayedPathSetter::Observe(nsISupports*, const char * aTopic, const char16_t*)
226 if (gPaths == nullptr) {
227 // Initialization of gPaths has not taken place, something is wrong,
228 // don't make things worse.
229 return NS_OK;
231 nsresult rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_50_DIR, gPaths->profileDir);
232 if (NS_FAILED(rv)) {
233 return rv;
235 rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_LOCAL_50_DIR, gPaths->localProfileDir);
236 if (NS_FAILED(rv)) {
237 return rv;
240 return NS_OK;
244 * Perform the part of initialization that can only be
245 * executed on the main thread.
247 nsresult InitOSFileConstants()
249 MOZ_ASSERT(NS_IsMainThread());
250 if (gInitialized) {
251 return NS_OK;
254 gInitialized = true;
256 nsAutoPtr<Paths> paths(new Paths);
258 // Initialize paths->libDir
259 nsCOMPtr<nsIFile> file;
260 nsresult rv = NS_GetSpecialDirectory(NS_XPCOM_LIBRARY_FILE, getter_AddRefs(file));
261 if (NS_FAILED(rv)) {
262 return rv;
265 nsCOMPtr<nsIFile> libDir;
266 rv = file->GetParent(getter_AddRefs(libDir));
267 if (NS_FAILED(rv)) {
268 return rv;
271 rv = libDir->GetPath(paths->libDir);
272 if (NS_FAILED(rv)) {
273 return rv;
276 // Setup profileDir and localProfileDir immediately if possible (we
277 // assume that NS_APP_USER_PROFILE_50_DIR and
278 // NS_APP_USER_PROFILE_LOCAL_50_DIR are set simultaneously)
279 rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_50_DIR, paths->profileDir);
280 if (NS_SUCCEEDED(rv)) {
281 rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_LOCAL_50_DIR, paths->localProfileDir);
284 // Otherwise, delay setup of profileDir/localProfileDir until they
285 // become available.
286 if (NS_FAILED(rv)) {
287 nsCOMPtr<nsIObserverService> obsService = do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
288 if (NS_FAILED(rv)) {
289 return rv;
291 nsRefPtr<DelayedPathSetter> pathSetter = new DelayedPathSetter();
292 rv = obsService->AddObserver(pathSetter, "profile-do-change", false);
293 if (NS_FAILED(rv)) {
294 return rv;
298 // For other directories, ignore errors (they may be undefined on
299 // some platforms or in non-Firefox embeddings of Gecko).
301 GetPathToSpecialDir(NS_OS_TEMP_DIR, paths->tmpDir);
302 GetPathToSpecialDir(NS_OS_HOME_DIR, paths->homeDir);
303 GetPathToSpecialDir(NS_OS_DESKTOP_DIR, paths->desktopDir);
304 GetPathToSpecialDir(XRE_USER_APP_DATA_DIR, paths->userApplicationDataDir);
306 #if defined(XP_WIN)
307 GetPathToSpecialDir(NS_WIN_APPDATA_DIR, paths->winAppDataDir);
308 GetPathToSpecialDir(NS_WIN_PROGRAMS_DIR, paths->winStartMenuProgsDir);
309 #endif // defined(XP_WIN)
311 #if defined(XP_MACOSX)
312 GetPathToSpecialDir(NS_MAC_USER_LIB_DIR, paths->macUserLibDir);
313 GetPathToSpecialDir(NS_OSX_LOCAL_APPLICATIONS_DIR, paths->macLocalApplicationsDir);
314 GetPathToSpecialDir(NS_MAC_TRASH_DIR, paths->macTrashDir);
315 #endif // defined(XP_MACOSX)
317 gPaths = paths.forget();
319 // Get the umask from the system-info service.
320 // The property will always be present, but it will be zero on
321 // non-Unix systems.
322 nsCOMPtr<nsIPropertyBag2> infoService =
323 do_GetService("@mozilla.org/system-info;1");
324 MOZ_ASSERT(infoService, "Could not access the system information service");
325 rv = infoService->GetPropertyAsUint32(NS_LITERAL_STRING("umask"),
326 &gUserUmask);
327 if (NS_FAILED(rv)) {
328 return rv;
331 return NS_OK;
335 * Perform the cleaning up that can only be executed on the main thread.
337 void CleanupOSFileConstants()
339 MOZ_ASSERT(NS_IsMainThread());
340 if (!gInitialized) {
341 return;
344 gInitialized = false;
345 delete gPaths;
350 * Define a simple read-only property holding an integer.
352 * @param name The name of the constant. Used both as the JS name for the
353 * constant and to access its value. Must be defined.
355 * Produces a |ConstantSpec|.
357 #define INT_CONSTANT(name) \
358 { #name, INT_TO_JSVAL(name) }
361 * Define a simple read-only property holding an unsigned integer.
363 * @param name The name of the constant. Used both as the JS name for the
364 * constant and to access its value. Must be defined.
366 * Produces a |ConstantSpec|.
368 #define UINT_CONSTANT(name) \
369 { #name, UINT_TO_JSVAL((name)) }
372 * End marker for ConstantSpec
374 #define PROP_END { nullptr, JS::UndefinedValue() }
377 // Define missing constants for Android
378 #if !defined(S_IRGRP)
379 #define S_IXOTH 0001
380 #define S_IWOTH 0002
381 #define S_IROTH 0004
382 #define S_IRWXO 0007
383 #define S_IXGRP 0010
384 #define S_IWGRP 0020
385 #define S_IRGRP 0040
386 #define S_IRWXG 0070
387 #define S_IXUSR 0100
388 #define S_IWUSR 0200
389 #define S_IRUSR 0400
390 #define S_IRWXU 0700
391 #endif // !defined(S_IRGRP)
394 * The properties defined in libc.
396 * If you extend this list of properties, please
397 * separate categories ("errors", "open", etc.),
398 * keep properties organized by alphabetical order
399 * and #ifdef-away properties that are not portable.
401 static const dom::ConstantSpec gLibcProperties[] =
403 // Arguments for open
404 INT_CONSTANT(O_APPEND),
405 INT_CONSTANT(O_CREAT),
406 #if defined(O_DIRECTORY)
407 INT_CONSTANT(O_DIRECTORY),
408 #endif // defined(O_DIRECTORY)
409 #if defined(O_EVTONLY)
410 INT_CONSTANT(O_EVTONLY),
411 #endif // defined(O_EVTONLY)
412 INT_CONSTANT(O_EXCL),
413 #if defined(O_EXLOCK)
414 INT_CONSTANT(O_EXLOCK),
415 #endif // defined(O_EXLOCK)
416 #if defined(O_LARGEFILE)
417 INT_CONSTANT(O_LARGEFILE),
418 #endif // defined(O_LARGEFILE)
419 #if defined(O_NOFOLLOW)
420 INT_CONSTANT(O_NOFOLLOW),
421 #endif // defined(O_NOFOLLOW)
422 #if defined(O_NONBLOCK)
423 INT_CONSTANT(O_NONBLOCK),
424 #endif // defined(O_NONBLOCK)
425 INT_CONSTANT(O_RDONLY),
426 INT_CONSTANT(O_RDWR),
427 #if defined(O_RSYNC)
428 INT_CONSTANT(O_RSYNC),
429 #endif // defined(O_RSYNC)
430 #if defined(O_SHLOCK)
431 INT_CONSTANT(O_SHLOCK),
432 #endif // defined(O_SHLOCK)
433 #if defined(O_SYMLINK)
434 INT_CONSTANT(O_SYMLINK),
435 #endif // defined(O_SYMLINK)
436 #if defined(O_SYNC)
437 INT_CONSTANT(O_SYNC),
438 #endif // defined(O_SYNC)
439 INT_CONSTANT(O_TRUNC),
440 INT_CONSTANT(O_WRONLY),
442 #if defined(AT_EACCESS)
443 INT_CONSTANT(AT_EACCESS),
444 #endif //defined(AT_EACCESS)
445 #if defined(AT_FDCWD)
446 INT_CONSTANT(AT_FDCWD),
447 #endif //defined(AT_FDCWD)
448 #if defined(AT_SYMLINK_NOFOLLOW)
449 INT_CONSTANT(AT_SYMLINK_NOFOLLOW),
450 #endif //defined(AT_SYMLINK_NOFOLLOW)
452 #if defined(POSIX_FADV_SEQUENTIAL)
453 INT_CONSTANT(POSIX_FADV_SEQUENTIAL),
454 #endif //defined(POSIX_FADV_SEQUENTIAL)
456 // access
457 #if defined(F_OK)
458 INT_CONSTANT(F_OK),
459 INT_CONSTANT(R_OK),
460 INT_CONSTANT(W_OK),
461 INT_CONSTANT(X_OK),
462 #endif // defined(F_OK)
464 // modes
465 INT_CONSTANT(S_IRGRP),
466 INT_CONSTANT(S_IROTH),
467 INT_CONSTANT(S_IRUSR),
468 INT_CONSTANT(S_IRWXG),
469 INT_CONSTANT(S_IRWXO),
470 INT_CONSTANT(S_IRWXU),
471 INT_CONSTANT(S_IWGRP),
472 INT_CONSTANT(S_IWOTH),
473 INT_CONSTANT(S_IWUSR),
474 INT_CONSTANT(S_IXOTH),
475 INT_CONSTANT(S_IXGRP),
476 INT_CONSTANT(S_IXUSR),
478 // seek
479 INT_CONSTANT(SEEK_CUR),
480 INT_CONSTANT(SEEK_END),
481 INT_CONSTANT(SEEK_SET),
483 // fcntl command values
484 #if defined(XP_UNIX)
485 INT_CONSTANT(F_GETLK),
486 INT_CONSTANT(F_SETLK),
487 INT_CONSTANT(F_SETLKW),
489 // flock type values
490 INT_CONSTANT(F_RDLCK),
491 INT_CONSTANT(F_WRLCK),
492 INT_CONSTANT(F_UNLCK),
493 #endif // defined(XP_UNIX)
494 // copyfile
495 #if defined(COPYFILE_DATA)
496 INT_CONSTANT(COPYFILE_DATA),
497 INT_CONSTANT(COPYFILE_EXCL),
498 INT_CONSTANT(COPYFILE_XATTR),
499 INT_CONSTANT(COPYFILE_STAT),
500 INT_CONSTANT(COPYFILE_ACL),
501 INT_CONSTANT(COPYFILE_MOVE),
502 #endif // defined(COPYFILE_DATA)
504 // error values
505 INT_CONSTANT(EACCES),
506 INT_CONSTANT(EAGAIN),
507 INT_CONSTANT(EBADF),
508 INT_CONSTANT(EEXIST),
509 INT_CONSTANT(EFAULT),
510 INT_CONSTANT(EFBIG),
511 INT_CONSTANT(EINVAL),
512 INT_CONSTANT(EIO),
513 INT_CONSTANT(EISDIR),
514 #if defined(ELOOP) // not defined with VC9
515 INT_CONSTANT(ELOOP),
516 #endif // defined(ELOOP)
517 INT_CONSTANT(EMFILE),
518 INT_CONSTANT(ENAMETOOLONG),
519 INT_CONSTANT(ENFILE),
520 INT_CONSTANT(ENOENT),
521 INT_CONSTANT(ENOMEM),
522 INT_CONSTANT(ENOSPC),
523 INT_CONSTANT(ENOTDIR),
524 INT_CONSTANT(ENXIO),
525 #if defined(EOPNOTSUPP) // not defined with VC 9
526 INT_CONSTANT(EOPNOTSUPP),
527 #endif // defined(EOPNOTSUPP)
528 #if defined(EOVERFLOW) // not defined with VC 9
529 INT_CONSTANT(EOVERFLOW),
530 #endif // defined(EOVERFLOW)
531 INT_CONSTANT(EPERM),
532 INT_CONSTANT(ERANGE),
533 #if defined(ETIMEDOUT) // not defined with VC 9
534 INT_CONSTANT(ETIMEDOUT),
535 #endif // defined(ETIMEDOUT)
536 #if defined(EWOULDBLOCK) // not defined with VC 9
537 INT_CONSTANT(EWOULDBLOCK),
538 #endif // defined(EWOULDBLOCK)
539 INT_CONSTANT(EXDEV),
541 #if defined(DT_UNKNOWN)
542 // Constants for |readdir|
543 INT_CONSTANT(DT_UNKNOWN),
544 INT_CONSTANT(DT_FIFO),
545 INT_CONSTANT(DT_CHR),
546 INT_CONSTANT(DT_DIR),
547 INT_CONSTANT(DT_BLK),
548 INT_CONSTANT(DT_REG),
549 INT_CONSTANT(DT_LNK),
550 INT_CONSTANT(DT_SOCK),
551 #endif // defined(DT_UNKNOWN)
553 #if defined(S_IFIFO)
554 // Constants for |stat|
555 INT_CONSTANT(S_IFMT),
556 INT_CONSTANT(S_IFIFO),
557 INT_CONSTANT(S_IFCHR),
558 INT_CONSTANT(S_IFDIR),
559 INT_CONSTANT(S_IFBLK),
560 INT_CONSTANT(S_IFREG),
561 INT_CONSTANT(S_IFLNK),
562 INT_CONSTANT(S_IFSOCK),
563 #endif // defined(S_IFIFO)
565 INT_CONSTANT(PATH_MAX),
567 // Constants used to define data structures
569 // Many data structures have different fields/sizes/etc. on
570 // various OSes / versions of the same OS / platforms. For these
571 // data structures, we need to compute and export from C the size
572 // and, if necessary, the offset of fields, so as to be able to
573 // define the structure in JS.
575 #if defined(XP_UNIX)
576 // The size of |mode_t|.
577 { "OSFILE_SIZEOF_MODE_T", INT_TO_JSVAL(sizeof (mode_t)) },
579 // The size of |gid_t|.
580 { "OSFILE_SIZEOF_GID_T", INT_TO_JSVAL(sizeof (gid_t)) },
582 // The size of |uid_t|.
583 { "OSFILE_SIZEOF_UID_T", INT_TO_JSVAL(sizeof (uid_t)) },
585 // The size of |time_t|.
586 { "OSFILE_SIZEOF_TIME_T", INT_TO_JSVAL(sizeof (time_t)) },
588 // The size of |fsblkcnt_t|.
589 { "OSFILE_SIZEOF_FSBLKCNT_T", INT_TO_JSVAL(sizeof (fsblkcnt_t)) },
591 #if !defined(ANDROID)
592 // The size of |posix_spawn_file_actions_t|.
593 { "OSFILE_SIZEOF_POSIX_SPAWN_FILE_ACTIONS_T", INT_TO_JSVAL(sizeof (posix_spawn_file_actions_t)) },
594 #endif // !defined(ANDROID)
596 // Defining |dirent|.
597 // Size
598 { "OSFILE_SIZEOF_DIRENT", INT_TO_JSVAL(sizeof (dirent)) },
600 // Defining |flock|.
601 #if defined(XP_UNIX)
602 { "OSFILE_SIZEOF_FLOCK", INT_TO_JSVAL(sizeof (struct flock)) },
603 { "OSFILE_OFFSETOF_FLOCK_L_START", INT_TO_JSVAL(offsetof (struct flock, l_start)) },
604 { "OSFILE_OFFSETOF_FLOCK_L_LEN", INT_TO_JSVAL(offsetof (struct flock, l_len)) },
605 { "OSFILE_OFFSETOF_FLOCK_L_PID", INT_TO_JSVAL(offsetof (struct flock, l_pid)) },
606 { "OSFILE_OFFSETOF_FLOCK_L_TYPE", INT_TO_JSVAL(offsetof (struct flock, l_type)) },
607 { "OSFILE_OFFSETOF_FLOCK_L_WHENCE", INT_TO_JSVAL(offsetof (struct flock, l_whence)) },
608 #endif // defined(XP_UNIX)
609 // Offset of field |d_name|.
610 { "OSFILE_OFFSETOF_DIRENT_D_NAME", INT_TO_JSVAL(offsetof (struct dirent, d_name)) },
611 // An upper bound to the length of field |d_name| of struct |dirent|.
612 // (may not be exact, depending on padding).
613 { "OSFILE_SIZEOF_DIRENT_D_NAME", INT_TO_JSVAL(sizeof (struct dirent) - offsetof (struct dirent, d_name)) },
615 // Defining |timeval|.
616 { "OSFILE_SIZEOF_TIMEVAL", INT_TO_JSVAL(sizeof (struct timeval)) },
617 { "OSFILE_OFFSETOF_TIMEVAL_TV_SEC", INT_TO_JSVAL(offsetof (struct timeval, tv_sec)) },
618 { "OSFILE_OFFSETOF_TIMEVAL_TV_USEC", INT_TO_JSVAL(offsetof (struct timeval, tv_usec)) },
620 #if defined(DT_UNKNOWN)
621 // Position of field |d_type| in |dirent|
622 // Not strictly posix, but seems defined on all platforms
623 // except mingw32.
624 { "OSFILE_OFFSETOF_DIRENT_D_TYPE", INT_TO_JSVAL(offsetof (struct dirent, d_type)) },
625 #endif // defined(DT_UNKNOWN)
627 // Under MacOS X and BSDs, |dirfd| is a macro rather than a
628 // function, so we need a little help to get it to work
629 #if defined(dirfd)
630 { "OSFILE_SIZEOF_DIR", INT_TO_JSVAL(sizeof (DIR)) },
632 { "OSFILE_OFFSETOF_DIR_DD_FD", INT_TO_JSVAL(offsetof (DIR, __dd_fd)) },
633 #endif
635 // Defining |stat|
637 { "OSFILE_SIZEOF_STAT", INT_TO_JSVAL(sizeof (struct stat)) },
639 { "OSFILE_OFFSETOF_STAT_ST_MODE", INT_TO_JSVAL(offsetof (struct stat, st_mode)) },
640 { "OSFILE_OFFSETOF_STAT_ST_UID", INT_TO_JSVAL(offsetof (struct stat, st_uid)) },
641 { "OSFILE_OFFSETOF_STAT_ST_GID", INT_TO_JSVAL(offsetof (struct stat, st_gid)) },
642 { "OSFILE_OFFSETOF_STAT_ST_SIZE", INT_TO_JSVAL(offsetof (struct stat, st_size)) },
644 #if defined(HAVE_ST_ATIMESPEC)
645 { "OSFILE_OFFSETOF_STAT_ST_ATIME", INT_TO_JSVAL(offsetof (struct stat, st_atimespec)) },
646 { "OSFILE_OFFSETOF_STAT_ST_MTIME", INT_TO_JSVAL(offsetof (struct stat, st_mtimespec)) },
647 { "OSFILE_OFFSETOF_STAT_ST_CTIME", INT_TO_JSVAL(offsetof (struct stat, st_ctimespec)) },
648 #else
649 { "OSFILE_OFFSETOF_STAT_ST_ATIME", INT_TO_JSVAL(offsetof (struct stat, st_atime)) },
650 { "OSFILE_OFFSETOF_STAT_ST_MTIME", INT_TO_JSVAL(offsetof (struct stat, st_mtime)) },
651 { "OSFILE_OFFSETOF_STAT_ST_CTIME", INT_TO_JSVAL(offsetof (struct stat, st_ctime)) },
652 #endif // defined(HAVE_ST_ATIME)
654 // Several OSes have a birthtime field. For the moment, supporting only Darwin.
655 #if defined(_DARWIN_FEATURE_64_BIT_INODE)
656 { "OSFILE_OFFSETOF_STAT_ST_BIRTHTIME", INT_TO_JSVAL(offsetof (struct stat, st_birthtime)) },
657 #endif // defined(_DARWIN_FEATURE_64_BIT_INODE)
659 // Defining |statvfs|
661 { "OSFILE_SIZEOF_STATVFS", INT_TO_JSVAL(sizeof (struct statvfs)) },
663 { "OSFILE_OFFSETOF_STATVFS_F_BSIZE", INT_TO_JSVAL(offsetof (struct statvfs, f_bsize)) },
664 { "OSFILE_OFFSETOF_STATVFS_F_BAVAIL", INT_TO_JSVAL(offsetof (struct statvfs, f_bavail)) },
666 #endif // defined(XP_UNIX)
670 // System configuration
672 // Under MacOSX, to avoid using deprecated functions that do not
673 // match the constants we define in this object (including
674 // |sizeof|/|offsetof| stuff, but not only), for a number of
675 // functions, we need to adapt the name of the symbols we are using,
676 // whenever macro _DARWIN_FEATURE_64_BIT_INODE is set. We export
677 // this value to be able to do so from JavaScript.
678 #if defined(_DARWIN_FEATURE_64_BIT_INODE)
679 { "_DARWIN_FEATURE_64_BIT_INODE", INT_TO_JSVAL(1) },
680 #endif // defined(_DARWIN_FEATURE_64_BIT_INODE)
682 // Similar feature for Linux
683 #if defined(_STAT_VER)
684 INT_CONSTANT(_STAT_VER),
685 #endif // defined(_STAT_VER)
687 PROP_END
691 #if defined(XP_WIN)
693 * The properties defined in windows.h.
695 * If you extend this list of properties, please
696 * separate categories ("errors", "open", etc.),
697 * keep properties organized by alphabetical order
698 * and #ifdef-away properties that are not portable.
700 static const dom::ConstantSpec gWinProperties[] =
702 // FormatMessage flags
703 INT_CONSTANT(FORMAT_MESSAGE_FROM_SYSTEM),
704 INT_CONSTANT(FORMAT_MESSAGE_IGNORE_INSERTS),
706 // The max length of paths
707 INT_CONSTANT(MAX_PATH),
709 // CreateFile desired access
710 INT_CONSTANT(GENERIC_ALL),
711 INT_CONSTANT(GENERIC_EXECUTE),
712 INT_CONSTANT(GENERIC_READ),
713 INT_CONSTANT(GENERIC_WRITE),
715 // CreateFile share mode
716 INT_CONSTANT(FILE_SHARE_DELETE),
717 INT_CONSTANT(FILE_SHARE_READ),
718 INT_CONSTANT(FILE_SHARE_WRITE),
720 // CreateFile creation disposition
721 INT_CONSTANT(CREATE_ALWAYS),
722 INT_CONSTANT(CREATE_NEW),
723 INT_CONSTANT(OPEN_ALWAYS),
724 INT_CONSTANT(OPEN_EXISTING),
725 INT_CONSTANT(TRUNCATE_EXISTING),
727 // CreateFile attributes
728 INT_CONSTANT(FILE_ATTRIBUTE_ARCHIVE),
729 INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
730 INT_CONSTANT(FILE_ATTRIBUTE_NORMAL),
731 INT_CONSTANT(FILE_ATTRIBUTE_READONLY),
732 INT_CONSTANT(FILE_ATTRIBUTE_REPARSE_POINT),
733 INT_CONSTANT(FILE_ATTRIBUTE_TEMPORARY),
734 INT_CONSTANT(FILE_FLAG_BACKUP_SEMANTICS),
736 // CreateFile error constant
737 { "INVALID_HANDLE_VALUE", INT_TO_JSVAL(INT_PTR(INVALID_HANDLE_VALUE)) },
740 // CreateFile flags
741 INT_CONSTANT(FILE_FLAG_DELETE_ON_CLOSE),
743 // SetFilePointer methods
744 INT_CONSTANT(FILE_BEGIN),
745 INT_CONSTANT(FILE_CURRENT),
746 INT_CONSTANT(FILE_END),
748 // SetFilePointer error constant
749 UINT_CONSTANT(INVALID_SET_FILE_POINTER),
751 // File attributes
752 INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
755 // MoveFile flags
756 INT_CONSTANT(MOVEFILE_COPY_ALLOWED),
757 INT_CONSTANT(MOVEFILE_REPLACE_EXISTING),
759 // GetFileAttributes error constant
760 INT_CONSTANT(INVALID_FILE_ATTRIBUTES),
762 // GetNamedSecurityInfo and SetNamedSecurityInfo constants
763 INT_CONSTANT(UNPROTECTED_DACL_SECURITY_INFORMATION),
764 INT_CONSTANT(SE_FILE_OBJECT),
765 INT_CONSTANT(DACL_SECURITY_INFORMATION),
767 // Errors
768 INT_CONSTANT(ERROR_INVALID_HANDLE),
769 INT_CONSTANT(ERROR_ACCESS_DENIED),
770 INT_CONSTANT(ERROR_DIR_NOT_EMPTY),
771 INT_CONSTANT(ERROR_FILE_EXISTS),
772 INT_CONSTANT(ERROR_ALREADY_EXISTS),
773 INT_CONSTANT(ERROR_FILE_NOT_FOUND),
774 INT_CONSTANT(ERROR_NO_MORE_FILES),
775 INT_CONSTANT(ERROR_PATH_NOT_FOUND),
776 INT_CONSTANT(ERROR_BAD_ARGUMENTS),
777 INT_CONSTANT(ERROR_SHARING_VIOLATION),
778 INT_CONSTANT(ERROR_NOT_SUPPORTED),
780 PROP_END
782 #endif // defined(XP_WIN)
786 * Get a field of an object as an object.
788 * If the field does not exist, create it. If it exists but is not an
789 * object, throw a JS error.
791 JSObject *GetOrCreateObjectProperty(JSContext *cx, JS::Handle<JSObject*> aObject,
792 const char *aProperty)
794 JS::Rooted<JS::Value> val(cx);
795 if (!JS_GetProperty(cx, aObject, aProperty, &val)) {
796 return nullptr;
798 if (!val.isUndefined()) {
799 if (val.isObject()) {
800 return &val.toObject();
803 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
804 JSMSG_UNEXPECTED_TYPE, aProperty, "not an object");
805 return nullptr;
807 return JS_DefineObject(cx, aObject, aProperty, nullptr, JS::NullPtr(),
808 JSPROP_ENUMERATE);
812 * Set a property of an object from a nsString.
814 * If the nsString is void (i.e. IsVoid is true), do nothing.
816 bool SetStringProperty(JSContext *cx, JS::Handle<JSObject*> aObject, const char *aProperty,
817 const nsString aValue)
819 if (aValue.IsVoid()) {
820 return true;
822 JSString* strValue = JS_NewUCStringCopyZ(cx, aValue.get());
823 NS_ENSURE_TRUE(strValue, false);
824 JS::Rooted<JS::Value> valValue(cx, STRING_TO_JSVAL(strValue));
825 return JS_SetProperty(cx, aObject, aProperty, valValue);
829 * Define OS-specific constants.
831 * This function creates or uses JS object |OS.Constants| to store
832 * all its constants.
834 bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
836 MOZ_ASSERT(gInitialized);
838 if (gPaths == nullptr) {
839 // If an initialization error was ignored, we may end up with
840 // |gInitialized == true| but |gPaths == nullptr|. We cannot
841 // |MOZ_ASSERT| this, as this would kill precompile_cache.js,
842 // so we simply return an error.
843 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
844 JSMSG_CANT_OPEN, "OSFileConstants", "initialization has failed");
845 return false;
848 JS::Rooted<JSObject*> objOS(cx);
849 if (!(objOS = GetOrCreateObjectProperty(cx, global, "OS"))) {
850 return false;
852 JS::Rooted<JSObject*> objConstants(cx);
853 if (!(objConstants = GetOrCreateObjectProperty(cx, objOS, "Constants"))) {
854 return false;
857 // Build OS.Constants.libc
859 JS::Rooted<JSObject*> objLibc(cx);
860 if (!(objLibc = GetOrCreateObjectProperty(cx, objConstants, "libc"))) {
861 return false;
863 if (!dom::DefineConstants(cx, objLibc, gLibcProperties)) {
864 return false;
867 #if defined(XP_WIN)
868 // Build OS.Constants.Win
870 JS::Rooted<JSObject*> objWin(cx);
871 if (!(objWin = GetOrCreateObjectProperty(cx, objConstants, "Win"))) {
872 return false;
874 if (!dom::DefineConstants(cx, objWin, gWinProperties)) {
875 return false;
877 #endif // defined(XP_WIN)
879 // Build OS.Constants.Sys
881 JS::Rooted<JSObject*> objSys(cx);
882 if (!(objSys = GetOrCreateObjectProperty(cx, objConstants, "Sys"))) {
883 return false;
886 #if defined(MOZ_WIDGET_GONK)
887 JSString* strVersion = JS_NewStringCopyZ(cx, "Gonk");
888 if (!strVersion){
889 return false;
891 JS::Rooted<JS::Value> valVersion(cx, STRING_TO_JSVAL(strVersion));
892 if (!JS_SetProperty(cx, objSys, "Name", valVersion)) {
893 return false;
895 #else
896 nsCOMPtr<nsIXULRuntime> runtime = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
897 if (runtime) {
898 nsAutoCString os;
899 DebugOnly<nsresult> rv = runtime->GetOS(os);
900 MOZ_ASSERT(NS_SUCCEEDED(rv));
902 JSString* strVersion = JS_NewStringCopyZ(cx, os.get());
903 if (!strVersion) {
904 return false;
907 JS::Rooted<JS::Value> valVersion(cx, STRING_TO_JSVAL(strVersion));
908 if (!JS_SetProperty(cx, objSys, "Name", valVersion)) {
909 return false;
912 #endif // defined(MOZ_WIDGET_GONK)
914 #if defined(DEBUG)
915 JS::Rooted<JS::Value> valDebug(cx, JSVAL_TRUE);
916 if (!JS_SetProperty(cx, objSys, "DEBUG", valDebug)) {
917 return false;
919 #endif
921 dom::ConstantSpec umask_cs[] = {
922 { "umask", UINT_TO_JSVAL(gUserUmask) },
923 PROP_END
925 if (!dom::DefineConstants(cx, objSys, umask_cs)) {
926 return false;
929 // Build OS.Constants.Path
931 JS::Rooted<JSObject*> objPath(cx);
932 if (!(objPath = GetOrCreateObjectProperty(cx, objConstants, "Path"))) {
933 return false;
936 // Locate libxul
937 // Note that we don't actually provide the full path, only the name of the
938 // library, which is sufficient to link to the library using js-ctypes.
940 #if defined(XP_MACOSX)
941 // Under MacOS X, for some reason, libxul is called simply "XUL",
942 // and we need to provide the full path.
943 nsAutoString libxul;
944 libxul.Append(gPaths->libDir);
945 libxul.AppendLiteral("/XUL");
946 #else
947 // On other platforms, libxul is a library "xul" with regular
948 // library prefix/suffix.
949 nsAutoString libxul;
950 libxul.AppendLiteral(DLL_PREFIX);
951 libxul.AppendLiteral("xul");
952 libxul.AppendLiteral(DLL_SUFFIX);
953 #endif // defined(XP_MACOSX)
955 if (!SetStringProperty(cx, objPath, "libxul", libxul)) {
956 return false;
959 if (!SetStringProperty(cx, objPath, "libDir", gPaths->libDir)) {
960 return false;
963 if (!SetStringProperty(cx, objPath, "tmpDir", gPaths->tmpDir)) {
964 return false;
967 // Configure profileDir only if it is available at this stage
968 if (!gPaths->profileDir.IsVoid()
969 && !SetStringProperty(cx, objPath, "profileDir", gPaths->profileDir)) {
970 return false;
973 // Configure localProfileDir only if it is available at this stage
974 if (!gPaths->localProfileDir.IsVoid()
975 && !SetStringProperty(cx, objPath, "localProfileDir", gPaths->localProfileDir)) {
976 return false;
979 if (!SetStringProperty(cx, objPath, "homeDir", gPaths->homeDir)) {
980 return false;
983 if (!SetStringProperty(cx, objPath, "desktopDir", gPaths->desktopDir)) {
984 return false;
987 if (!SetStringProperty(cx, objPath, "userApplicationDataDir", gPaths->userApplicationDataDir)) {
988 return false;
991 #if defined(XP_WIN)
992 if (!SetStringProperty(cx, objPath, "winAppDataDir", gPaths->winAppDataDir)) {
993 return false;
996 if (!SetStringProperty(cx, objPath, "winStartMenuProgsDir", gPaths->winStartMenuProgsDir)) {
997 return false;
999 #endif // defined(XP_WIN)
1001 #if defined(XP_MACOSX)
1002 if (!SetStringProperty(cx, objPath, "macUserLibDir", gPaths->macUserLibDir)) {
1003 return false;
1006 if (!SetStringProperty(cx, objPath, "macLocalApplicationsDir", gPaths->macLocalApplicationsDir)) {
1007 return false;
1010 if (!SetStringProperty(cx, objPath, "macTrashDir", gPaths->macTrashDir)) {
1011 return false;
1013 #endif // defined(XP_MACOSX)
1015 // sqlite3 is linked from different places depending on the platform
1016 nsAutoString libsqlite3;
1017 #if defined(ANDROID)
1018 // On Android, we use the system's libsqlite3
1019 libsqlite3.AppendLiteral(DLL_PREFIX);
1020 libsqlite3.AppendLiteral("sqlite3");
1021 libsqlite3.AppendLiteral(DLL_SUFFIX);
1022 #elif defined(XP_WIN)
1023 // On Windows, for some reason, this is part of nss3.dll
1024 libsqlite3.AppendLiteral(DLL_PREFIX);
1025 libsqlite3.AppendLiteral("nss3");
1026 libsqlite3.AppendLiteral(DLL_SUFFIX);
1027 #else
1028 // On other platforms, we link sqlite3 into libxul
1029 libsqlite3 = libxul;
1030 #endif // defined(ANDROID) || defined(XP_WIN)
1032 if (!SetStringProperty(cx, objPath, "libsqlite3", libsqlite3)) {
1033 return false;
1036 return true;
1039 NS_IMPL_ISUPPORTS(OSFileConstantsService, nsIOSFileConstantsService)
1041 OSFileConstantsService::OSFileConstantsService()
1043 MOZ_ASSERT(NS_IsMainThread());
1046 OSFileConstantsService::~OSFileConstantsService()
1048 mozilla::CleanupOSFileConstants();
1052 NS_IMETHODIMP
1053 OSFileConstantsService::Init(JSContext *aCx)
1055 nsresult rv = mozilla::InitOSFileConstants();
1056 if (NS_FAILED(rv)) {
1057 return rv;
1060 mozJSComponentLoader* loader = mozJSComponentLoader::Get();
1061 JS::Rooted<JSObject*> targetObj(aCx);
1062 rv = loader->FindTargetObject(aCx, &targetObj);
1063 NS_ENSURE_SUCCESS(rv, rv);
1065 if (!mozilla::DefineOSFileConstants(aCx, targetObj)) {
1066 return NS_ERROR_FAILURE;
1069 return NS_OK;
1072 } // namespace mozilla