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