1/* This Source Code Form is subject to the terms of the Mozilla Public
2 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
3 * You can obtain one at http://mozilla.org/MPL/2.0/. */
4
5{
6  if (typeof Components != "undefined") {
7    // We do not wish osfile_unix_back.jsm to be used directly as a main thread
8    // module yet. When time comes, it will be loaded by a combination of
9    // a main thread front-end/worker thread implementation that makes sure
10    // that we are not executing synchronous IO code in the main thread.
11
12    throw new Error("osfile_unix_back.jsm cannot be used from the main thread yet");
13  }
14  (function(exports) {
15     "use strict";
16     if (exports.OS && exports.OS.Unix && exports.OS.Unix.File) {
17       return; // Avoid double initialization
18     }
19
20     let SharedAll =
21       require("resource://gre/modules/osfile/osfile_shared_allthreads.jsm");
22     let SysAll =
23       require("resource://gre/modules/osfile/osfile_unix_allthreads.jsm");
24     let LOG = SharedAll.LOG.bind(SharedAll, "Unix", "back");
25     let libc = SysAll.libc;
26     let Const = SharedAll.Constants.libc;
27
28     /**
29      * Initialize the Unix module.
30      *
31      * @param {function=} declareFFI
32      */
33     // FIXME: Both |init| and |aDeclareFFI| are deprecated, we should remove them
34     let init = function init(aDeclareFFI) {
35       let declareFFI;
36       if (aDeclareFFI) {
37         declareFFI = aDeclareFFI.bind(null, libc);
38       } else {
39         declareFFI = SysAll.declareFFI;
40       }
41       let declareLazyFFI = SharedAll.declareLazyFFI;
42
43       // Initialize types that require additional OS-specific
44       // support - either finalization or matching against
45       // OS-specific constants.
46       let Type = Object.create(SysAll.Type);
47       let SysFile = exports.OS.Unix.File = { Type: Type };
48
49       /**
50        * A file descriptor.
51        */
52       Type.fd = Type.int.withName("fd");
53       Type.fd.importFromC = function importFromC(fd_int) {
54         return ctypes.CDataFinalizer(fd_int, SysFile._close);
55       };
56
57
58       /**
59        * A C integer holding -1 in case of error or a file descriptor
60        * in case of success.
61        */
62       Type.negativeone_or_fd = Type.fd.withName("negativeone_or_fd");
63       Type.negativeone_or_fd.importFromC =
64         function importFromC(fd_int) {
65           if (fd_int == -1) {
66             return -1;
67           }
68           return ctypes.CDataFinalizer(fd_int, SysFile._close);
69         };
70
71       /**
72        * A C integer holding -1 in case of error or a meaningless value
73        * in case of success.
74        */
75       Type.negativeone_or_nothing =
76         Type.int.withName("negativeone_or_nothing");
77
78       /**
79        * A C integer holding -1 in case of error or a positive integer
80        * in case of success.
81        */
82       Type.negativeone_or_ssize_t =
83         Type.ssize_t.withName("negativeone_or_ssize_t");
84
85       /**
86        * Various libc integer types
87        */
88       Type.mode_t =
89         Type.intn_t(Const.OSFILE_SIZEOF_MODE_T).withName("mode_t");
90       Type.uid_t =
91         Type.intn_t(Const.OSFILE_SIZEOF_UID_T).withName("uid_t");
92       Type.gid_t =
93         Type.intn_t(Const.OSFILE_SIZEOF_GID_T).withName("gid_t");
94
95       /**
96        * Type |time_t|
97        */
98       Type.time_t =
99         Type.intn_t(Const.OSFILE_SIZEOF_TIME_T).withName("time_t");
100
101       // Structure |dirent|
102       // Building this type is rather complicated, as its layout varies between
103       // variants of Unix. For this reason, we rely on a number of constants
104       // (computed in C from the C data structures) that give us the layout.
105       // The structure we compute looks like
106       //  { int8_t[...] before_d_type; // ignored content
107       //    int8_t      d_type       ;
108       //    int8_t[...] before_d_name; // ignored content
109       //    char[...]   d_name;
110       //    };
111       {
112         let d_name_extra_size = 0;
113         if (Const.OSFILE_SIZEOF_DIRENT_D_NAME < 8) {
114           // d_name is defined like "char d_name[1];" on some platforms
115           // (e.g. Solaris), we need to give it more size for our structure.
116           d_name_extra_size = 256;
117         }
118
119         let dirent = new SharedAll.HollowStructure("dirent",
120           Const.OSFILE_SIZEOF_DIRENT + d_name_extra_size);
121         if (Const.OSFILE_OFFSETOF_DIRENT_D_TYPE != undefined) {
122           // |dirent| doesn't have d_type on some platforms (e.g. Solaris).
123           dirent.add_field_at(Const.OSFILE_OFFSETOF_DIRENT_D_TYPE,
124             "d_type", ctypes.uint8_t);
125         }
126         dirent.add_field_at(Const.OSFILE_OFFSETOF_DIRENT_D_NAME,
127           "d_name", ctypes.ArrayType(ctypes.char,
128             Const.OSFILE_SIZEOF_DIRENT_D_NAME + d_name_extra_size));
129
130         // We now have built |dirent|.
131         Type.dirent = dirent.getType();
132       }
133       Type.null_or_dirent_ptr =
134         new SharedAll.Type("null_of_dirent",
135                  Type.dirent.out_ptr.implementation);
136
137       // Structure |stat|
138       // Same technique
139       {
140         let stat = new SharedAll.HollowStructure("stat",
141           Const.OSFILE_SIZEOF_STAT);
142         stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_MODE,
143                        "st_mode", Type.mode_t.implementation);
144         stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_UID,
145                          "st_uid", Type.uid_t.implementation);
146         stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_GID,
147                          "st_gid", Type.gid_t.implementation);
148
149         // Here, things get complicated with different data structures.
150         // Some platforms have |time_t st_atime| and some platforms have
151         // |timespec st_atimespec|. However, since |timespec| starts with
152         // a |time_t|, followed by nanoseconds, we just cheat and pretend
153         // that everybody has |time_t st_atime|, possibly followed by padding
154         stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_ATIME,
155                          "st_atime", Type.time_t.implementation);
156         stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_MTIME,
157                          "st_mtime", Type.time_t.implementation);
158         stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_CTIME,
159                          "st_ctime", Type.time_t.implementation);
160
161         // To complicate further, MacOS and some BSDs have a field |birthtime|
162         if ("OSFILE_OFFSETOF_STAT_ST_BIRTHTIME" in Const) {
163           stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_BIRTHTIME,
164                             "st_birthtime", Type.time_t.implementation);
165         }
166
167         stat.add_field_at(Const.OSFILE_OFFSETOF_STAT_ST_SIZE,
168                        "st_size", Type.off_t.implementation);
169         Type.stat = stat.getType();
170       }
171
172       // Structure |DIR|
173       if ("OSFILE_SIZEOF_DIR" in Const) {
174         // On platforms for which we need to access the fields of DIR
175         // directly (e.g. because certain functions are implemented
176         // as macros), we need to define DIR as a hollow structure.
177         let DIR = new SharedAll.HollowStructure(
178           "DIR",
179           Const.OSFILE_SIZEOF_DIR);
180
181         DIR.add_field_at(
182           Const.OSFILE_OFFSETOF_DIR_DD_FD,
183           "dd_fd",
184           Type.fd.implementation);
185
186         Type.DIR = DIR.getType();
187       } else {
188         // On other platforms, we keep DIR as a blackbox
189         Type.DIR =
190           new SharedAll.Type("DIR",
191             ctypes.StructType("DIR"));
192       }
193
194       Type.null_or_DIR_ptr =
195         Type.DIR.out_ptr.withName("null_or_DIR*");
196       Type.null_or_DIR_ptr.importFromC = function importFromC(dir) {
197         if (dir == null || dir.isNull()) {
198           return null;
199         }
200         return ctypes.CDataFinalizer(dir, SysFile._close_dir);
201       };
202
203       // Structure |timeval|
204       {
205         let timeval = new SharedAll.HollowStructure(
206           "timeval",
207           Const.OSFILE_SIZEOF_TIMEVAL);
208         timeval.add_field_at(
209           Const.OSFILE_OFFSETOF_TIMEVAL_TV_SEC,
210           "tv_sec",
211           Type.long.implementation);
212         timeval.add_field_at(
213           Const.OSFILE_OFFSETOF_TIMEVAL_TV_USEC,
214           "tv_usec",
215           Type.long.implementation);
216         Type.timeval = timeval.getType();
217         Type.timevals = new SharedAll.Type("two timevals",
218           ctypes.ArrayType(Type.timeval.implementation, 2));
219       }
220
221       // Types fsblkcnt_t and fsfilcnt_t, used by structure |statvfs|
222       Type.fsblkcnt_t =
223         Type.uintn_t(Const.OSFILE_SIZEOF_FSBLKCNT_T).withName("fsblkcnt_t");
224
225       // Structure |statvfs|
226       // Use an hollow structure
227       {
228         let statvfs = new SharedAll.HollowStructure("statvfs",
229           Const.OSFILE_SIZEOF_STATVFS);
230
231         statvfs.add_field_at(Const.OSFILE_OFFSETOF_STATVFS_F_FRSIZE,
232                        "f_frsize", Type.unsigned_long.implementation);
233         statvfs.add_field_at(Const.OSFILE_OFFSETOF_STATVFS_F_BAVAIL,
234                        "f_bavail", Type.fsblkcnt_t.implementation);
235
236         Type.statvfs = statvfs.getType();
237       }
238
239       // Declare libc functions as functions of |OS.Unix.File|
240
241       // Finalizer-related functions
242       libc.declareLazy(SysFile, "_close",
243                        "close", ctypes.default_abi,
244                        /*return */ctypes.int,
245                        /*fd*/     ctypes.int);
246
247       SysFile.close = function close(fd) {
248         // Detach the finalizer and call |_close|.
249         return fd.dispose();
250       };
251
252       libc.declareLazy(SysFile, "_close_dir",
253                        "closedir", ctypes.default_abi,
254                        /*return */ctypes.int,
255                        /*dirp*/   Type.DIR.in_ptr.implementation);
256
257       SysFile.closedir = function closedir(fd) {
258         // Detach the finalizer and call |_close_dir|.
259         return fd.dispose();
260       };
261
262       {
263         // Symbol free() is special.
264         // We override the definition of free() on several platforms.
265         let default_lib = new SharedAll.Library("default_lib",
266                                                 "a.out");
267
268         // On platforms for which we override free(), nspr defines
269         // a special library name "a.out" that will resolve to the
270         // correct implementation free().
271         // If it turns out we don't have an a.out library or a.out
272         // doesn't contain free, use the ordinary libc free.
273
274         default_lib.declareLazyWithFallback(libc, SysFile, "free",
275           "free", ctypes.default_abi,
276           /*return*/ ctypes.void_t,
277           /*ptr*/    ctypes.voidptr_t);
278       }
279
280
281       // Other functions
282       libc.declareLazyFFI(SysFile,  "access",
283                           "access", ctypes.default_abi,
284                           /*return*/ Type.negativeone_or_nothing,
285                           /*path*/   Type.path,
286                           /*mode*/   Type.int);
287
288       libc.declareLazyFFI(SysFile,  "chdir",
289                           "chdir", ctypes.default_abi,
290                           /*return*/ Type.negativeone_or_nothing,
291                           /*path*/   Type.path);
292
293       libc.declareLazyFFI(SysFile,  "chmod",
294                           "chmod", ctypes.default_abi,
295                           /*return*/ Type.negativeone_or_nothing,
296                           /*path*/   Type.path,
297                           /*mode*/   Type.mode_t);
298
299       libc.declareLazyFFI(SysFile,  "chown",
300                           "chown", ctypes.default_abi,
301                           /*return*/ Type.negativeone_or_nothing,
302                           /*path*/   Type.path,
303                           /*uid*/    Type.uid_t,
304                           /*gid*/    Type.gid_t);
305
306       libc.declareLazyFFI(SysFile,  "copyfile",
307                           "copyfile", ctypes.default_abi,
308                           /*return*/ Type.negativeone_or_nothing,
309                           /*source*/ Type.path,
310                           /*dest*/   Type.path,
311                           /*state*/  Type.void_t.in_ptr, // Ignored atm
312                           /*flags*/  Type.uint32_t);
313
314       libc.declareLazyFFI(SysFile,  "dup",
315                           "dup", ctypes.default_abi,
316                           /*return*/ Type.negativeone_or_fd,
317                           /*fd*/     Type.fd);
318
319       if ("OSFILE_SIZEOF_DIR" in Const) {
320         // On platforms for which |dirfd| is a macro
321         SysFile.dirfd =
322           function dirfd(DIRp) {
323             return Type.DIR.in_ptr.implementation(DIRp).contents.dd_fd;
324           };
325       } else {
326         // On platforms for which |dirfd| is a function
327         libc.declareLazyFFI(SysFile,  "dirfd",
328                             "dirfd", ctypes.default_abi,
329                             /*return*/ Type.negativeone_or_fd,
330                             /*dir*/    Type.DIR.in_ptr);
331       }
332
333       libc.declareLazyFFI(SysFile,  "chdir",
334                           "chdir", ctypes.default_abi,
335                           /*return*/ Type.negativeone_or_nothing,
336                           /*path*/   Type.path);
337
338       libc.declareLazyFFI(SysFile,  "fchdir",
339                           "fchdir", ctypes.default_abi,
340                           /*return*/ Type.negativeone_or_nothing,
341                           /*fd*/     Type.fd);
342
343       libc.declareLazyFFI(SysFile,  "fchmod",
344                           "fchmod", ctypes.default_abi,
345                           /*return*/ Type.negativeone_or_nothing,
346                           /*fd*/     Type.fd,
347                           /*mode*/   Type.mode_t);
348
349       libc.declareLazyFFI(SysFile,  "fchown",
350                           "fchown", ctypes.default_abi,
351                           /*return*/ Type.negativeone_or_nothing,
352                           /*fd*/     Type.fd,
353                           /*uid_t*/  Type.uid_t,
354                           /*gid_t*/  Type.gid_t);
355
356       libc.declareLazyFFI(SysFile,  "fsync",
357                           "fsync", ctypes.default_abi,
358                           /*return*/ Type.negativeone_or_nothing,
359                           /*fd*/     Type.fd);
360
361       libc.declareLazyFFI(SysFile,  "getcwd",
362                           "getcwd", ctypes.default_abi,
363                           /*return*/ Type.out_path,
364                           /*buf*/    Type.out_path,
365                           /*size*/   Type.size_t);
366
367       libc.declareLazyFFI(SysFile,  "getwd",
368                           "getwd", ctypes.default_abi,
369                           /*return*/ Type.out_path,
370                           /*buf*/    Type.out_path);
371
372       // Two variants of |getwd| which allocate the memory
373       // dynamically.
374
375       // Linux/Android version
376       libc.declareLazyFFI(SysFile,  "get_current_dir_name",
377                           "get_current_dir_name", ctypes.default_abi,
378                           /*return*/ Type.out_path.releaseWithLazy(() =>
379                             SysFile.free
380                           ));
381
382       // MacOS/BSD version (will return NULL on Linux/Android)
383       libc.declareLazyFFI(SysFile,  "getwd_auto",
384                           "getwd", ctypes.default_abi,
385                           /*return*/ Type.out_path.releaseWithLazy(() =>
386                             SysFile.free
387                           ),
388                           /*buf*/    Type.void_t.out_ptr);
389
390       libc.declareLazyFFI(SysFile,  "fdatasync",
391                           "fdatasync", ctypes.default_abi,
392                           /*return*/ Type.negativeone_or_nothing,
393                           /*fd*/     Type.fd); // Note: MacOS/BSD-specific
394
395       libc.declareLazyFFI(SysFile,  "ftruncate",
396                           "ftruncate", ctypes.default_abi,
397                           /*return*/ Type.negativeone_or_nothing,
398                           /*fd*/     Type.fd,
399                           /*length*/ Type.off_t);
400
401
402       libc.declareLazyFFI(SysFile,  "lchown",
403                           "lchown", ctypes.default_abi,
404                           /*return*/ Type.negativeone_or_nothing,
405                           /*path*/   Type.path,
406                           /*uid_t*/  Type.uid_t,
407                           /*gid_t*/  Type.gid_t);
408
409       libc.declareLazyFFI(SysFile,  "link",
410                           "link", ctypes.default_abi,
411                           /*return*/ Type.negativeone_or_nothing,
412                           /*source*/ Type.path,
413                           /*dest*/   Type.path);
414
415       libc.declareLazyFFI(SysFile,  "lseek",
416                           "lseek", ctypes.default_abi,
417                           /*return*/ Type.off_t,
418                           /*fd*/     Type.fd,
419                           /*offset*/ Type.off_t,
420                           /*whence*/ Type.int);
421
422       libc.declareLazyFFI(SysFile,  "mkdir",
423                           "mkdir", ctypes.default_abi,
424                           /*return*/ Type.int,
425                           /*path*/ Type.path,
426                           /*mode*/ Type.int);
427
428       libc.declareLazyFFI(SysFile,  "mkstemp",
429                           "mkstemp", ctypes.default_abi,
430                           /*return*/   Type.fd,
431                           /*template*/ Type.out_path);
432
433       libc.declareLazyFFI(SysFile,  "open",
434                           "open", ctypes.default_abi,
435                           /*return*/ Type.negativeone_or_fd,
436                           /*path*/   Type.path,
437                           /*oflags*/ Type.int,
438                           /*mode*/   Type.int);
439
440       if (OS.Constants.Sys.Name == "NetBSD") {
441          libc.declareLazyFFI(SysFile,  "opendir",
442                              "__opendir30", ctypes.default_abi,
443                   /*return*/ Type.null_or_DIR_ptr,
444                   /*path*/   Type.path);
445       } else {
446          libc.declareLazyFFI(SysFile,  "opendir",
447                              "opendir", ctypes.default_abi,
448                    /*return*/ Type.null_or_DIR_ptr,
449                    /*path*/   Type.path);
450       }
451
452       libc.declareLazyFFI(SysFile,  "pread",
453                               "pread", ctypes.default_abi,
454                    /*return*/ Type.negativeone_or_ssize_t,
455                    /*fd*/     Type.fd,
456                    /*buf*/    Type.void_t.out_ptr,
457                    /*nbytes*/ Type.size_t,
458                    /*offset*/ Type.off_t);
459
460       libc.declareLazyFFI(SysFile,  "pwrite",
461                               "pwrite", ctypes.default_abi,
462                    /*return*/ Type.negativeone_or_ssize_t,
463                    /*fd*/     Type.fd,
464                    /*buf*/    Type.void_t.in_ptr,
465                    /*nbytes*/ Type.size_t,
466                    /*offset*/ Type.off_t);
467
468       libc.declareLazyFFI(SysFile,  "read",
469                              "read", ctypes.default_abi,
470                    /*return*/Type.negativeone_or_ssize_t,
471                    /*fd*/    Type.fd,
472                    /*buf*/   Type.void_t.out_ptr,
473                    /*nbytes*/Type.size_t);
474
475       libc.declareLazyFFI(SysFile,  "posix_fadvise",
476                               "posix_fadvise", ctypes.default_abi,
477                    /*return*/ Type.int,
478                    /*fd*/     Type.fd,
479                    /*offset*/ Type.off_t,
480                    /*len*/    Type.off_t,
481                    /*advise*/ Type.int);
482
483       if (Const._DARWIN_FEATURE_64_BIT_INODE) {
484         // Special case for MacOS X 10.5+
485         // Symbol name "readdir" still exists but is used for a
486         // deprecated function that does not match the
487         // constants of |Const|.
488         libc.declareLazyFFI(SysFile,  "readdir",
489                                "readdir$INODE64", ctypes.default_abi,
490                     /*return*/ Type.null_or_dirent_ptr,
491                      /*dir*/   Type.DIR.in_ptr); // For MacOS X
492       } else if (OS.Constants.Sys.Name == "NetBSD") {
493         libc.declareLazyFFI(SysFile,  "readdir",
494                                "__readdir30", ctypes.default_abi,
495                      /*return*/Type.null_or_dirent_ptr,
496                      /*dir*/   Type.DIR.in_ptr); // Other Unices
497       } else {
498         libc.declareLazyFFI(SysFile,  "readdir",
499                                "readdir", ctypes.default_abi,
500                      /*return*/Type.null_or_dirent_ptr,
501                      /*dir*/   Type.DIR.in_ptr); // Other Unices
502       }
503
504       libc.declareLazyFFI(SysFile,  "rename",
505                               "rename", ctypes.default_abi,
506                    /*return*/ Type.negativeone_or_nothing,
507                    /*old*/    Type.path,
508                    /*new*/    Type.path);
509
510       libc.declareLazyFFI(SysFile,  "rmdir",
511                               "rmdir", ctypes.default_abi,
512                    /*return*/ Type.int,
513                    /*path*/   Type.path);
514
515       libc.declareLazyFFI(SysFile,  "splice",
516                               "splice", ctypes.default_abi,
517                    /*return*/ Type.long,
518                    /*fd_in*/  Type.fd,
519                    /*off_in*/ Type.off_t.in_ptr,
520                    /*fd_out*/ Type.fd,
521                    /*off_out*/Type.off_t.in_ptr,
522                    /*len*/    Type.size_t,
523                    /*flags*/  Type.unsigned_int); // Linux/Android-specific
524
525       libc.declareLazyFFI(SysFile,  "statfs",
526                               "statfs", ctypes.default_abi,
527                    /*return*/ Type.negativeone_or_nothing,
528                    /*path*/   Type.path,
529                    /*buf*/    Type.statvfs.out_ptr); // Android,B2G
530
531       libc.declareLazyFFI(SysFile,  "statvfs",
532                               "statvfs", ctypes.default_abi,
533                    /*return*/ Type.negativeone_or_nothing,
534                    /*path*/   Type.path,
535                    /*buf*/    Type.statvfs.out_ptr); // Other platforms
536
537       libc.declareLazyFFI(SysFile,  "symlink",
538                               "symlink", ctypes.default_abi,
539                    /*return*/ Type.negativeone_or_nothing,
540                    /*source*/ Type.path,
541                    /*dest*/   Type.path);
542
543       libc.declareLazyFFI(SysFile,  "truncate",
544                              "truncate", ctypes.default_abi,
545                    /*return*/Type.negativeone_or_nothing,
546                    /*path*/  Type.path,
547                    /*length*/ Type.off_t);
548
549       libc.declareLazyFFI(SysFile,  "unlink",
550                           "unlink", ctypes.default_abi,
551                    /*return*/ Type.negativeone_or_nothing,
552                    /*path*/ Type.path);
553
554       libc.declareLazyFFI(SysFile,  "write",
555                           "write", ctypes.default_abi,
556                    /*return*/ Type.negativeone_or_ssize_t,
557                    /*fd*/     Type.fd,
558                    /*buf*/    Type.void_t.in_ptr,
559                    /*nbytes*/ Type.size_t);
560
561       // Weird cases that require special treatment
562
563       // OSes use a variety of hacks to differentiate between
564       // 32-bits and 64-bits versions of |stat|, |lstat|, |fstat|.
565       if (Const._DARWIN_FEATURE_64_BIT_INODE) {
566         // MacOS X 64-bits
567         libc.declareLazyFFI(SysFile,  "stat",
568                             "stat$INODE64", ctypes.default_abi,
569                      /*return*/ Type.negativeone_or_nothing,
570                      /*path*/   Type.path,
571                      /*buf*/    Type.stat.out_ptr
572                     );
573         libc.declareLazyFFI(SysFile,  "lstat",
574                             "lstat$INODE64", ctypes.default_abi,
575                      /*return*/ Type.negativeone_or_nothing,
576                      /*path*/   Type.path,
577                      /*buf*/    Type.stat.out_ptr
578                     );
579         libc.declareLazyFFI(SysFile,  "fstat",
580                             "fstat$INODE64", ctypes.default_abi,
581                      /*return*/ Type.negativeone_or_nothing,
582                      /*path*/   Type.fd,
583                      /*buf*/    Type.stat.out_ptr
584                     );
585       } else if (Const._STAT_VER != undefined) {
586         const ver = Const._STAT_VER;
587         let xstat_name, lxstat_name, fxstat_name;
588         if (OS.Constants.Sys.Name == "SunOS") {
589           // Solaris
590           xstat_name = "_xstat";
591           lxstat_name = "_lxstat";
592           fxstat_name = "_fxstat";
593         } else {
594           // Linux, all widths
595           xstat_name = "__xstat";
596           lxstat_name = "__lxstat";
597           fxstat_name = "__fxstat";
598         }
599
600         let Stat = {};
601         libc.declareLazyFFI(Stat,  "xstat",
602                             xstat_name, ctypes.default_abi,
603                      /*return*/    Type.negativeone_or_nothing,
604                      /*_stat_ver*/ Type.int,
605                      /*path*/      Type.path,
606                      /*buf*/       Type.stat.out_ptr);
607         libc.declareLazyFFI(Stat,  "lxstat",
608                             lxstat_name, ctypes.default_abi,
609                      /*return*/    Type.negativeone_or_nothing,
610                      /*_stat_ver*/ Type.int,
611                      /*path*/      Type.path,
612                      /*buf*/       Type.stat.out_ptr);
613         libc.declareLazyFFI(Stat, "fxstat",
614                             fxstat_name, ctypes.default_abi,
615                      /*return*/    Type.negativeone_or_nothing,
616                      /*_stat_ver*/ Type.int,
617                      /*fd*/        Type.fd,
618                      /*buf*/       Type.stat.out_ptr);
619
620
621         SysFile.stat = function stat(path, buf) {
622           return Stat.xstat(ver, path, buf);
623         };
624
625         SysFile.lstat = function lstat(path, buf) {
626           return Stat.lxstat(ver, path, buf);
627         };
628
629         SysFile.fstat = function fstat(fd, buf) {
630           return Stat.fxstat(ver, fd, buf);
631         };
632       } else if (OS.Constants.Sys.Name == "NetBSD") {
633         // NetBSD 5.0 and newer
634         libc.declareLazyFFI(SysFile,  "stat",
635                             "__stat50", ctypes.default_abi,
636                      /*return*/ Type.negativeone_or_nothing,
637                      /*path*/   Type.path,
638                      /*buf*/    Type.stat.out_ptr
639                     );
640         libc.declareLazyFFI(SysFile,  "lstat",
641                             "__lstat50", ctypes.default_abi,
642                      /*return*/ Type.negativeone_or_nothing,
643                      /*path*/   Type.path,
644                      /*buf*/    Type.stat.out_ptr
645                     );
646         libc.declareLazyFFI(SysFile,  "fstat",
647                             "__fstat50", ctypes.default_abi,
648                      /*return*/ Type.negativeone_or_nothing,
649                      /*fd*/     Type.fd,
650                      /*buf*/    Type.stat.out_ptr
651                     );
652       } else {
653         // Mac OS X 32-bits, other Unix
654         libc.declareLazyFFI(SysFile,  "stat",
655                             "stat", ctypes.default_abi,
656                      /*return*/ Type.negativeone_or_nothing,
657                      /*path*/   Type.path,
658                      /*buf*/    Type.stat.out_ptr
659                     );
660         libc.declareLazyFFI(SysFile,  "lstat",
661                             "lstat", ctypes.default_abi,
662                      /*return*/ Type.negativeone_or_nothing,
663                      /*path*/   Type.path,
664                      /*buf*/    Type.stat.out_ptr
665                     );
666         libc.declareLazyFFI(SysFile,  "fstat",
667                             "fstat", ctypes.default_abi,
668                      /*return*/ Type.negativeone_or_nothing,
669                      /*fd*/     Type.fd,
670                      /*buf*/    Type.stat.out_ptr
671                     );
672       }
673
674       // We cannot make a C array of CDataFinalizer, so
675       // pipe cannot be directly defined as a C function.
676
677       let Pipe = {};
678       libc.declareLazyFFI(Pipe, "_pipe",
679         "pipe", ctypes.default_abi,
680         /*return*/ Type.negativeone_or_nothing,
681         /*fds*/    new SharedAll.Type("two file descriptors",
682             ctypes.ArrayType(ctypes.int, 2)));
683
684       // A shared per-thread buffer used to communicate with |pipe|
685       let _pipebuf = new (ctypes.ArrayType(ctypes.int, 2))();
686
687       SysFile.pipe = function pipe(array) {
688         let result = Pipe._pipe(_pipebuf);
689         if (result == -1) {
690           return result;
691         }
692         array[0] = ctypes.CDataFinalizer(_pipebuf[0], SysFile._close);
693         array[1] = ctypes.CDataFinalizer(_pipebuf[1], SysFile._close);
694         return result;
695       };
696
697       if (OS.Constants.Sys.Name == "NetBSD") {
698           libc.declareLazyFFI(SysFile, "utimes",
699                               "__utimes50", ctypes.default_abi,
700                      /*return*/     Type.negativeone_or_nothing,
701                      /*path*/       Type.path,
702                      /*timeval[2]*/ Type.timevals.out_ptr
703                      );
704       } else {
705           libc.declareLazyFFI(SysFile, "utimes",
706                               "utimes", ctypes.default_abi,
707                      /*return*/     Type.negativeone_or_nothing,
708                      /*path*/       Type.path,
709                      /*timeval[2]*/ Type.timevals.out_ptr
710                      );
711       }
712       if (OS.Constants.Sys.Name == "NetBSD") {
713           libc.declareLazyFFI(SysFile, "futimes",
714                               "__futimes50", ctypes.default_abi,
715                      /*return*/     Type.negativeone_or_nothing,
716                      /*fd*/         Type.fd,
717                      /*timeval[2]*/ Type.timevals.out_ptr
718                      );
719       } else {
720           libc.declareLazyFFI(SysFile, "futimes",
721                               "futimes", ctypes.default_abi,
722                      /*return*/     Type.negativeone_or_nothing,
723                      /*fd*/         Type.fd,
724                      /*timeval[2]*/ Type.timevals.out_ptr
725                      );
726       }
727     };
728
729     exports.OS.Unix = {
730       File: {
731         _init: init
732       }
733     };
734   })(this);
735}
736