Bug 770538 - dirfd, MacOS X version. r=froydnj
authorDavid Rajchenbach-Teller <dteller@mozilla.com>
Tue, 30 Oct 2012 11:34:49 -0400
changeset 111924 0a1f5facc2aeb858b5ba472d40d7179aeaeb33a9
parent 111923 d25ef46858dc52aa0f95b4b217e5f828c7d44bb2
child 111925 1c6b13fd3b6ad6826d6aeb8c27e293d7d9786696
push id93
push usernmatsakis@mozilla.com
push dateWed, 31 Oct 2012 21:26:57 +0000
reviewersfroydnj
bugs770538
milestone19.0a1
Bug 770538 - dirfd, MacOS X version. r=froydnj
dom/system/OSFileConstants.cpp
toolkit/components/osfile/osfile_unix_back.jsm
--- a/dom/system/OSFileConstants.cpp
+++ b/dom/system/OSFileConstants.cpp
@@ -375,16 +375,23 @@ static dom::ConstantSpec gLibcProperties
 
 #if defined(DT_UNKNOWN)
   // Position of field |d_type| in |dirent|
   // Not strictly posix, but seems defined on all platforms
   // except mingw32.
   { "OSFILE_OFFSETOF_DIRENT_D_TYPE", INT_TO_JSVAL(offsetof (struct dirent, d_type)) },
 #endif // defined(DT_UNKNOWN)
 
+  // Under MacOS X, |dirfd| is a macro rather than a function, so we
+  // need a little help to get it to work
+#if defined(dirfd)
+  { "OSFILE_SIZEOF_DIR", INT_TO_JSVAL(sizeof (DIR)) },
+
+  { "OSFILE_OFFSETOF_DIR_DD_FD", INT_TO_JSVAL(offsetof (DIR, __dd_fd)) },
+#endif
 
   // Defining |stat|
 
   { "OSFILE_SIZEOF_STAT", INT_TO_JSVAL(sizeof (struct stat)) },
 
   { "OSFILE_OFFSETOF_STAT_ST_MODE", INT_TO_JSVAL(offsetof (struct stat, st_mode)) },
   { "OSFILE_OFFSETOF_STAT_ST_UID", INT_TO_JSVAL(offsetof (struct stat, st_uid)) },
   { "OSFILE_OFFSETOF_STAT_ST_GID", INT_TO_JSVAL(offsetof (struct stat, st_gid)) },
--- a/toolkit/components/osfile/osfile_unix_back.jsm
+++ b/toolkit/components/osfile/osfile_unix_back.jsm
@@ -103,29 +103,16 @@
          Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_GID_T).withName("gid_t");
 
        /**
         * Type |time_t|
         */
        Types.time_t =
          Types.intn_t(OS.Constants.libc.OSFILE_SIZEOF_TIME_T).withName("time_t");
 
-       Types.DIR =
-         new Type("DIR",
-                  ctypes.StructType("DIR"));
-
-       Types.null_or_DIR_ptr =
-         Types.DIR.out_ptr.withName("null_or_DIR*");
-       Types.null_or_DIR_ptr.importFromC = function importFromC(dir) {
-         if (dir == null || dir.isNull()) {
-           return null;
-         }
-         return ctypes.CDataFinalizer(dir, _close_dir);
-       };
-
        // Structure |dirent|
        // Building this type is rather complicated, as its layout varies between
        // variants of Unix. For this reason, we rely on a number of constants
        // (computed in C from the C data structures) that give us the layout.
        // The structure we compute looks like
        //  { int8_t[...] before_d_type; // ignored content
        //    int8_t      d_type       ;
        //    int8_t[...] before_d_name; // ignored content
@@ -170,16 +157,47 @@
          stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_CTIME,
                           "st_ctime", Types.time_t.implementation);
 
          stat.add_field_at(OS.Constants.libc.OSFILE_OFFSETOF_STAT_ST_SIZE,
                         "st_size", Types.size_t.implementation);
          Types.stat = stat.getType();
        }
 
+       // Structure |DIR|
+       if ("OSFILE_SIZEOF_DIR" in OS.Constants.libc) {
+         // On platforms for which we need to access the fields of DIR
+         // directly (e.g. because certain functions are implemented
+         // as macros), we need to define DIR as a hollow structure.
+         let DIR = new OS.Shared.HollowStructure(
+           "DIR",
+           OS.Constants.libc.OSFILE_SIZEOF_DIR);
+
+         DIR.add_field_at(
+           OS.Constants.libc.OSFILE_OFFSETOF_DIR_DD_FD,
+           "dd_fd",
+           Types.fd.implementation);
+
+         Types.DIR = DIR.getType();
+       } else {
+         // On other platforms, we keep DIR as a blackbox
+         Types.DIR =
+           new Type("DIR",
+             ctypes.StructType("DIR"));
+       }
+
+       Types.null_or_DIR_ptr =
+         Types.DIR.out_ptr.withName("null_or_DIR*");
+       Types.null_or_DIR_ptr.importFromC = function importFromC(dir) {
+         if (dir == null || dir.isNull()) {
+           return null;
+         }
+         return ctypes.CDataFinalizer(dir, _close_dir);
+       };
+
        // Declare libc functions as functions of |OS.Unix.File|
 
        // Finalizer-related functions
        let _close = UnixFile._close =
          libc.declare("close", ctypes.default_abi,
                         /*return */ctypes.int,
                         /*fd*/     ctypes.int);
 
@@ -236,20 +254,29 @@
                     /*state*/  Types.void_t.in_ptr, // Ignored atm
                     /*flags*/  Types.uint32_t);
 
        UnixFile.dup =
          declareFFI("dup", ctypes.default_abi,
                     /*return*/ Types.negativeone_or_fd,
                     /*fd*/     Types.fd);
 
-       UnixFile.dirfd =
-         declareFFI("dirfd", ctypes.default_abi,
-                    /*return*/ Types.negativeone_or_fd,
-                    /*dir*/    Types.null_or_DIR_ptr);
+       if ("OSFILE_SIZEOF_DIR" in OS.Constants.libc) {
+         // On platforms for which |dirfd| is a macro
+         UnixFile.dirfd =
+           function dirfd(DIRp) {
+             return Types.DIR.in_ptr.implementation(DIRp).contents.dd_fd;
+           };
+       } else {
+         // On platforms for which |dirfd| is a function
+         UnixFile.dirfd =
+           declareFFI("dirfd", ctypes.default_abi,
+                      /*return*/ Types.negativeone_or_fd,
+                      /*dir*/    Types.DIR.in_ptr);
+       }
 
        UnixFile.chdir =
          declareFFI("chdir", ctypes.default_abi,
                     /*return*/ Types.negativeone_or_nothing,
                     /*path*/   Types.path);
 
        UnixFile.fchdir =
          declareFFI("fchdir", ctypes.default_abi,