1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */
3 /* This Source Code Form is subject to the terms of the Mozilla Public
4 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
5 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6
7 #include "mozilla/DebugOnly.h"
8
9 #include "fcntl.h"
10 #include "errno.h"
11
12 #include "prsystem.h"
13
14 // Short macro to get the size of a member of a
15 // given struct at compile time.
16 // t is the type of struct, m the name of the
17 // member:
18 // DOM_SIZEOF_MEMBER(struct mystruct, myint)
19 // will give you the size of the type of myint.
20 #define DOM_SIZEOF_MEMBER(t, m) sizeof(((t*)0)->m)
21
22 #if defined(XP_UNIX)
23 # include "unistd.h"
24 # include "dirent.h"
25 # include "poll.h"
26 # include "sys/stat.h"
27 # if defined(XP_LINUX)
28 # include <sys/prctl.h>
29 # include <sys/vfs.h>
30 # define statvfs statfs
31 # define f_frsize f_bsize
32 # else
33 # include "sys/statvfs.h"
34 # endif // defined(XP_LINUX)
35 # if !defined(ANDROID)
36 # include "sys/wait.h"
37 # include <spawn.h>
38 # endif // !defined(ANDROID)
39 #endif // defined(XP_UNIX)
40
41 #if defined(XP_LINUX)
42 # include <linux/fadvise.h>
43 #endif // defined(XP_LINUX)
44
45 #if defined(XP_MACOSX)
46 # include "copyfile.h"
47 #endif // defined(XP_MACOSX)
48
49 #if defined(XP_WIN)
50 # include <windows.h>
51 # include <accctrl.h>
52
53 # ifndef PATH_MAX
54 # define PATH_MAX MAX_PATH
55 # endif
56
57 #endif // defined(XP_WIN)
58
59 #include "jsapi.h"
60 #include "jsfriendapi.h"
61 #include "js/friend/ErrorMessages.h" // js::GetErrorMessage, JSMSG_*
62 #include "BindingUtils.h"
63
64 // Used to provide information on the OS
65
66 #include "nsThreadUtils.h"
67 #include "nsIObserverService.h"
68 #include "nsIObserver.h"
69 #include "nsDirectoryServiceUtils.h"
70 #include "nsIXULRuntime.h"
71 #include "nsXPCOMCIDInternal.h"
72 #include "nsServiceManagerUtils.h"
73 #include "nsString.h"
74 #include "nsSystemInfo.h"
75 #include "nsDirectoryServiceDefs.h"
76 #include "nsXULAppAPI.h"
77 #include "nsAppDirectoryServiceDefs.h"
78 #include "mozJSComponentLoader.h"
79
80 #include "mozilla/ClearOnShutdown.h"
81 #include "mozilla/StaticPtr.h"
82 #include "mozilla/UniquePtr.h"
83
84 #include "OSFileConstants.h"
85 #include "nsZipArchive.h"
86
87 #if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__NetBSD__) || \
88 defined(__OpenBSD__)
89 # define __dd_fd dd_fd
90 #endif
91
92 /**
93 * This module defines the basic libc constants (error numbers, open modes,
94 * etc.) used by OS.File and possibly other OS-bound JavaScript libraries.
95 */
96
97 namespace mozilla {
98
99 namespace {
100
101 StaticRefPtr<OSFileConstantsService> gInstance;
102
103 } // anonymous namespace
104
105 struct OSFileConstantsService::Paths {
106 /**
107 * The name of the directory holding all the libraries (libxpcom, libnss,
108 * etc.)
109 */
110 nsString libDir;
111 nsString tmpDir;
112 nsString profileDir;
113 nsString localProfileDir;
114
Pathsmozilla::OSFileConstantsService::Paths115 Paths() {
116 libDir.SetIsVoid(true);
117 tmpDir.SetIsVoid(true);
118 profileDir.SetIsVoid(true);
119 localProfileDir.SetIsVoid(true);
120 }
121 };
122
123 /**
124 * Return the path to one of the special directories.
125 *
126 * @param aKey The key to the special directory (e.g. "TmpD", "ProfD", ...)
127 * @param aOutPath The path to the special directory. In case of error,
128 * the string is set to void.
129 */
GetPathToSpecialDir(const char * aKey,nsString & aOutPath)130 nsresult GetPathToSpecialDir(const char* aKey, nsString& aOutPath) {
131 nsCOMPtr<nsIFile> file;
132 nsresult rv = NS_GetSpecialDirectory(aKey, getter_AddRefs(file));
133 if (NS_FAILED(rv) || !file) {
134 return rv;
135 }
136
137 return file->GetPath(aOutPath);
138 }
139
140 /**
141 * In some cases, OSFileConstants may be instantiated before the
142 * profile is setup. In such cases, |OS.Constants.Path.profileDir| and
143 * |OS.Constants.Path.localProfileDir| are undefined. However, we want
144 * to ensure that this does not break existing code, so that future
145 * workers spawned after the profile is setup have these constants.
146 *
147 * For this purpose, we register an observer to set |mPaths->profileDir|
148 * and |mPaths->localProfileDir| once the profile is setup.
149 */
150 NS_IMETHODIMP
Observe(nsISupports *,const char * aTopic,const char16_t *)151 OSFileConstantsService::Observe(nsISupports*, const char* aTopic,
152 const char16_t*) {
153 if (!mInitialized) {
154 // Initialization has not taken place, something is wrong,
155 // don't make things worse.
156 return NS_OK;
157 }
158
159 nsresult rv =
160 GetPathToSpecialDir(NS_APP_USER_PROFILE_50_DIR, mPaths->profileDir);
161 if (NS_FAILED(rv)) {
162 return rv;
163 }
164 rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_LOCAL_50_DIR,
165 mPaths->localProfileDir);
166 if (NS_FAILED(rv)) {
167 return rv;
168 }
169
170 return NS_OK;
171 }
172
173 /**
174 * Perform the part of initialization that can only be
175 * executed on the main thread.
176 */
InitOSFileConstants()177 nsresult OSFileConstantsService::InitOSFileConstants() {
178 MOZ_ASSERT(NS_IsMainThread());
179 if (mInitialized) {
180 return NS_OK;
181 }
182
183 UniquePtr<Paths> paths(new Paths);
184
185 // Initialize paths->libDir
186 nsCOMPtr<nsIFile> file;
187 nsresult rv =
188 NS_GetSpecialDirectory(NS_XPCOM_LIBRARY_FILE, getter_AddRefs(file));
189 if (NS_FAILED(rv)) {
190 return rv;
191 }
192
193 nsCOMPtr<nsIFile> libDir;
194 rv = file->GetParent(getter_AddRefs(libDir));
195 if (NS_FAILED(rv)) {
196 return rv;
197 }
198
199 rv = libDir->GetPath(paths->libDir);
200 if (NS_FAILED(rv)) {
201 return rv;
202 }
203
204 // Setup profileDir and localProfileDir immediately if possible (we
205 // assume that NS_APP_USER_PROFILE_50_DIR and
206 // NS_APP_USER_PROFILE_LOCAL_50_DIR are set simultaneously)
207 rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_50_DIR, paths->profileDir);
208 if (NS_SUCCEEDED(rv)) {
209 rv = GetPathToSpecialDir(NS_APP_USER_PROFILE_LOCAL_50_DIR,
210 paths->localProfileDir);
211 }
212
213 // Otherwise, delay setup of profileDir/localProfileDir until they
214 // become available.
215 if (NS_FAILED(rv)) {
216 nsCOMPtr<nsIObserverService> obsService =
217 do_GetService(NS_OBSERVERSERVICE_CONTRACTID, &rv);
218 if (NS_FAILED(rv)) {
219 return rv;
220 }
221 rv = obsService->AddObserver(this, "profile-do-change", false);
222 if (NS_FAILED(rv)) {
223 return rv;
224 }
225 }
226
227 GetPathToSpecialDir(NS_OS_TEMP_DIR, paths->tmpDir);
228
229 mPaths = std::move(paths);
230
231 // Get the umask from the system-info service.
232 // The property will always be present, but it will be zero on
233 // non-Unix systems.
234 // nsSystemInfo::gUserUmask is initialized by NS_InitXPCOM so we don't need
235 // to initialize the service.
236 mUserUmask = nsSystemInfo::gUserUmask;
237
238 mInitialized = true;
239 return NS_OK;
240 }
241
242 /**
243 * Define a simple read-only property holding an integer.
244 *
245 * @param name The name of the constant. Used both as the JS name for the
246 * constant and to access its value. Must be defined.
247 *
248 * Produces a |ConstantSpec|.
249 */
250 #define INT_CONSTANT(name) \
251 { #name, JS::Int32Value(name) }
252
253 /**
254 * Define a simple read-only property holding an unsigned integer.
255 *
256 * @param name The name of the constant. Used both as the JS name for the
257 * constant and to access its value. Must be defined.
258 *
259 * Produces a |ConstantSpec|.
260 */
261 #define UINT_CONSTANT(name) \
262 { #name, JS::NumberValue(name) }
263
264 /**
265 * End marker for ConstantSpec
266 */
267 #define PROP_END \
268 { nullptr, JS::UndefinedValue() }
269
270 // Define missing constants for Android
271 #if !defined(S_IRGRP)
272 # define S_IXOTH 0001
273 # define S_IWOTH 0002
274 # define S_IROTH 0004
275 # define S_IRWXO 0007
276 # define S_IXGRP 0010
277 # define S_IWGRP 0020
278 # define S_IRGRP 0040
279 # define S_IRWXG 0070
280 # define S_IXUSR 0100
281 # define S_IWUSR 0200
282 # define S_IRUSR 0400
283 # define S_IRWXU 0700
284 #endif // !defined(S_IRGRP)
285
286 /**
287 * The properties defined in libc.
288 *
289 * If you extend this list of properties, please
290 * separate categories ("errors", "open", etc.),
291 * keep properties organized by alphabetical order
292 * and #ifdef-away properties that are not portable.
293 */
294 static const dom::ConstantSpec gLibcProperties[] = {
295 // Arguments for open
296 INT_CONSTANT(O_APPEND),
297 #if defined(O_CLOEXEC)
298 INT_CONSTANT(O_CLOEXEC),
299 #endif // defined(O_CLOEXEC)
300 INT_CONSTANT(O_CREAT),
301 #if defined(O_DIRECTORY)
302 INT_CONSTANT(O_DIRECTORY),
303 #endif // defined(O_DIRECTORY)
304 #if defined(O_EVTONLY)
305 INT_CONSTANT(O_EVTONLY),
306 #endif // defined(O_EVTONLY)
307 INT_CONSTANT(O_EXCL),
308 #if defined(O_EXLOCK)
309 INT_CONSTANT(O_EXLOCK),
310 #endif // defined(O_EXLOCK)
311 #if defined(O_LARGEFILE)
312 INT_CONSTANT(O_LARGEFILE),
313 #endif // defined(O_LARGEFILE)
314 #if defined(O_NOFOLLOW)
315 INT_CONSTANT(O_NOFOLLOW),
316 #endif // defined(O_NOFOLLOW)
317 #if defined(O_NONBLOCK)
318 INT_CONSTANT(O_NONBLOCK),
319 #endif // defined(O_NONBLOCK)
320 INT_CONSTANT(O_RDONLY),
321 INT_CONSTANT(O_RDWR),
322 #if defined(O_RSYNC)
323 INT_CONSTANT(O_RSYNC),
324 #endif // defined(O_RSYNC)
325 #if defined(O_SHLOCK)
326 INT_CONSTANT(O_SHLOCK),
327 #endif // defined(O_SHLOCK)
328 #if defined(O_SYMLINK)
329 INT_CONSTANT(O_SYMLINK),
330 #endif // defined(O_SYMLINK)
331 #if defined(O_SYNC)
332 INT_CONSTANT(O_SYNC),
333 #endif // defined(O_SYNC)
334 INT_CONSTANT(O_TRUNC),
335 INT_CONSTANT(O_WRONLY),
336
337 #if defined(FD_CLOEXEC)
338 INT_CONSTANT(FD_CLOEXEC),
339 #endif // defined(FD_CLOEXEC)
340
341 #if defined(AT_EACCESS)
342 INT_CONSTANT(AT_EACCESS),
343 #endif // defined(AT_EACCESS)
344 #if defined(AT_FDCWD)
345 INT_CONSTANT(AT_FDCWD),
346 #endif // defined(AT_FDCWD)
347 #if defined(AT_SYMLINK_NOFOLLOW)
348 INT_CONSTANT(AT_SYMLINK_NOFOLLOW),
349 #endif // defined(AT_SYMLINK_NOFOLLOW)
350
351 #if defined(POSIX_FADV_SEQUENTIAL)
352 INT_CONSTANT(POSIX_FADV_SEQUENTIAL),
353 #endif // defined(POSIX_FADV_SEQUENTIAL)
354
355 // access
356 #if defined(F_OK)
357 INT_CONSTANT(F_OK),
358 INT_CONSTANT(R_OK),
359 INT_CONSTANT(W_OK),
360 INT_CONSTANT(X_OK),
361 #endif // defined(F_OK)
362
363 // modes
364 INT_CONSTANT(S_IRGRP),
365 INT_CONSTANT(S_IROTH),
366 INT_CONSTANT(S_IRUSR),
367 INT_CONSTANT(S_IRWXG),
368 INT_CONSTANT(S_IRWXO),
369 INT_CONSTANT(S_IRWXU),
370 INT_CONSTANT(S_IWGRP),
371 INT_CONSTANT(S_IWOTH),
372 INT_CONSTANT(S_IWUSR),
373 INT_CONSTANT(S_IXOTH),
374 INT_CONSTANT(S_IXGRP),
375 INT_CONSTANT(S_IXUSR),
376
377 // seek
378 INT_CONSTANT(SEEK_CUR),
379 INT_CONSTANT(SEEK_END),
380 INT_CONSTANT(SEEK_SET),
381
382 #if defined(XP_UNIX)
383 // poll
384 INT_CONSTANT(POLLERR),
385 INT_CONSTANT(POLLHUP),
386 INT_CONSTANT(POLLIN),
387 INT_CONSTANT(POLLNVAL),
388 INT_CONSTANT(POLLOUT),
389
390 // wait
391 # if defined(WNOHANG)
392 INT_CONSTANT(WNOHANG),
393 # endif // defined(WNOHANG)
394
395 // fcntl command values
396 INT_CONSTANT(F_GETLK),
397 INT_CONSTANT(F_SETFD),
398 INT_CONSTANT(F_SETFL),
399 INT_CONSTANT(F_SETLK),
400 INT_CONSTANT(F_SETLKW),
401
402 // flock type values
403 INT_CONSTANT(F_RDLCK),
404 INT_CONSTANT(F_WRLCK),
405 INT_CONSTANT(F_UNLCK),
406
407 // splice
408 # if defined(SPLICE_F_MOVE)
409 INT_CONSTANT(SPLICE_F_MOVE),
410 # endif // defined(SPLICE_F_MOVE)
411 # if defined(SPLICE_F_NONBLOCK)
412 INT_CONSTANT(SPLICE_F_NONBLOCK),
413 # endif // defined(SPLICE_F_NONBLOCK)
414 # if defined(SPLICE_F_MORE)
415 INT_CONSTANT(SPLICE_F_MORE),
416 # endif // defined(SPLICE_F_MORE)
417 # if defined(SPLICE_F_GIFT)
418 INT_CONSTANT(SPLICE_F_GIFT),
419 # endif // defined(SPLICE_F_GIFT)
420 #endif // defined(XP_UNIX)
421 // copyfile
422 #if defined(COPYFILE_DATA)
423 INT_CONSTANT(COPYFILE_DATA),
424 INT_CONSTANT(COPYFILE_EXCL),
425 INT_CONSTANT(COPYFILE_XATTR),
426 INT_CONSTANT(COPYFILE_STAT),
427 INT_CONSTANT(COPYFILE_ACL),
428 INT_CONSTANT(COPYFILE_MOVE),
429 #endif // defined(COPYFILE_DATA)
430
431 // error values
432 INT_CONSTANT(EACCES),
433 INT_CONSTANT(EAGAIN),
434 INT_CONSTANT(EBADF),
435 INT_CONSTANT(EEXIST),
436 INT_CONSTANT(EFAULT),
437 INT_CONSTANT(EFBIG),
438 INT_CONSTANT(EINVAL),
439 INT_CONSTANT(EINTR),
440 INT_CONSTANT(EIO),
441 INT_CONSTANT(EISDIR),
442 #if defined(ELOOP) // not defined with VC9
443 INT_CONSTANT(ELOOP),
444 #endif // defined(ELOOP)
445 INT_CONSTANT(EMFILE),
446 INT_CONSTANT(ENAMETOOLONG),
447 INT_CONSTANT(ENFILE),
448 INT_CONSTANT(ENOENT),
449 INT_CONSTANT(ENOMEM),
450 INT_CONSTANT(ENOSPC),
451 INT_CONSTANT(ENOTDIR),
452 INT_CONSTANT(ENXIO),
453 #if defined(EOPNOTSUPP) // not defined with VC 9
454 INT_CONSTANT(EOPNOTSUPP),
455 #endif // defined(EOPNOTSUPP)
456 #if defined(EOVERFLOW) // not defined with VC 9
457 INT_CONSTANT(EOVERFLOW),
458 #endif // defined(EOVERFLOW)
459 INT_CONSTANT(EPERM),
460 INT_CONSTANT(ERANGE),
461 INT_CONSTANT(ENOSYS),
462 #if defined(ETIMEDOUT) // not defined with VC 9
463 INT_CONSTANT(ETIMEDOUT),
464 #endif // defined(ETIMEDOUT)
465 #if defined(EWOULDBLOCK) // not defined with VC 9
466 INT_CONSTANT(EWOULDBLOCK),
467 #endif // defined(EWOULDBLOCK)
468 INT_CONSTANT(EXDEV),
469
470 #if defined(DT_UNKNOWN)
471 // Constants for |readdir|
472 INT_CONSTANT(DT_UNKNOWN),
473 INT_CONSTANT(DT_FIFO),
474 INT_CONSTANT(DT_CHR),
475 INT_CONSTANT(DT_DIR),
476 INT_CONSTANT(DT_BLK),
477 INT_CONSTANT(DT_REG),
478 INT_CONSTANT(DT_LNK),
479 INT_CONSTANT(DT_SOCK),
480 #endif // defined(DT_UNKNOWN)
481
482 #if defined(XP_UNIX)
483 // Constants for |stat|
484 INT_CONSTANT(S_IFMT),
485 INT_CONSTANT(S_IFIFO),
486 INT_CONSTANT(S_IFCHR),
487 INT_CONSTANT(S_IFDIR),
488 INT_CONSTANT(S_IFBLK),
489 INT_CONSTANT(S_IFREG),
490 INT_CONSTANT(S_IFLNK), // not defined on minGW
491 INT_CONSTANT(S_IFSOCK), // not defined on minGW
492 #endif // defined(XP_UNIX)
493
494 INT_CONSTANT(PATH_MAX),
495
496 #if defined(XP_LINUX)
497 // prctl options
498 INT_CONSTANT(PR_CAPBSET_READ),
499 #endif
500
501 // Constants used to define data structures
502 //
503 // Many data structures have different fields/sizes/etc. on
504 // various OSes / versions of the same OS / platforms. For these
505 // data structures, we need to compute and export from C the size
506 // and, if necessary, the offset of fields, so as to be able to
507 // define the structure in JS.
508
509 #if defined(XP_UNIX)
510 // The size of |mode_t|.
511 {"OSFILE_SIZEOF_MODE_T", JS::Int32Value(sizeof(mode_t))},
512
513 // The size of |gid_t|.
514 {"OSFILE_SIZEOF_GID_T", JS::Int32Value(sizeof(gid_t))},
515
516 // The size of |uid_t|.
517 {"OSFILE_SIZEOF_UID_T", JS::Int32Value(sizeof(uid_t))},
518
519 // The size of |time_t|.
520 {"OSFILE_SIZEOF_TIME_T", JS::Int32Value(sizeof(time_t))},
521
522 // The size of |fsblkcnt_t|.
523 {"OSFILE_SIZEOF_FSBLKCNT_T", JS::Int32Value(sizeof(fsblkcnt_t))},
524
525 # if !defined(ANDROID)
526 // The size of |posix_spawn_file_actions_t|.
527 {"OSFILE_SIZEOF_POSIX_SPAWN_FILE_ACTIONS_T",
528 JS::Int32Value(sizeof(posix_spawn_file_actions_t))},
529
530 // The size of |posix_spawnattr_t|.
531 {"OSFILE_SIZEOF_POSIX_SPAWNATTR_T",
532 JS::Int32Value(sizeof(posix_spawnattr_t))},
533 # endif // !defined(ANDROID)
534
535 // Defining |dirent|.
536 // Size
537 {"OSFILE_SIZEOF_DIRENT", JS::Int32Value(sizeof(dirent))},
538
539 // Defining |flock|.
540 {"OSFILE_SIZEOF_FLOCK", JS::Int32Value(sizeof(struct flock))},
541 {"OSFILE_OFFSETOF_FLOCK_L_START",
542 JS::Int32Value(offsetof(struct flock, l_start))},
543 {"OSFILE_OFFSETOF_FLOCK_L_LEN",
544 JS::Int32Value(offsetof(struct flock, l_len))},
545 {"OSFILE_OFFSETOF_FLOCK_L_PID",
546 JS::Int32Value(offsetof(struct flock, l_pid))},
547 {"OSFILE_OFFSETOF_FLOCK_L_TYPE",
548 JS::Int32Value(offsetof(struct flock, l_type))},
549 {"OSFILE_OFFSETOF_FLOCK_L_WHENCE",
550 JS::Int32Value(offsetof(struct flock, l_whence))},
551
552 // Offset of field |d_name|.
553 {"OSFILE_OFFSETOF_DIRENT_D_NAME",
554 JS::Int32Value(offsetof(struct dirent, d_name))},
555 // An upper bound to the length of field |d_name| of struct |dirent|.
556 // (may not be exact, depending on padding).
557 {"OSFILE_SIZEOF_DIRENT_D_NAME",
558 JS::Int32Value(sizeof(struct dirent) - offsetof(struct dirent, d_name))},
559
560 // Defining |timeval|.
561 {"OSFILE_SIZEOF_TIMEVAL", JS::Int32Value(sizeof(struct timeval))},
562 {"OSFILE_OFFSETOF_TIMEVAL_TV_SEC",
563 JS::Int32Value(offsetof(struct timeval, tv_sec))},
564 {"OSFILE_OFFSETOF_TIMEVAL_TV_USEC",
565 JS::Int32Value(offsetof(struct timeval, tv_usec))},
566
567 # if defined(DT_UNKNOWN)
568 // Position of field |d_type| in |dirent|
569 // Not strictly posix, but seems defined on all platforms
570 // except mingw32.
571 {"OSFILE_OFFSETOF_DIRENT_D_TYPE",
572 JS::Int32Value(offsetof(struct dirent, d_type))},
573 # endif // defined(DT_UNKNOWN)
574
575 // Under MacOS X and BSDs, |dirfd| is a macro rather than a
576 // function, so we need a little help to get it to work
577 # if defined(dirfd)
578 {"OSFILE_SIZEOF_DIR", JS::Int32Value(sizeof(DIR))},
579
580 {"OSFILE_OFFSETOF_DIR_DD_FD", JS::Int32Value(offsetof(DIR, __dd_fd))},
581 # endif
582
583 // Defining |stat|
584
585 {"OSFILE_SIZEOF_STAT", JS::Int32Value(sizeof(struct stat))},
586
587 {"OSFILE_OFFSETOF_STAT_ST_MODE",
588 JS::Int32Value(offsetof(struct stat, st_mode))},
589 {"OSFILE_OFFSETOF_STAT_ST_UID",
590 JS::Int32Value(offsetof(struct stat, st_uid))},
591 {"OSFILE_OFFSETOF_STAT_ST_GID",
592 JS::Int32Value(offsetof(struct stat, st_gid))},
593 {"OSFILE_OFFSETOF_STAT_ST_SIZE",
594 JS::Int32Value(offsetof(struct stat, st_size))},
595
596 # if defined(HAVE_ST_ATIMESPEC)
597 {"OSFILE_OFFSETOF_STAT_ST_ATIME",
598 JS::Int32Value(offsetof(struct stat, st_atimespec))},
599 {"OSFILE_OFFSETOF_STAT_ST_MTIME",
600 JS::Int32Value(offsetof(struct stat, st_mtimespec))},
601 {"OSFILE_OFFSETOF_STAT_ST_CTIME",
602 JS::Int32Value(offsetof(struct stat, st_ctimespec))},
603 # else
604 {"OSFILE_OFFSETOF_STAT_ST_ATIME",
605 JS::Int32Value(offsetof(struct stat, st_atime))},
606 {"OSFILE_OFFSETOF_STAT_ST_MTIME",
607 JS::Int32Value(offsetof(struct stat, st_mtime))},
608 {"OSFILE_OFFSETOF_STAT_ST_CTIME",
609 JS::Int32Value(offsetof(struct stat, st_ctime))},
610 # endif // defined(HAVE_ST_ATIME)
611
612 // Several OSes have a birthtime field. For the moment, supporting only Darwin.
613 # if defined(_DARWIN_FEATURE_64_BIT_INODE)
614 {"OSFILE_OFFSETOF_STAT_ST_BIRTHTIME",
615 JS::Int32Value(offsetof(struct stat, st_birthtime))},
616 # endif // defined(_DARWIN_FEATURE_64_BIT_INODE)
617
618 // Defining |statvfs|
619
620 {"OSFILE_SIZEOF_STATVFS", JS::Int32Value(sizeof(struct statvfs))},
621
622 // We have no guarantee how big "f_frsize" is, so we have to calculate that.
623 {"OSFILE_SIZEOF_STATVFS_F_FRSIZE",
624 JS::Int32Value(DOM_SIZEOF_MEMBER(struct statvfs, f_frsize))},
625 {"OSFILE_OFFSETOF_STATVFS_F_FRSIZE",
626 JS::Int32Value(offsetof(struct statvfs, f_frsize))},
627 {"OSFILE_OFFSETOF_STATVFS_F_BAVAIL",
628 JS::Int32Value(offsetof(struct statvfs, f_bavail))},
629
630 #endif // defined(XP_UNIX)
631
632 // System configuration
633
634 // Under MacOSX, to avoid using deprecated functions that do not
635 // match the constants we define in this object (including
636 // |sizeof|/|offsetof| stuff, but not only), for a number of
637 // functions, we need to use functions with a $INODE64 suffix.
638 // That is true on Intel-based mac when the _DARWIN_FEATURE_64_BIT_INODE
639 // macro is set. But not on Apple Silicon.
640 #if defined(_DARWIN_FEATURE_64_BIT_INODE) && !defined(__aarch64__)
641 {"_DARWIN_INODE64_SYMBOLS", JS::Int32Value(1)},
642 #endif // defined(_DARWIN_FEATURE_64_BIT_INODE)
643
644 // Similar feature for Linux
645 #if defined(_STAT_VER)
646 INT_CONSTANT(_STAT_VER),
647 #endif // defined(_STAT_VER)
648
649 PROP_END};
650
651 #if defined(XP_WIN)
652 /**
653 * The properties defined in windows.h.
654 *
655 * If you extend this list of properties, please
656 * separate categories ("errors", "open", etc.),
657 * keep properties organized by alphabetical order
658 * and #ifdef-away properties that are not portable.
659 */
660 static const dom::ConstantSpec gWinProperties[] = {
661 // FormatMessage flags
662 INT_CONSTANT(FORMAT_MESSAGE_FROM_SYSTEM),
663 INT_CONSTANT(FORMAT_MESSAGE_IGNORE_INSERTS),
664
665 // The max length of paths
666 INT_CONSTANT(MAX_PATH),
667
668 // CreateFile desired access
669 INT_CONSTANT(GENERIC_ALL),
670 INT_CONSTANT(GENERIC_EXECUTE),
671 INT_CONSTANT(GENERIC_READ),
672 INT_CONSTANT(GENERIC_WRITE),
673
674 // CreateFile share mode
675 INT_CONSTANT(FILE_SHARE_DELETE),
676 INT_CONSTANT(FILE_SHARE_READ),
677 INT_CONSTANT(FILE_SHARE_WRITE),
678
679 // CreateFile creation disposition
680 INT_CONSTANT(CREATE_ALWAYS),
681 INT_CONSTANT(CREATE_NEW),
682 INT_CONSTANT(OPEN_ALWAYS),
683 INT_CONSTANT(OPEN_EXISTING),
684 INT_CONSTANT(TRUNCATE_EXISTING),
685
686 // CreateFile attributes
687 INT_CONSTANT(FILE_ATTRIBUTE_ARCHIVE),
688 INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
689 INT_CONSTANT(FILE_ATTRIBUTE_HIDDEN),
690 INT_CONSTANT(FILE_ATTRIBUTE_NORMAL),
691 INT_CONSTANT(FILE_ATTRIBUTE_READONLY),
692 INT_CONSTANT(FILE_ATTRIBUTE_REPARSE_POINT),
693 INT_CONSTANT(FILE_ATTRIBUTE_SYSTEM),
694 INT_CONSTANT(FILE_ATTRIBUTE_TEMPORARY),
695 INT_CONSTANT(FILE_FLAG_BACKUP_SEMANTICS),
696
697 // CreateFile error constant
698 {"INVALID_HANDLE_VALUE", JS::Int32Value(INT_PTR(INVALID_HANDLE_VALUE))},
699
700 // CreateFile flags
701 INT_CONSTANT(FILE_FLAG_DELETE_ON_CLOSE),
702
703 // SetFilePointer methods
704 INT_CONSTANT(FILE_BEGIN),
705 INT_CONSTANT(FILE_CURRENT),
706 INT_CONSTANT(FILE_END),
707
708 // SetFilePointer error constant
709 UINT_CONSTANT(INVALID_SET_FILE_POINTER),
710
711 // File attributes
712 INT_CONSTANT(FILE_ATTRIBUTE_DIRECTORY),
713
714 // MoveFile flags
715 INT_CONSTANT(MOVEFILE_COPY_ALLOWED),
716 INT_CONSTANT(MOVEFILE_REPLACE_EXISTING),
717
718 // GetFileAttributes error constant
719 INT_CONSTANT(INVALID_FILE_ATTRIBUTES),
720
721 // GetNamedSecurityInfo and SetNamedSecurityInfo constants
722 INT_CONSTANT(UNPROTECTED_DACL_SECURITY_INFORMATION),
723 INT_CONSTANT(SE_FILE_OBJECT),
724 INT_CONSTANT(DACL_SECURITY_INFORMATION),
725
726 // Errors
727 INT_CONSTANT(ERROR_INVALID_HANDLE),
728 INT_CONSTANT(ERROR_ACCESS_DENIED),
729 INT_CONSTANT(ERROR_DIR_NOT_EMPTY),
730 INT_CONSTANT(ERROR_FILE_EXISTS),
731 INT_CONSTANT(ERROR_ALREADY_EXISTS),
732 INT_CONSTANT(ERROR_FILE_NOT_FOUND),
733 INT_CONSTANT(ERROR_NO_MORE_FILES),
734 INT_CONSTANT(ERROR_PATH_NOT_FOUND),
735 INT_CONSTANT(ERROR_BAD_ARGUMENTS),
736 INT_CONSTANT(ERROR_SHARING_VIOLATION),
737 INT_CONSTANT(ERROR_NOT_SUPPORTED),
738
739 PROP_END};
740 #endif // defined(XP_WIN)
741
742 /**
743 * Get a field of an object as an object.
744 *
745 * If the field does not exist, create it. If it exists but is not an
746 * object, throw a JS error.
747 */
GetOrCreateObjectProperty(JSContext * cx,JS::Handle<JSObject * > aObject,const char * aProperty)748 JSObject* GetOrCreateObjectProperty(JSContext* cx,
749 JS::Handle<JSObject*> aObject,
750 const char* aProperty) {
751 JS::Rooted<JS::Value> val(cx);
752 if (!JS_GetProperty(cx, aObject, aProperty, &val)) {
753 return nullptr;
754 }
755 if (!val.isUndefined()) {
756 if (val.isObject()) {
757 return &val.toObject();
758 }
759
760 JS_ReportErrorNumberASCII(cx, js::GetErrorMessage, nullptr,
761 JSMSG_UNEXPECTED_TYPE, aProperty,
762 "not an object");
763 return nullptr;
764 }
765 return JS_DefineObject(cx, aObject, aProperty, nullptr, JSPROP_ENUMERATE);
766 }
767
768 /**
769 * Set a property of an object from a nsString.
770 *
771 * If the nsString is void (i.e. IsVoid is true), do nothing.
772 */
SetStringProperty(JSContext * cx,JS::Handle<JSObject * > aObject,const char * aProperty,const nsString aValue)773 bool SetStringProperty(JSContext* cx, JS::Handle<JSObject*> aObject,
774 const char* aProperty, const nsString aValue) {
775 if (aValue.IsVoid()) {
776 return true;
777 }
778 JSString* strValue = JS_NewUCStringCopyZ(cx, aValue.get());
779 NS_ENSURE_TRUE(strValue, false);
780 JS::Rooted<JS::Value> valValue(cx, JS::StringValue(strValue));
781 return JS_SetProperty(cx, aObject, aProperty, valValue);
782 }
783
784 /**
785 * Define OS-specific constants.
786 *
787 * This function creates or uses JS object |OS.Constants| to store
788 * all its constants.
789 */
DefineOSFileConstants(JSContext * aCx,JS::Handle<JSObject * > aGlobal)790 bool OSFileConstantsService::DefineOSFileConstants(
791 JSContext* aCx, JS::Handle<JSObject*> aGlobal) {
792 if (!mInitialized) {
793 JS_ReportErrorNumberASCII(aCx, js::GetErrorMessage, nullptr,
794 JSMSG_CANT_OPEN, "OSFileConstants",
795 "initialization has failed");
796 return false;
797 }
798
799 JS::Rooted<JSObject*> objOS(aCx);
800 if (!(objOS = GetOrCreateObjectProperty(aCx, aGlobal, "OS"))) {
801 return false;
802 }
803 JS::Rooted<JSObject*> objConstants(aCx);
804 if (!(objConstants = GetOrCreateObjectProperty(aCx, objOS, "Constants"))) {
805 return false;
806 }
807
808 // Build OS.Constants.libc
809
810 JS::Rooted<JSObject*> objLibc(aCx);
811 if (!(objLibc = GetOrCreateObjectProperty(aCx, objConstants, "libc"))) {
812 return false;
813 }
814 if (!dom::DefineConstants(aCx, objLibc, gLibcProperties)) {
815 return false;
816 }
817
818 #if defined(XP_WIN)
819 // Build OS.Constants.Win
820
821 JS::Rooted<JSObject*> objWin(aCx);
822 if (!(objWin = GetOrCreateObjectProperty(aCx, objConstants, "Win"))) {
823 return false;
824 }
825 if (!dom::DefineConstants(aCx, objWin, gWinProperties)) {
826 return false;
827 }
828 #endif // defined(XP_WIN)
829
830 // Build OS.Constants.Sys
831
832 JS::Rooted<JSObject*> objSys(aCx);
833 if (!(objSys = GetOrCreateObjectProperty(aCx, objConstants, "Sys"))) {
834 return false;
835 }
836
837 nsCOMPtr<nsIXULRuntime> runtime =
838 do_GetService(XULRUNTIME_SERVICE_CONTRACTID);
839 if (runtime) {
840 nsAutoCString os;
841 DebugOnly<nsresult> rv = runtime->GetOS(os);
842 MOZ_ASSERT(NS_SUCCEEDED(rv));
843
844 JSString* strVersion = JS_NewStringCopyZ(aCx, os.get());
845 if (!strVersion) {
846 return false;
847 }
848
849 JS::Rooted<JS::Value> valVersion(aCx, JS::StringValue(strVersion));
850 if (!JS_SetProperty(aCx, objSys, "Name", valVersion)) {
851 return false;
852 }
853 }
854
855 #if defined(DEBUG)
856 JS::Rooted<JS::Value> valDebug(aCx, JS::TrueValue());
857 if (!JS_SetProperty(aCx, objSys, "DEBUG", valDebug)) {
858 return false;
859 }
860 #endif
861
862 #if defined(HAVE_64BIT_BUILD)
863 JS::Rooted<JS::Value> valBits(aCx, JS::Int32Value(64));
864 #else
865 JS::Rooted<JS::Value> valBits(aCx, JS::Int32Value(32));
866 #endif // defined (HAVE_64BIT_BUILD)
867 if (!JS_SetProperty(aCx, objSys, "bits", valBits)) {
868 return false;
869 }
870
871 if (!JS_DefineProperty(
872 aCx, objSys, "umask", mUserUmask,
873 JSPROP_ENUMERATE | JSPROP_READONLY | JSPROP_PERMANENT)) {
874 return false;
875 }
876
877 // Build OS.Constants.Path
878
879 JS::Rooted<JSObject*> objPath(aCx);
880 if (!(objPath = GetOrCreateObjectProperty(aCx, objConstants, "Path"))) {
881 return false;
882 }
883
884 // Locate libxul
885 // Note that we don't actually provide the full path, only the name of the
886 // library, which is sufficient to link to the library using js-ctypes.
887
888 #if defined(XP_MACOSX)
889 // Under MacOS X, for some reason, libxul is called simply "XUL",
890 // and we need to provide the full path.
891 nsAutoString libxul;
892 libxul.Append(mPaths->libDir);
893 libxul.AppendLiteral("/XUL");
894 #else
895 // On other platforms, libxul is a library "xul" with regular
896 // library prefix/suffix.
897 nsAutoString libxul;
898 libxul.AppendLiteral(MOZ_DLL_PREFIX);
899 libxul.AppendLiteral("xul");
900 libxul.AppendLiteral(MOZ_DLL_SUFFIX);
901 #endif // defined(XP_MACOSX)
902
903 if (!SetStringProperty(aCx, objPath, "libxul", libxul)) {
904 return false;
905 }
906
907 if (!SetStringProperty(aCx, objPath, "libDir", mPaths->libDir)) {
908 return false;
909 }
910
911 if (!SetStringProperty(aCx, objPath, "tmpDir", mPaths->tmpDir)) {
912 return false;
913 }
914
915 // Configure profileDir only if it is available at this stage
916 if (!mPaths->profileDir.IsVoid() &&
917 !SetStringProperty(aCx, objPath, "profileDir", mPaths->profileDir)) {
918 return false;
919 }
920
921 // Configure localProfileDir only if it is available at this stage
922 if (!mPaths->localProfileDir.IsVoid() &&
923 !SetStringProperty(aCx, objPath, "localProfileDir",
924 mPaths->localProfileDir)) {
925 return false;
926 }
927
928 // sqlite3 is linked from different places depending on the platform
929 nsAutoString libsqlite3;
930 #if defined(ANDROID)
931 // On Android, we use the system's libsqlite3
932 libsqlite3.AppendLiteral(MOZ_DLL_PREFIX);
933 libsqlite3.AppendLiteral("sqlite3");
934 libsqlite3.AppendLiteral(MOZ_DLL_SUFFIX);
935 #elif defined(XP_WIN)
936 // On Windows, for some reason, this is part of nss3.dll
937 libsqlite3.AppendLiteral(MOZ_DLL_PREFIX);
938 libsqlite3.AppendLiteral("nss3");
939 libsqlite3.AppendLiteral(MOZ_DLL_SUFFIX);
940 #else
941 // On other platforms, we link sqlite3 into libxul
942 libsqlite3 = libxul;
943 #endif // defined(ANDROID) || defined(XP_WIN)
944
945 if (!SetStringProperty(aCx, objPath, "libsqlite3", libsqlite3)) {
946 return false;
947 }
948
949 return true;
950 }
951
NS_IMPL_ISUPPORTS(OSFileConstantsService,nsIOSFileConstantsService,nsIObserver)952 NS_IMPL_ISUPPORTS(OSFileConstantsService, nsIOSFileConstantsService,
953 nsIObserver)
954
955 /* static */
956 already_AddRefed<OSFileConstantsService> OSFileConstantsService::GetOrCreate() {
957 if (!gInstance) {
958 MOZ_ASSERT(NS_IsMainThread());
959
960 RefPtr<OSFileConstantsService> service = new OSFileConstantsService();
961 nsresult rv = service->InitOSFileConstants();
962 if (NS_WARN_IF(NS_FAILED(rv))) {
963 return nullptr;
964 }
965
966 gInstance = std::move(service);
967 ClearOnShutdown(&gInstance);
968 }
969
970 RefPtr<OSFileConstantsService> copy = gInstance;
971 return copy.forget();
972 }
973
OSFileConstantsService()974 OSFileConstantsService::OSFileConstantsService()
975 : mInitialized(false), mUserUmask(0) {
976 MOZ_ASSERT(NS_IsMainThread());
977 }
978
~OSFileConstantsService()979 OSFileConstantsService::~OSFileConstantsService() {
980 MOZ_ASSERT(NS_IsMainThread());
981 }
982
983 NS_IMETHODIMP
Init(JSContext * aCx)984 OSFileConstantsService::Init(JSContext* aCx) {
985 MOZ_ASSERT(NS_IsMainThread());
986
987 nsresult rv = InitOSFileConstants();
988 if (NS_FAILED(rv)) {
989 return rv;
990 }
991
992 mozJSComponentLoader* loader = mozJSComponentLoader::Get();
993 JS::Rooted<JSObject*> targetObj(aCx);
994 loader->FindTargetObject(aCx, &targetObj);
995
996 if (!DefineOSFileConstants(aCx, targetObj)) {
997 return NS_ERROR_FAILURE;
998 }
999
1000 return NS_OK;
1001 }
1002
1003 } // namespace mozilla
1004