Thu, 22 Jan 2015 13:21:57 +0100
Incorporate requested changes from Mozilla in review:
https://bugzilla.mozilla.org/show_bug.cgi?id=1123480#c6
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>
36 #endif // defined(XP_WIN)
38 #include "jsapi.h"
39 #include "jsfriendapi.h"
40 #include "BindingUtils.h"
42 // Used to provide information on the OS
44 #include "nsThreadUtils.h"
45 #include "nsIObserverService.h"
46 #include "nsIObserver.h"
47 #include "nsDirectoryServiceUtils.h"
48 #include "nsIXULRuntime.h"
49 #include "nsIPropertyBag2.h"
50 #include "nsXPCOMCIDInternal.h"
51 #include "nsServiceManagerUtils.h"
52 #include "nsString.h"
53 #include "nsAutoPtr.h"
54 #include "nsDirectoryServiceDefs.h"
55 #include "nsXULAppAPI.h"
56 #include "nsAppDirectoryServiceDefs.h"
57 #include "mozJSComponentLoader.h"
59 #include "OSFileConstants.h"
60 #include "nsIOSFileConstantsService.h"
61 #include "nsZipArchive.h"
63 #if defined(__DragonFly__) || defined(__FreeBSD__) \
64 || defined(__NetBSD__) || defined(__OpenBSD__)
65 #define __dd_fd dd_fd
66 #endif
68 /**
69 * This module defines the basic libc constants (error numbers, open modes,
70 * etc.) used by OS.File and possibly other OS-bound JavaScript libraries.
71 */
74 namespace mozilla {
76 // Use an anonymous namespace to hide the symbols and avoid any collision
77 // with, for instance, |extern bool gInitialized;|
78 namespace {
79 /**
80 * |true| if this module has been initialized, |false| otherwise
81 */
82 bool gInitialized = false;
84 struct Paths {
85 /**
86 * The name of the directory holding all the libraries (libxpcom, libnss, etc.)
87 */
88 nsString libDir;
89 nsString tmpDir;
90 nsString profileDir;
91 nsString localProfileDir;
92 /**
93 * The user's home directory
94 */
95 nsString homeDir;
96 /**
97 * The user's desktop directory, if there is one. Otherwise this is
98 * the same as homeDir.
99 */
100 nsString desktopDir;
101 /**
102 * The user's 'application data' directory.
103 * Windows:
104 * HOME = Documents and Settings\$USER\Application Data
105 * UAppData = $HOME[\$vendor]\$name
106 *
107 * Unix:
108 * HOME = ~
109 * UAppData = $HOME/.[$vendor/]$name
110 *
111 * Mac:
112 * HOME = ~
113 * UAppData = $HOME/Library/Application Support/$name
114 */
115 nsString userApplicationDataDir;
117 #if defined(XP_WIN)
118 /**
119 * The user's application data directory.
120 */
121 nsString winAppDataDir;
122 /**
123 * The programs subdirectory in the user's start menu directory.
124 */
125 nsString winStartMenuProgsDir;
126 #endif // defined(XP_WIN)
128 #if defined(XP_MACOSX)
129 /**
130 * The user's Library directory.
131 */
132 nsString macUserLibDir;
133 /**
134 * The Application directory, that stores applications installed in the
135 * system.
136 */
137 nsString macLocalApplicationsDir;
138 #endif // defined(XP_MACOSX)
140 Paths()
141 {
142 libDir.SetIsVoid(true);
143 tmpDir.SetIsVoid(true);
144 profileDir.SetIsVoid(true);
145 localProfileDir.SetIsVoid(true);
146 homeDir.SetIsVoid(true);
147 desktopDir.SetIsVoid(true);
148 userApplicationDataDir.SetIsVoid(true);
150 #if defined(XP_WIN)
151 winAppDataDir.SetIsVoid(true);
152 winStartMenuProgsDir.SetIsVoid(true);
153 #endif // defined(XP_WIN)
155 #if defined(XP_MACOSX)
156 macUserLibDir.SetIsVoid(true);
157 macLocalApplicationsDir.SetIsVoid(true);
158 #endif // defined(XP_MACOSX)
159 }
160 };
162 /**
163 * System directories.
164 */
165 Paths* gPaths = nullptr;
167 /**
168 * (Unix) the umask, which goes in OS.Constants.Sys but
169 * can only be looked up (via the system-info service)
170 * on the main thread.
171 */
172 uint32_t gUserUmask = 0;
173 }
175 /**
176 * Return the path to one of the special directories.
177 *
178 * @param aKey The key to the special directory (e.g. "TmpD", "ProfD", ...)
179 * @param aOutPath The path to the special directory. In case of error,
180 * the string is set to void.
181 */
182 nsresult GetPathToSpecialDir(const char *aKey, nsString& aOutPath)
183 {
184 nsCOMPtr<nsIFile> file;
185 nsresult rv = NS_GetSpecialDirectory(aKey, getter_AddRefs(file));
186 if (NS_FAILED(rv) || !file) {
187 return rv;
188 }
190 return file->GetPath(aOutPath);
191 }
193 /**
194 * In some cases, OSFileConstants may be instantiated before the
195 * profile is setup. In such cases, |OS.Constants.Path.profileDir| and
196 * |OS.Constants.Path.localProfileDir| are undefined. However, we want
197 * to ensure that this does not break existing code, so that future
198 * workers spawned after the profile is setup have these constants.
199 *
200 * For this purpose, we register an observer to set |gPaths->profileDir|
201 * and |gPaths->localProfileDir| once the profile is setup.
202 */
203 class DelayedPathSetter MOZ_FINAL: public nsIObserver
204 {
205 NS_DECL_ISUPPORTS
206 NS_DECL_NSIOBSERVER
208 DelayedPathSetter() {}
209 };
211 NS_IMPL_ISUPPORTS(DelayedPathSetter, nsIObserver)
213 NS_IMETHODIMP
214 DelayedPathSetter::Observe(nsISupports*, const char * aTopic, const char16_t*)
215 {
216 if (gPaths == nullptr) {
217 // Initialization of gPaths has not taken place, something is wrong,
218 // don't make things worse.
219 return NS_OK;
220 }
221 nsresult rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_50_DIR, gPaths->profileDir);
222 if (NS_FAILED(rv)) {
223 return rv;
224 }
225 rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_LOCAL_50_DIR, gPaths->localProfileDir);
226 if (NS_FAILED(rv)) {
227 return rv;
228 }
230 return NS_OK;
231 }
233 /**
234 * Perform the part of initialization that can only be
235 * executed on the main thread.
236 */
237 nsresult InitOSFileConstants()
238 {
239 MOZ_ASSERT(NS_IsMainThread());
240 if (gInitialized) {
241 return NS_OK;
242 }
244 gInitialized = true;
246 nsAutoPtr<Paths> paths(new Paths);
248 // Initialize paths->libDir
249 nsCOMPtr<nsIFile> file;
250 nsresult rv = NS_GetSpecialDirectory(NS_XPCOM_LIBRARY_FILE, getter_AddRefs(file));
251 if (NS_FAILED(rv)) {
252 return rv;
253 }
255 nsCOMPtr<nsIFile> libDir;
256 rv = file->GetParent(getter_AddRefs(libDir));
257 if (NS_FAILED(rv)) {
258 return rv;
259 }
261 rv = libDir->GetPath(paths->libDir);
262 if (NS_FAILED(rv)) {
263 return rv;
264 }
266 // Setup profileDir and localProfileDir immediately if possible (we
267 // assume that NS_APP_USER_PROFILE_50_DIR and
268 // NS_APP_USER_PROFILE_LOCAL_50_DIR are set simultaneously)
269 rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_50_DIR, paths->profileDir);
270 if (NS_SUCCEEDED(rv)) {
271 rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_LOCAL_50_DIR, paths->localProfileDir);
272 }
274 // Otherwise, delay setup of profileDir/localProfileDir until they
275 // become available.
276 if (NS_FAILED(rv)) {
277 nsCOMPtr<nsIObserverService> obsService = do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
278 if (NS_FAILED(rv)) {
279 return rv;
280 }
281 nsRefPtr<DelayedPathSetter> pathSetter = new DelayedPathSetter();
282 rv = obsService->AddObserver(pathSetter, "profile-do-change", false);
283 if (NS_FAILED(rv)) {
284 return rv;
285 }
286 }
288 // For other directories, ignore errors (they may be undefined on
289 // some platforms or in non-Firefox embeddings of Gecko).
291 GetPathToSpecialDir(NS_OS_TEMP_DIR, paths->tmpDir);
292 GetPathToSpecialDir(NS_OS_HOME_DIR, paths->homeDir);
293 GetPathToSpecialDir(NS_OS_DESKTOP_DIR, paths->desktopDir);
294 GetPathToSpecialDir(XRE_USER_APP_DATA_DIR, paths->userApplicationDataDir);
296 #if defined(XP_WIN)
297 GetPathToSpecialDir(NS_WIN_APPDATA_DIR, paths->winAppDataDir);
298 GetPathToSpecialDir(NS_WIN_PROGRAMS_DIR, paths->winStartMenuProgsDir);
299 #endif // defined(XP_WIN)
301 #if defined(XP_MACOSX)
302 GetPathToSpecialDir(NS_MAC_USER_LIB_DIR, paths->macUserLibDir);
303 GetPathToSpecialDir(NS_OSX_LOCAL_APPLICATIONS_DIR, paths->macLocalApplicationsDir);
304 #endif // defined(XP_MACOSX)
306 gPaths = paths.forget();
308 // Get the umask from the system-info service.
309 // The property will always be present, but it will be zero on
310 // non-Unix systems.
311 nsCOMPtr<nsIPropertyBag2> infoService =
312 do_GetService("@mozilla.org/system-info;1");
313 MOZ_ASSERT(infoService, "Could not access the system information service");
314 rv = infoService->GetPropertyAsUint32(NS_LITERAL_STRING("umask"),
315 &gUserUmask);
316 if (NS_FAILED(rv)) {
317 return rv;
318 }
320 return NS_OK;
321 }
323 /**
324 * Perform the cleaning up that can only be executed on the main thread.
325 */
326 void CleanupOSFileConstants()
327 {
328 MOZ_ASSERT(NS_IsMainThread());
329 if (!gInitialized) {
330 return;
331 }
333 gInitialized = false;
334 delete gPaths;
335 }
338 /**
339 * Define a simple read-only property holding an integer.
340 *
341 * @param name The name of the constant. Used both as the JS name for the
342 * constant and to access its value. Must be defined.
343 *
344 * Produces a |ConstantSpec|.
345 */
346 #define INT_CONSTANT(name) \
347 { #name, INT_TO_JSVAL(name) }
349 /**
350 * Define a simple read-only property holding an unsigned integer.
351 *
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.
354 *
355 * Produces a |ConstantSpec|.
356 */
357 #define UINT_CONSTANT(name) \
358 { #name, UINT_TO_JSVAL((name)) }
360 /**
361 * End marker for ConstantSpec
362 */
363 #define PROP_END { nullptr, JS::UndefinedValue() }
366 // Define missing constants for Android
367 #if !defined(S_IRGRP)
368 #define S_IXOTH 0001
369 #define S_IWOTH 0002
370 #define S_IROTH 0004
371 #define S_IRWXO 0007
372 #define S_IXGRP 0010
373 #define S_IWGRP 0020
374 #define S_IRGRP 0040
375 #define S_IRWXG 0070
376 #define S_IXUSR 0100
377 #define S_IWUSR 0200
378 #define S_IRUSR 0400
379 #define S_IRWXU 0700
380 #endif // !defined(S_IRGRP)
382 /**
383 * The properties defined in libc.
384 *
385 * If you extend this list of properties, please
386 * separate categories ("errors", "open", etc.),
387 * keep properties organized by alphabetical order
388 * and #ifdef-away properties that are not portable.
389 */
390 static const dom::ConstantSpec gLibcProperties[] =
391 {
392 // Arguments for open
393 INT_CONSTANT(O_APPEND),
394 INT_CONSTANT(O_CREAT),
395 #if defined(O_DIRECTORY)
396 INT_CONSTANT(O_DIRECTORY),
397 #endif // defined(O_DIRECTORY)
398 #if defined(O_EVTONLY)
399 INT_CONSTANT(O_EVTONLY),
400 #endif // defined(O_EVTONLY)
401 INT_CONSTANT(O_EXCL),
402 #if defined(O_EXLOCK)
403 INT_CONSTANT(O_EXLOCK),
404 #endif // defined(O_EXLOCK)
405 #if defined(O_LARGEFILE)
406 INT_CONSTANT(O_LARGEFILE),
407 #endif // defined(O_LARGEFILE)
408 #if defined(O_NOFOLLOW)
409 INT_CONSTANT(O_NOFOLLOW),
410 #endif // defined(O_NOFOLLOW)
411 #if defined(O_NONBLOCK)
412 INT_CONSTANT(O_NONBLOCK),
413 #endif // defined(O_NONBLOCK)
414 INT_CONSTANT(O_RDONLY),
415 INT_CONSTANT(O_RDWR),
416 #if defined(O_RSYNC)
417 INT_CONSTANT(O_RSYNC),
418 #endif // defined(O_RSYNC)
419 #if defined(O_SHLOCK)
420 INT_CONSTANT(O_SHLOCK),
421 #endif // defined(O_SHLOCK)
422 #if defined(O_SYMLINK)
423 INT_CONSTANT(O_SYMLINK),
424 #endif // defined(O_SYMLINK)
425 #if defined(O_SYNC)
426 INT_CONSTANT(O_SYNC),
427 #endif // defined(O_SYNC)
428 INT_CONSTANT(O_TRUNC),
429 INT_CONSTANT(O_WRONLY),
431 #if defined(AT_EACCESS)
432 INT_CONSTANT(AT_EACCESS),
433 #endif //defined(AT_EACCESS)
434 #if defined(AT_FDCWD)
435 INT_CONSTANT(AT_FDCWD),
436 #endif //defined(AT_FDCWD)
437 #if defined(AT_SYMLINK_NOFOLLOW)
438 INT_CONSTANT(AT_SYMLINK_NOFOLLOW),
439 #endif //defined(AT_SYMLINK_NOFOLLOW)
441 #if defined(POSIX_FADV_SEQUENTIAL)
442 INT_CONSTANT(POSIX_FADV_SEQUENTIAL),
443 #endif //defined(POSIX_FADV_SEQUENTIAL)
445 // access
446 #if defined(F_OK)
447 INT_CONSTANT(F_OK),
448 INT_CONSTANT(R_OK),
449 INT_CONSTANT(W_OK),
450 INT_CONSTANT(X_OK),
451 #endif // defined(F_OK)
453 // modes
454 INT_CONSTANT(S_IRGRP),
455 INT_CONSTANT(S_IROTH),
456 INT_CONSTANT(S_IRUSR),
457 INT_CONSTANT(S_IRWXG),
458 INT_CONSTANT(S_IRWXO),
459 INT_CONSTANT(S_IRWXU),
460 INT_CONSTANT(S_IWGRP),
461 INT_CONSTANT(S_IWOTH),
462 INT_CONSTANT(S_IWUSR),
463 INT_CONSTANT(S_IXOTH),
464 INT_CONSTANT(S_IXGRP),
465 INT_CONSTANT(S_IXUSR),
467 // seek
468 INT_CONSTANT(SEEK_CUR),
469 INT_CONSTANT(SEEK_END),
470 INT_CONSTANT(SEEK_SET),
472 // copyfile
473 #if defined(COPYFILE_DATA)
474 INT_CONSTANT(COPYFILE_DATA),
475 INT_CONSTANT(COPYFILE_EXCL),
476 INT_CONSTANT(COPYFILE_XATTR),
477 INT_CONSTANT(COPYFILE_STAT),
478 INT_CONSTANT(COPYFILE_ACL),
479 INT_CONSTANT(COPYFILE_MOVE),
480 #endif // defined(COPYFILE_DATA)
482 // error values
483 INT_CONSTANT(EACCES),
484 INT_CONSTANT(EAGAIN),
485 INT_CONSTANT(EBADF),
486 INT_CONSTANT(EEXIST),
487 INT_CONSTANT(EFAULT),
488 INT_CONSTANT(EFBIG),
489 INT_CONSTANT(EINVAL),
490 INT_CONSTANT(EIO),
491 INT_CONSTANT(EISDIR),
492 #if defined(ELOOP) // not defined with VC9
493 INT_CONSTANT(ELOOP),
494 #endif // defined(ELOOP)
495 INT_CONSTANT(EMFILE),
496 INT_CONSTANT(ENAMETOOLONG),
497 INT_CONSTANT(ENFILE),
498 INT_CONSTANT(ENOENT),
499 INT_CONSTANT(ENOMEM),
500 INT_CONSTANT(ENOSPC),
501 INT_CONSTANT(ENOTDIR),
502 INT_CONSTANT(ENXIO),
503 #if defined(EOPNOTSUPP) // not defined with VC 9
504 INT_CONSTANT(EOPNOTSUPP),
505 #endif // defined(EOPNOTSUPP)
506 #if defined(EOVERFLOW) // not defined with VC 9
507 INT_CONSTANT(EOVERFLOW),
508 #endif // defined(EOVERFLOW)
509 INT_CONSTANT(EPERM),
510 INT_CONSTANT(ERANGE),
511 #if defined(ETIMEDOUT) // not defined with VC 9
512 INT_CONSTANT(ETIMEDOUT),
513 #endif // defined(ETIMEDOUT)
514 #if defined(EWOULDBLOCK) // not defined with VC 9
515 INT_CONSTANT(EWOULDBLOCK),
516 #endif // defined(EWOULDBLOCK)
517 INT_CONSTANT(EXDEV),
519 #if defined(DT_UNKNOWN)
520 // Constants for |readdir|
521 INT_CONSTANT(DT_UNKNOWN),
522 INT_CONSTANT(DT_FIFO),
523 INT_CONSTANT(DT_CHR),
524 INT_CONSTANT(DT_DIR),
525 INT_CONSTANT(DT_BLK),
526 INT_CONSTANT(DT_REG),
527 INT_CONSTANT(DT_LNK),
528 INT_CONSTANT(DT_SOCK),
529 #endif // defined(DT_UNKNOWN)
531 #if defined(S_IFIFO)
532 // Constants for |stat|
533 INT_CONSTANT(S_IFMT),
534 INT_CONSTANT(S_IFIFO),
535 INT_CONSTANT(S_IFCHR),
536 INT_CONSTANT(S_IFDIR),
537 INT_CONSTANT(S_IFBLK),
538 INT_CONSTANT(S_IFREG),
539 INT_CONSTANT(S_IFLNK),
540 INT_CONSTANT(S_IFSOCK),
541 #endif // defined(S_IFIFO)
543 // Constants used to define data structures
544 //
545 // Many data structures have different fields/sizes/etc. on
546 // various OSes / versions of the same OS / platforms. For these
547 // data structures, we need to compute and export from C the size
548 // and, if necessary, the offset of fields, so as to be able to
549 // define the structure in JS.
551 #if defined(XP_UNIX)
552 // The size of |mode_t|.
553 { "OSFILE_SIZEOF_MODE_T", INT_TO_JSVAL(sizeof (mode_t)) },
555 // The size of |gid_t|.
556 { "OSFILE_SIZEOF_GID_T", INT_TO_JSVAL(sizeof (gid_t)) },
558 // The size of |uid_t|.
559 { "OSFILE_SIZEOF_UID_T", INT_TO_JSVAL(sizeof (uid_t)) },
561 // The size of |time_t|.
562 { "OSFILE_SIZEOF_TIME_T", INT_TO_JSVAL(sizeof (time_t)) },
564 // The size of |fsblkcnt_t|.
565 { "OSFILE_SIZEOF_FSBLKCNT_T", INT_TO_JSVAL(sizeof (fsblkcnt_t)) },
567 #if !defined(ANDROID)
568 // The size of |posix_spawn_file_actions_t|.
569 { "OSFILE_SIZEOF_POSIX_SPAWN_FILE_ACTIONS_T", INT_TO_JSVAL(sizeof (posix_spawn_file_actions_t)) },
570 #endif // !defined(ANDROID)
572 // Defining |dirent|.
573 // Size
574 { "OSFILE_SIZEOF_DIRENT", INT_TO_JSVAL(sizeof (dirent)) },
576 // Offset of field |d_name|.
577 { "OSFILE_OFFSETOF_DIRENT_D_NAME", INT_TO_JSVAL(offsetof (struct dirent, d_name)) },
578 // An upper bound to the length of field |d_name| of struct |dirent|.
579 // (may not be exact, depending on padding).
580 { "OSFILE_SIZEOF_DIRENT_D_NAME", INT_TO_JSVAL(sizeof (struct dirent) - offsetof (struct dirent, d_name)) },
582 // Defining |timeval|.
583 { "OSFILE_SIZEOF_TIMEVAL", INT_TO_JSVAL(sizeof (struct timeval)) },
584 { "OSFILE_OFFSETOF_TIMEVAL_TV_SEC", INT_TO_JSVAL(offsetof (struct timeval, tv_sec)) },
585 { "OSFILE_OFFSETOF_TIMEVAL_TV_USEC", INT_TO_JSVAL(offsetof (struct timeval, tv_usec)) },
587 #if defined(DT_UNKNOWN)
588 // Position of field |d_type| in |dirent|
589 // Not strictly posix, but seems defined on all platforms
590 // except mingw32.
591 { "OSFILE_OFFSETOF_DIRENT_D_TYPE", INT_TO_JSVAL(offsetof (struct dirent, d_type)) },
592 #endif // defined(DT_UNKNOWN)
594 // Under MacOS X and BSDs, |dirfd| is a macro rather than a
595 // function, so we need a little help to get it to work
596 #if defined(dirfd)
597 { "OSFILE_SIZEOF_DIR", INT_TO_JSVAL(sizeof (DIR)) },
599 { "OSFILE_OFFSETOF_DIR_DD_FD", INT_TO_JSVAL(offsetof (DIR, __dd_fd)) },
600 #endif
602 // Defining |stat|
604 { "OSFILE_SIZEOF_STAT", INT_TO_JSVAL(sizeof (struct stat)) },
606 { "OSFILE_OFFSETOF_STAT_ST_MODE", INT_TO_JSVAL(offsetof (struct stat, st_mode)) },
607 { "OSFILE_OFFSETOF_STAT_ST_UID", INT_TO_JSVAL(offsetof (struct stat, st_uid)) },
608 { "OSFILE_OFFSETOF_STAT_ST_GID", INT_TO_JSVAL(offsetof (struct stat, st_gid)) },
609 { "OSFILE_OFFSETOF_STAT_ST_SIZE", INT_TO_JSVAL(offsetof (struct stat, st_size)) },
611 #if defined(HAVE_ST_ATIMESPEC)
612 { "OSFILE_OFFSETOF_STAT_ST_ATIME", INT_TO_JSVAL(offsetof (struct stat, st_atimespec)) },
613 { "OSFILE_OFFSETOF_STAT_ST_MTIME", INT_TO_JSVAL(offsetof (struct stat, st_mtimespec)) },
614 { "OSFILE_OFFSETOF_STAT_ST_CTIME", INT_TO_JSVAL(offsetof (struct stat, st_ctimespec)) },
615 #else
616 { "OSFILE_OFFSETOF_STAT_ST_ATIME", INT_TO_JSVAL(offsetof (struct stat, st_atime)) },
617 { "OSFILE_OFFSETOF_STAT_ST_MTIME", INT_TO_JSVAL(offsetof (struct stat, st_mtime)) },
618 { "OSFILE_OFFSETOF_STAT_ST_CTIME", INT_TO_JSVAL(offsetof (struct stat, st_ctime)) },
619 #endif // defined(HAVE_ST_ATIME)
621 // Several OSes have a birthtime field. For the moment, supporting only Darwin.
622 #if defined(_DARWIN_FEATURE_64_BIT_INODE)
623 { "OSFILE_OFFSETOF_STAT_ST_BIRTHTIME", INT_TO_JSVAL(offsetof (struct stat, st_birthtime)) },
624 #endif // defined(_DARWIN_FEATURE_64_BIT_INODE)
626 // Defining |statvfs|
628 { "OSFILE_SIZEOF_STATVFS", INT_TO_JSVAL(sizeof (struct statvfs)) },
630 { "OSFILE_OFFSETOF_STATVFS_F_BSIZE", INT_TO_JSVAL(offsetof (struct statvfs, f_bsize)) },
631 { "OSFILE_OFFSETOF_STATVFS_F_BAVAIL", INT_TO_JSVAL(offsetof (struct statvfs, f_bavail)) },
633 #endif // defined(XP_UNIX)
637 // System configuration
639 // Under MacOSX, to avoid using deprecated functions that do not
640 // match the constants we define in this object (including
641 // |sizeof|/|offsetof| stuff, but not only), for a number of
642 // functions, we need to adapt the name of the symbols we are using,
643 // whenever macro _DARWIN_FEATURE_64_BIT_INODE is set. We export
644 // this value to be able to do so from JavaScript.
645 #if defined(_DARWIN_FEATURE_64_BIT_INODE)
646 { "_DARWIN_FEATURE_64_BIT_INODE", INT_TO_JSVAL(1) },
647 #endif // defined(_DARWIN_FEATURE_64_BIT_INODE)
649 // Similar feature for Linux
650 #if defined(_STAT_VER)
651 INT_CONSTANT(_STAT_VER),
652 #endif // defined(_STAT_VER)
654 PROP_END
655 };
658 #if defined(XP_WIN)
659 /**
660 * The properties defined in windows.h.
661 *
662 * If you extend this list of properties, please
663 * separate categories ("errors", "open", etc.),
664 * keep properties organized by alphabetical order
665 * and #ifdef-away properties that are not portable.
666 */
667 static const dom::ConstantSpec gWinProperties[] =
668 {
669 // FormatMessage flags
670 INT_CONSTANT(FORMAT_MESSAGE_FROM_SYSTEM),
671 INT_CONSTANT(FORMAT_MESSAGE_IGNORE_INSERTS),
673 // The max length of paths
674 INT_CONSTANT(MAX_PATH),
676 // CreateFile desired access
677 INT_CONSTANT(GENERIC_ALL),
678 INT_CONSTANT(GENERIC_EXECUTE),
679 INT_CONSTANT(GENERIC_READ),
680 INT_CONSTANT(GENERIC_WRITE),
682 // CreateFile share mode
683 INT_CONSTANT(FILE_SHARE_DELETE),
684 INT_CONSTANT(FILE_SHARE_READ),
685 INT_CONSTANT(FILE_SHARE_WRITE),
687 // CreateFile creation disposition
688 INT_CONSTANT(CREATE_ALWAYS),
689 INT_CONSTANT(CREATE_NEW),
690 INT_CONSTANT(OPEN_ALWAYS),
691 INT_CONSTANT(OPEN_EXISTING),
692 INT_CONSTANT(TRUNCATE_EXISTING),
694 // CreateFile attributes
695 INT_CONSTANT(FILE_ATTRIBUTE_ARCHIVE),
696 INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
697 INT_CONSTANT(FILE_ATTRIBUTE_NORMAL),
698 INT_CONSTANT(FILE_ATTRIBUTE_READONLY),
699 INT_CONSTANT(FILE_ATTRIBUTE_REPARSE_POINT),
700 INT_CONSTANT(FILE_ATTRIBUTE_TEMPORARY),
701 INT_CONSTANT(FILE_FLAG_BACKUP_SEMANTICS),
703 // CreateFile error constant
704 { "INVALID_HANDLE_VALUE", INT_TO_JSVAL(INT_PTR(INVALID_HANDLE_VALUE)) },
707 // CreateFile flags
708 INT_CONSTANT(FILE_FLAG_DELETE_ON_CLOSE),
710 // SetFilePointer methods
711 INT_CONSTANT(FILE_BEGIN),
712 INT_CONSTANT(FILE_CURRENT),
713 INT_CONSTANT(FILE_END),
715 // SetFilePointer error constant
716 UINT_CONSTANT(INVALID_SET_FILE_POINTER),
718 // File attributes
719 INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
722 // MoveFile flags
723 INT_CONSTANT(MOVEFILE_COPY_ALLOWED),
724 INT_CONSTANT(MOVEFILE_REPLACE_EXISTING),
726 // GetFileAttributes error constant
727 INT_CONSTANT(INVALID_FILE_ATTRIBUTES),
729 // GetNamedSecurityInfo and SetNamedSecurityInfo constants
730 INT_CONSTANT(UNPROTECTED_DACL_SECURITY_INFORMATION),
731 INT_CONSTANT(SE_FILE_OBJECT),
732 INT_CONSTANT(DACL_SECURITY_INFORMATION),
734 // Errors
735 INT_CONSTANT(ERROR_INVALID_HANDLE),
736 INT_CONSTANT(ERROR_ACCESS_DENIED),
737 INT_CONSTANT(ERROR_DIR_NOT_EMPTY),
738 INT_CONSTANT(ERROR_FILE_EXISTS),
739 INT_CONSTANT(ERROR_ALREADY_EXISTS),
740 INT_CONSTANT(ERROR_FILE_NOT_FOUND),
741 INT_CONSTANT(ERROR_NO_MORE_FILES),
742 INT_CONSTANT(ERROR_PATH_NOT_FOUND),
743 INT_CONSTANT(ERROR_BAD_ARGUMENTS),
744 INT_CONSTANT(ERROR_NOT_SUPPORTED),
746 PROP_END
747 };
748 #endif // defined(XP_WIN)
751 /**
752 * Get a field of an object as an object.
753 *
754 * If the field does not exist, create it. If it exists but is not an
755 * object, throw a JS error.
756 */
757 JSObject *GetOrCreateObjectProperty(JSContext *cx, JS::Handle<JSObject*> aObject,
758 const char *aProperty)
759 {
760 JS::Rooted<JS::Value> val(cx);
761 if (!JS_GetProperty(cx, aObject, aProperty, &val)) {
762 return nullptr;
763 }
764 if (!val.isUndefined()) {
765 if (val.isObject()) {
766 return &val.toObject();
767 }
769 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
770 JSMSG_UNEXPECTED_TYPE, aProperty, "not an object");
771 return nullptr;
772 }
773 return JS_DefineObject(cx, aObject, aProperty, nullptr, nullptr,
774 JSPROP_ENUMERATE);
775 }
777 /**
778 * Set a property of an object from a nsString.
779 *
780 * If the nsString is void (i.e. IsVoid is true), do nothing.
781 */
782 bool SetStringProperty(JSContext *cx, JS::Handle<JSObject*> aObject, const char *aProperty,
783 const nsString aValue)
784 {
785 if (aValue.IsVoid()) {
786 return true;
787 }
788 JSString* strValue = JS_NewUCStringCopyZ(cx, aValue.get());
789 NS_ENSURE_TRUE(strValue, false);
790 JS::Rooted<JS::Value> valValue(cx, STRING_TO_JSVAL(strValue));
791 return JS_SetProperty(cx, aObject, aProperty, valValue);
792 }
794 /**
795 * Define OS-specific constants.
796 *
797 * This function creates or uses JS object |OS.Constants| to store
798 * all its constants.
799 */
800 bool DefineOSFileConstants(JSContext *cx, JS::Handle<JSObject*> global)
801 {
802 MOZ_ASSERT(gInitialized);
804 if (gPaths == nullptr) {
805 // If an initialization error was ignored, we may end up with
806 // |gInitialized == true| but |gPaths == nullptr|. We cannot
807 // |MOZ_ASSERT| this, as this would kill precompile_cache.js,
808 // so we simply return an error.
809 JS_ReportErrorNumber(cx, js_GetErrorMessage, nullptr,
810 JSMSG_CANT_OPEN, "OSFileConstants", "initialization has failed");
811 return false;
812 }
814 JS::Rooted<JSObject*> objOS(cx);
815 if (!(objOS = GetOrCreateObjectProperty(cx, global, "OS"))) {
816 return false;
817 }
818 JS::Rooted<JSObject*> objConstants(cx);
819 if (!(objConstants = GetOrCreateObjectProperty(cx, objOS, "Constants"))) {
820 return false;
821 }
823 // Build OS.Constants.libc
825 JS::Rooted<JSObject*> objLibc(cx);
826 if (!(objLibc = GetOrCreateObjectProperty(cx, objConstants, "libc"))) {
827 return false;
828 }
829 if (!dom::DefineConstants(cx, objLibc, gLibcProperties)) {
830 return false;
831 }
833 #if defined(XP_WIN)
834 // Build OS.Constants.Win
836 JS::Rooted<JSObject*> objWin(cx);
837 if (!(objWin = GetOrCreateObjectProperty(cx, objConstants, "Win"))) {
838 return false;
839 }
840 if (!dom::DefineConstants(cx, objWin, gWinProperties)) {
841 return false;
842 }
843 #endif // defined(XP_WIN)
845 // Build OS.Constants.Sys
847 JS::Rooted<JSObject*> objSys(cx);
848 if (!(objSys = GetOrCreateObjectProperty(cx, objConstants, "Sys"))) {
849 return false;
850 }
852 nsCOMPtr<nsIXULRuntime> runtime = do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
853 if (runtime) {
854 nsAutoCString os;
855 DebugOnly<nsresult> rv = runtime->GetOS(os);
856 MOZ_ASSERT(NS_SUCCEEDED(rv));
858 JSString* strVersion = JS_NewStringCopyZ(cx, os.get());
859 if (!strVersion) {
860 return false;
861 }
863 JS::Rooted<JS::Value> valVersion(cx, STRING_TO_JSVAL(strVersion));
864 if (!JS_SetProperty(cx, objSys, "Name", valVersion)) {
865 return false;
866 }
867 }
869 #if defined(DEBUG)
870 JS::Rooted<JS::Value> valDebug(cx, JSVAL_TRUE);
871 if (!JS_SetProperty(cx, objSys, "DEBUG", valDebug)) {
872 return false;
873 }
874 #endif
876 dom::ConstantSpec umask_cs[] = {
877 { "umask", UINT_TO_JSVAL(gUserUmask) },
878 PROP_END
879 };
880 if (!dom::DefineConstants(cx, objSys, umask_cs)) {
881 return false;
882 }
884 // Build OS.Constants.Path
886 JS::Rooted<JSObject*> objPath(cx);
887 if (!(objPath = GetOrCreateObjectProperty(cx, objConstants, "Path"))) {
888 return false;
889 }
891 // Locate libxul
892 // Note that we don't actually provide the full path, only the name of the
893 // library, which is sufficient to link to the library using js-ctypes.
895 #if defined(XP_MACOSX)
896 // Under MacOS X, for some reason, libxul is called simply "XUL",
897 // and we need to provide the full path.
898 nsAutoString libxul;
899 libxul.Append(gPaths->libDir);
900 libxul.Append(NS_LITERAL_STRING("/XUL"));
901 #else
902 // On other platforms, libxul is a library "xul" with regular
903 // library prefix/suffix.
904 nsAutoString libxul;
905 libxul.Append(NS_LITERAL_STRING(DLL_PREFIX));
906 libxul.Append(NS_LITERAL_STRING("xul"));
907 libxul.Append(NS_LITERAL_STRING(DLL_SUFFIX));
908 #endif // defined(XP_MACOSX)
910 if (!SetStringProperty(cx, objPath, "libxul", libxul)) {
911 return false;
912 }
914 if (!SetStringProperty(cx, objPath, "libDir", gPaths->libDir)) {
915 return false;
916 }
918 if (!SetStringProperty(cx, objPath, "tmpDir", gPaths->tmpDir)) {
919 return false;
920 }
922 // Configure profileDir only if it is available at this stage
923 if (!gPaths->profileDir.IsVoid()
924 && !SetStringProperty(cx, objPath, "profileDir", gPaths->profileDir)) {
925 return false;
926 }
928 // Configure localProfileDir only if it is available at this stage
929 if (!gPaths->localProfileDir.IsVoid()
930 && !SetStringProperty(cx, objPath, "localProfileDir", gPaths->localProfileDir)) {
931 return false;
932 }
934 if (!SetStringProperty(cx, objPath, "homeDir", gPaths->homeDir)) {
935 return false;
936 }
938 if (!SetStringProperty(cx, objPath, "desktopDir", gPaths->desktopDir)) {
939 return false;
940 }
942 if (!SetStringProperty(cx, objPath, "userApplicationDataDir", gPaths->userApplicationDataDir)) {
943 return false;
944 }
946 #if defined(XP_WIN)
947 if (!SetStringProperty(cx, objPath, "winAppDataDir", gPaths->winAppDataDir)) {
948 return false;
949 }
951 if (!SetStringProperty(cx, objPath, "winStartMenuProgsDir", gPaths->winStartMenuProgsDir)) {
952 return false;
953 }
954 #endif // defined(XP_WIN)
956 #if defined(XP_MACOSX)
957 if (!SetStringProperty(cx, objPath, "macUserLibDir", gPaths->macUserLibDir)) {
958 return false;
959 }
961 if (!SetStringProperty(cx, objPath, "macLocalApplicationsDir", gPaths->macLocalApplicationsDir)) {
962 return false;
963 }
964 #endif // defined(XP_MACOSX)
966 // sqlite3 is linked from different places depending on the platform
967 nsAutoString libsqlite3;
968 #if defined(ANDROID)
969 // On Android, we use the system's libsqlite3
970 libsqlite3.Append(NS_LITERAL_STRING(DLL_PREFIX));
971 libsqlite3.Append(NS_LITERAL_STRING("sqlite3"));
972 libsqlite3.Append(NS_LITERAL_STRING(DLL_SUFFIX));
973 #elif defined(XP_WIN)
974 // On Windows, for some reason, this is part of nss3.dll
975 libsqlite3.Append(NS_LITERAL_STRING(DLL_PREFIX));
976 libsqlite3.Append(NS_LITERAL_STRING("nss3"));
977 libsqlite3.Append(NS_LITERAL_STRING(DLL_SUFFIX));
978 #else
979 // On other platforms, we link sqlite3 into libxul
980 libsqlite3 = libxul;
981 #endif // defined(ANDROID) || defined(XP_WIN)
983 if (!SetStringProperty(cx, objPath, "libsqlite3", libsqlite3)) {
984 return false;
985 }
987 return true;
988 }
990 NS_IMPL_ISUPPORTS(OSFileConstantsService, nsIOSFileConstantsService)
992 OSFileConstantsService::OSFileConstantsService()
993 {
994 MOZ_ASSERT(NS_IsMainThread());
995 }
997 OSFileConstantsService::~OSFileConstantsService()
998 {
999 mozilla::CleanupOSFileConstants();
1000 }
1003 NS_IMETHODIMP
1004 OSFileConstantsService::Init(JSContext *aCx)
1005 {
1006 nsresult rv = mozilla::InitOSFileConstants();
1007 if (NS_FAILED(rv)) {
1008 return rv;
1009 }
1011 mozJSComponentLoader* loader = mozJSComponentLoader::Get();
1012 JS::Rooted<JSObject*> targetObj(aCx);
1013 rv = loader->FindTargetObject(aCx, &targetObj);
1014 NS_ENSURE_SUCCESS(rv, rv);
1016 if (!mozilla::DefineOSFileConstants(aCx, targetObj)) {
1017 return NS_ERROR_FAILURE;
1018 }
1020 return NS_OK;
1021 }
1023 } // namespace mozilla