Update Iot.js
[platform/upstream/iotjs.git] / src / js / fs.js
1 /* Copyright 2015-present Samsung Electronics Co., Ltd. and other contributors
2  *
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16
17 var fs = exports;
18 var constants = require('constants');
19 var util = require('util');
20 var fsBuiltin = process.binding(process.binding.fs);
21
22
23 var O_APPEND = constants.O_APPEND;
24 var O_CREAT = constants.O_CREAT;
25 var O_EXCL = constants.O_EXCL;
26 var O_RDONLY = constants.O_RDONLY;
27 var O_RDWR = constants.O_RDWR;
28 var O_SYNC = constants.O_SYNC;
29 var O_TRUNC = constants.O_TRUNC;
30 var O_WRONLY = constants.O_WRONLY;
31
32
33 fs.Stats = function(stat) {
34   this.dev = stat.dev;
35   this.mode = stat.mode;
36   this.nlink = stat.nlink;
37   this.uid = stat.uid;
38   this.gid = stat.gid;
39   this.rdev = stat.rdev;
40   this.blksize = stat.blksize;
41   this.ino = stat.ino;
42   this.size = stat.size;
43   this.blocks = stat.blocks;
44 };
45
46
47 fs.Stats.prototype.isDirectory = function() {
48   return ((this.mode & constants.S_IFMT) === constants.S_IFDIR);
49 };
50
51
52 fs.Stats.prototype.isFile = function() {
53   return ((this.mode & constants.S_IFMT) === constants.S_IFREG);
54 };
55
56
57 fsBuiltin._createStat = function(stat) {
58   return new fs.Stats(stat);
59 };
60
61
62 fs.exists = function(path, callback) {
63   if (!path || !path.length) {
64     process.nextTick(function () {
65       if (callback) callback(false);
66     });
67     return;
68   }
69
70   var cb = function(err, stat) {
71     if (callback) callback(err ? false : true);
72   };
73
74   fsBuiltin.stat(checkArgString(path, 'path'),
75                  checkArgFunction(cb, 'callback'));
76 };
77
78
79 fs.existsSync = function(path) {
80   if (!path || !path.length) {
81     return false;
82   }
83
84   try {
85     fsBuiltin.stat(checkArgString(path, 'path'));
86     return true;
87   } catch (e) {
88     return false;
89   }
90 };
91
92
93 fs.stat = function(path, callback) {
94   fsBuiltin.stat(checkArgString(path, 'path'),
95                  checkArgFunction(callback, 'callback'));
96 };
97
98
99 fs.statSync = function(path) {
100   return fsBuiltin.stat(checkArgString(path, 'path'));
101 };
102
103
104 fs.fstat = function(fd, callback) {
105   fsBuiltin.fstat(checkArgNumber(fd, 'fd'),
106                   checkArgFunction(callback, 'callback'));
107 };
108
109
110 fs.fstatSync = function(fd) {
111   return fsBuiltin.fstat(checkArgNumber(fd, 'fd'));
112 };
113
114
115 fs.close = function(fd, callback) {
116   fsBuiltin.close(checkArgNumber(fd, 'fd'),
117                   checkArgFunction(callback, 'callback'));
118 };
119
120
121 fs.closeSync = function(fd) {
122   fsBuiltin.close(checkArgNumber(fd, 'fd'));
123 };
124
125
126 fs.open = function(path, flags, mode, callback) {
127   fsBuiltin.open(checkArgString(path, 'path'),
128                  convertFlags(flags),
129                  convertMode(mode, 438),
130                  checkArgFunction(arguments[arguments.length - 1]), 'callback');
131 };
132
133
134 fs.openSync = function(path, flags, mode) {
135   return fsBuiltin.open(checkArgString(path, 'path'),
136                         convertFlags(flags),
137                         convertMode(mode, 438));
138 };
139
140
141 fs.read = function(fd, buffer, offset, length, position, callback) {
142   callback = checkArgFunction(callback, 'callback');
143
144   var cb = function(err, bytesRead) {
145     callback(err, bytesRead || 0, buffer);
146   };
147
148   return fsBuiltin.read(checkArgNumber(fd, 'fd'),
149                         checkArgBuffer(buffer, 'buffer'),
150                         checkArgNumber(offset, 'offset'),
151                         checkArgNumber(length, 'length'),
152                         checkArgNumber(position, 'position'),
153                         cb);
154 };
155
156
157 fs.readSync = function(fd, buffer, offset, length, position) {
158   if (util.isNullOrUndefined(position)) {
159     position = -1;
160   }
161   return fsBuiltin.read(checkArgNumber(fd, 'fd'),
162                         checkArgBuffer(buffer, 'buffer'),
163                         checkArgNumber(offset, 'offset'),
164                         checkArgNumber(length, 'length'),
165                         checkArgNumber(position, 'position'));
166 };
167
168
169 fs.write = function(fd, buffer, offset, length, position, callback) {
170   if (util.isFunction(position)) {
171     callback = position;
172     position = -1; // write at current position.
173   }
174
175   callback = checkArgFunction(callback, 'callback');
176
177   var cb = function(err, written) {
178     callback(err, written, buffer);
179   };
180
181   return fsBuiltin.write(checkArgNumber(fd, 'fd'),
182                          checkArgBuffer(buffer, 'buffer'),
183                          checkArgNumber(offset, 'offset'),
184                          checkArgNumber(length, 'length'),
185                          checkArgNumber(position, 'position'),
186                          cb);
187 };
188
189
190 fs.writeSync = function(fd, buffer, offset, length, position) {
191   if (util.isNullOrUndefined(position)) {
192     position = -1; // write at current position.
193   }
194
195   return fsBuiltin.write(checkArgNumber(fd, 'fd'),
196                          checkArgBuffer(buffer, 'buffer'),
197                          checkArgNumber(offset, 'offset'),
198                          checkArgNumber(length, 'length'),
199                          checkArgNumber(position, 'position'));
200 };
201
202
203 fs.readFile = function(path, callback) {
204   checkArgString(path);
205   checkArgFunction(callback);
206
207   var fd;
208   var buffers;
209
210   fs.open(path, 'r', function(err, _fd) {
211     if (err) {
212       return callback(err);
213     }
214
215     fd = _fd;
216     buffers = [];
217
218     // start read
219     read();
220   });
221
222   var read = function() {
223     // Read segment of data.
224     var buffer = new Buffer(1023);
225     fs.read(fd, buffer, 0, 1023, -1, afterRead);
226   };
227
228   var afterRead = function(err, bytesRead, buffer) {
229     if (err) {
230       fs.close(fd, function(err) {
231         return callback(err);
232       });
233     }
234
235     if (bytesRead === 0) {
236       // End of file.
237       close();
238     } else {
239       // continue reading.
240       buffers.push(buffer.slice(0, bytesRead));
241       read();
242     }
243   };
244
245   var close = function() {
246     fs.close(fd, function(err) {
247       return callback(err, Buffer.concat(buffers));
248     });
249   }
250 };
251
252
253 fs.readFileSync = function(path) {
254   checkArgString(path);
255
256   var fd = fs.openSync(path, 'r', 438);
257   var buffers = [];
258
259   while (true) {
260     try {
261       var buffer = new Buffer(1023);
262       var bytesRead = fs.readSync(fd, buffer, 0, 1023);
263       if (bytesRead) {
264         buffers.push(buffer.slice(0, bytesRead));
265       } else {
266         break;
267       }
268     } catch (e) {
269       break;
270     }
271   }
272   fs.closeSync(fd);
273
274   return Buffer.concat(buffers);
275 };
276
277
278 fs.writeFile = function(path, data, callback) {
279   checkArgString(path);
280   checkArgBuffer(data);
281   checkArgFunction(callback);
282
283   var fd;
284   var len;
285   var bytesWritten;
286
287   fs.open(path, 'w', function(err, _fd) {
288     if (err) {
289       return callback(err);
290     }
291
292     fd = _fd;
293     len = data.length;
294     bytesWritten = 0;
295
296     write();
297   });
298
299   var write = function() {
300     var tryN = (len - bytesWritten) >= 1024 ? 1023 : (len - bytesWritten);
301     fs.write(fd, data, bytesWritten, tryN, bytesWritten, afterWrite);
302   };
303
304   var afterWrite = function(err, n) {
305     if (err) {
306       fs.close(fd, function(err) {
307         return callback(err);
308       });
309     }
310
311     if (n <= 0 || bytesWritten + n == len) {
312       // End of data
313       fs.close(fd, function(err) {
314         callback(err);
315       });
316     } else {
317       // continue writing
318       bytesWritten += n;
319       write();
320     }
321   };
322 };
323
324
325 fs.writeFileSync = function(path, data) {
326   checkArgString(path);
327   checkArgBuffer(data);
328
329   var fd = fs.openSync(path, 'w');
330   var len = data.length;
331   var bytesWritten = 0;
332
333   while (true) {
334     try {
335       var tryN = (len - bytesWritten) >= 1024 ? 1023 : (len - bytesWritten);
336       var n = fs.writeSync(fd, data, bytesWritten, tryN, bytesWritten);
337       bytesWritten += n;
338       if (bytesWritten == len) {
339         break;
340       }
341     } catch (e) {
342       break;
343     }
344   }
345   fs.closeSync(fd);
346   return bytesWritten;
347 };
348
349
350 fs.mkdir = function(path, mode, callback) {
351   if (util.isFunction(mode)) callback = mode;
352   checkArgString(path, 'path');
353   checkArgFunction(callback, 'callback');
354   fsBuiltin.mkdir(path, convertMode(mode, 511), callback);
355 };
356
357
358 fs.mkdirSync = function(path, mode) {
359   return fsBuiltin.mkdir(checkArgString(path, 'path'),
360                          convertMode(mode, 511));
361 };
362
363
364 fs.rmdir = function(path, callback) {
365   checkArgString(path, 'path');
366   checkArgFunction(callback, 'callback');
367   fsBuiltin.rmdir(path, callback);
368 };
369
370
371 fs.rmdirSync = function(path) {
372   return fsBuiltin.rmdir(checkArgString(path, 'path'));
373 };
374
375
376 fs.unlink = function(path, callback) {
377   checkArgString(path);
378   checkArgFunction(callback);
379   fsBuiltin.unlink(path, callback);
380 };
381
382
383 fs.unlinkSync = function(path) {
384   return fsBuiltin.unlink(checkArgString(path, 'path'));
385 };
386
387
388 fs.rename = function(oldPath, newPath, callback) {
389   checkArgString(oldPath);
390   checkArgString(newPath);
391   checkArgFunction(callback);
392   fsBuiltin.rename(oldPath, newPath, callback);
393 };
394
395
396 fs.renameSync = function(oldPath, newPath) {
397   checkArgString(oldPath);
398   checkArgString(newPath);
399   fsBuiltin.rename(oldPath, newPath);
400 };
401
402
403 fs.readdir = function(path, callback) {
404   checkArgString(path);
405   checkArgFunction(callback);
406   fsBuiltin.readdir(path, callback);
407 };
408
409
410 fs.readdirSync = function(path) {
411   return fsBuiltin.readdir(checkArgString(path, 'path'));
412 };
413
414
415 function convertFlags(flag) {
416   if (util.isString(flag)) {
417     switch (flag) {
418       case 'r': return O_RDONLY;
419       case 'rs':
420       case 'sr': return O_RDONLY | O_SYNC;
421
422       case 'r+': return O_RDWR;
423       case 'rs+':
424       case 'sr+': return O_RDWR | O_SYNC;
425
426       case 'w': return O_TRUNC | O_CREAT | O_WRONLY;
427       case 'wx':
428       case 'xw': return O_TRUNC | O_CREAT | O_WRONLY | O_EXCL;
429
430       case 'w+': return O_TRUNC | O_CREAT | O_RDWR;
431       case 'wx+':
432       case 'xw+': return O_TRUNC | O_CREAT | O_RDWR | O_EXCL;
433
434       case 'a': return O_APPEND | O_CREAT | O_WRONLY;
435       case 'ax':
436       case 'xa': return O_APPEND | O_CREAT | O_WRONLY | O_EXCL;
437
438       case 'a+': return O_APPEND | O_CREAT | O_RDWR;
439       case 'ax+':
440       case 'xa+': return O_APPEND | O_CREAT | O_RDWR | O_EXCL;
441     }
442   }
443   throw new TypeError('Bad argument: flags');
444 }
445
446
447 function convertMode(mode, def) {
448   if (util.isNumber(mode)) {
449     return mode;
450   } else if (util.isString(mode)) {
451     return parseInt(mode);
452   } else if (def) {
453     return convertMode(def);
454   }
455   return undefined;
456 }
457
458
459 function checkArgType(value, name, checkFunc) {
460   if (checkFunc(value)) {
461     return value;
462   } else {
463     throw new TypeError('Bad arguments: ' + name);
464   }
465 }
466
467
468 function checkArgBuffer(value, name) {
469   return checkArgType(value, name, util.isBuffer);
470 }
471
472
473 function checkArgNumber(value, name) {
474   return checkArgType(value, name, util.isNumber);
475 }
476
477
478 function checkArgString(value, name) {
479   return checkArgType(value, name, util.isString);
480 }
481
482
483 function checkArgFunction(value, name) {
484   return checkArgType(value, name, util.isFunction);
485 }