Coverage Report

Created: 2018-09-25 14:53

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