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