Security update for Core, with self-updated composer
[yaffs-website] / node_modules / temp / lib / temp.js
1 var fs   = require('fs'),
2     path = require('path'),
3     cnst = require('constants');
4
5 var rimraf     = require('rimraf'),
6     osTmpdir   = require('os-tmpdir'),
7     rimrafSync = rimraf.sync;
8
9 /* HELPERS */
10
11 var RDWR_EXCL = cnst.O_CREAT | cnst.O_TRUNC | cnst.O_RDWR | cnst.O_EXCL;
12
13 var generateName = function(rawAffixes, defaultPrefix) {
14   var affixes = parseAffixes(rawAffixes, defaultPrefix);
15   var now = new Date();
16   var name = [affixes.prefix,
17               now.getYear(), now.getMonth(), now.getDate(),
18               '-',
19               process.pid,
20               '-',
21               (Math.random() * 0x100000000 + 1).toString(36),
22               affixes.suffix].join('');
23   return path.join(affixes.dir || exports.dir, name);
24 };
25
26 var parseAffixes = function(rawAffixes, defaultPrefix) {
27   var affixes = {prefix: null, suffix: null};
28   if(rawAffixes) {
29     switch (typeof(rawAffixes)) {
30     case 'string':
31       affixes.prefix = rawAffixes;
32       break;
33     case 'object':
34       affixes = rawAffixes;
35       break;
36     default:
37       throw new Error("Unknown affix declaration: " + affixes);
38     }
39   } else {
40     affixes.prefix = defaultPrefix;
41   }
42   return affixes;
43 };
44
45 /* -------------------------------------------------------------------------
46  * Don't forget to call track() if you want file tracking and exit handlers!
47  * -------------------------------------------------------------------------
48  * When any temp file or directory is created, it is added to filesToDelete
49  * or dirsToDelete. The first time any temp file is created, a listener is
50  * added to remove all temp files and directories at exit.
51  */
52 var tracking = false;
53 var track = function(value) {
54   tracking = (value !== false);
55   return module.exports; // chainable
56 };
57 var exitListenerAttached = false;
58 var filesToDelete = [];
59 var dirsToDelete = [];
60
61 function deleteFileOnExit(filePath) {
62   if (!tracking) return false;
63   attachExitListener();
64   filesToDelete.push(filePath);
65 }
66
67 function deleteDirOnExit(dirPath) {
68   if (!tracking) return false;
69   attachExitListener();
70   dirsToDelete.push(dirPath);
71 }
72
73 function attachExitListener() {
74   if (!tracking) return false;
75   if (!exitListenerAttached) {
76     process.addListener('exit', cleanupSync);
77     exitListenerAttached = true;
78   }
79 }
80
81 function cleanupFilesSync() {
82   if (!tracking) {
83     return false;
84   }
85   var count = 0;
86   var toDelete;
87   while ((toDelete = filesToDelete.shift()) !== undefined) {
88     rimrafSync(toDelete);
89     count++;
90   }
91   return count;
92 }
93
94 function cleanupFiles(callback) {
95   if (!tracking) {
96     if (callback) {
97       callback(new Error("not tracking"));
98     }
99     return;
100   }
101   var count = 0;
102   var left = filesToDelete.length;
103   if (!left) {
104     if (callback) {
105       callback(null, count);
106     }
107     return;
108   }
109   var toDelete;
110   var rimrafCallback = function(err) {
111     if (!left) {
112       // Prevent processing if aborted
113       return;
114     }
115     if (err) {
116       // This shouldn't happen; pass error to callback and abort
117       // processing
118       if (callback) {
119         callback(err);
120       }
121       left = 0;
122       return;
123     } else {
124       count++;
125     }
126     left--;
127     if (!left && callback) {
128       callback(null, count);
129     }
130   };
131   while ((toDelete = filesToDelete.shift()) !== undefined) {
132     rimraf(toDelete, rimrafCallback);
133   }
134 }
135
136 function cleanupDirsSync() {
137   if (!tracking) {
138     return false;
139   }
140   var count = 0;
141   var toDelete;
142   while ((toDelete = dirsToDelete.shift()) !== undefined) {
143     rimrafSync(toDelete);
144     count++;
145   }
146   return count;
147 }
148
149 function cleanupDirs(callback) {
150   if (!tracking) {
151     if (callback) {
152       callback(new Error("not tracking"));
153     }
154     return;
155   }
156   var count = 0;
157   var left = dirsToDelete.length;
158   if (!left) {
159     if (callback) {
160       callback(null, count);
161     }
162     return;
163   }
164   var toDelete;
165   var rimrafCallback = function (err) {
166     if (!left) {
167       // Prevent processing if aborted
168       return;
169     }
170     if (err) {
171       // rimraf handles most "normal" errors; pass the error to the
172       // callback and abort processing
173       if (callback) {
174         callback(err, count);
175       }
176       left = 0;
177       return;
178     } else {
179       count;
180     }
181     left--;
182     if (!left && callback) {
183       callback(null, count);
184     }
185   };
186   while ((toDelete = dirsToDelete.shift()) !== undefined) {
187     rimraf(toDelete, rimrafCallback);
188   }
189 }
190
191 function cleanupSync() {
192   if (!tracking) {
193     return false;
194   }
195   var fileCount = cleanupFilesSync();
196   var dirCount  = cleanupDirsSync();
197   return {files: fileCount, dirs: dirCount};
198 }
199
200 function cleanup(callback) {
201   if (!tracking) {
202     if (callback) {
203       callback(new Error("not tracking"));
204     }
205     return;
206   }
207   cleanupFiles(function(fileErr, fileCount) {
208     if (fileErr) {
209       if (callback) {
210         callback(fileErr, {files: fileCount})
211       }
212     } else {
213       cleanupDirs(function(dirErr, dirCount) {
214         if (callback) {
215           callback(dirErr, {files: fileCount, dirs: dirCount});
216         }
217       });
218     }
219   });
220 }
221
222 /* DIRECTORIES */
223
224 function mkdir(affixes, callback) {
225   var dirPath = generateName(affixes, 'd-');
226   fs.mkdir(dirPath, 0700, function(err) {
227     if (!err) {
228       deleteDirOnExit(dirPath);
229     }
230     if (callback) {
231       callback(err, dirPath);
232     }
233   });
234 }
235
236 function mkdirSync(affixes) {
237   var dirPath = generateName(affixes, 'd-');
238   fs.mkdirSync(dirPath, 0700);
239   deleteDirOnExit(dirPath);
240   return dirPath;
241 }
242
243 /* FILES */
244
245 function open(affixes, callback) {
246   var filePath = generateName(affixes, 'f-');
247   fs.open(filePath, RDWR_EXCL, 0600, function(err, fd) {
248     if (!err) {
249       deleteFileOnExit(filePath);
250     }
251     if (callback) {
252       callback(err, {path: filePath, fd: fd});
253     }
254   });
255 }
256
257 function openSync(affixes) {
258   var filePath = generateName(affixes, 'f-');
259   var fd = fs.openSync(filePath, RDWR_EXCL, 0600);
260   deleteFileOnExit(filePath);
261   return {path: filePath, fd: fd};
262 }
263
264 function createWriteStream(affixes) {
265   var filePath = generateName(affixes, 's-');
266   var stream = fs.createWriteStream(filePath, {flags: RDWR_EXCL, mode: 0600});
267   deleteFileOnExit(filePath);
268   return stream;
269 }
270
271 /* EXPORTS */
272 // Settings
273 exports.dir               = path.resolve(osTmpdir());
274 exports.track             = track;
275 // Functions
276 exports.mkdir             = mkdir;
277 exports.mkdirSync         = mkdirSync;
278 exports.open              = open;
279 exports.openSync          = openSync;
280 exports.path              = generateName;
281 exports.cleanup           = cleanup;
282 exports.cleanupSync       = cleanupSync;
283 exports.createWriteStream = createWriteStream;