index.js 52 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931
  1. /* global Bare */
  2. const EventEmitter = require('bare-events')
  3. const path = require('bare-path')
  4. const { Readable, Writable } = require('streamx')
  5. const binding = require('./binding')
  6. const isWindows = Bare.platform === 'win32'
  7. const constants = exports.constants = {
  8. O_RDWR: binding.O_RDWR,
  9. O_RDONLY: binding.O_RDONLY,
  10. O_WRONLY: binding.O_WRONLY,
  11. O_CREAT: binding.O_CREAT,
  12. O_TRUNC: binding.O_TRUNC,
  13. O_APPEND: binding.O_APPEND,
  14. F_OK: binding.F_OK || 0,
  15. R_OK: binding.R_OK || 0,
  16. W_OK: binding.W_OK || 0,
  17. X_OK: binding.X_OK || 0,
  18. S_IFMT: binding.S_IFMT,
  19. S_IFREG: binding.S_IFREG,
  20. S_IFDIR: binding.S_IFDIR,
  21. S_IFCHR: binding.S_IFCHR,
  22. S_IFLNK: binding.S_IFLNK,
  23. S_IFBLK: binding.S_IFBLK || 0,
  24. S_IFIFO: binding.S_IFIFO || 0,
  25. S_IFSOCK: binding.S_IFSOCK || 0,
  26. S_IRUSR: binding.S_IRUSR || 0,
  27. S_IWUSR: binding.S_IWUSR || 0,
  28. S_IXUSR: binding.S_IXUSR || 0,
  29. S_IRGRP: binding.S_IRGRP || 0,
  30. S_IWGRP: binding.S_IWGRP || 0,
  31. S_IXGRP: binding.S_IXGRP || 0,
  32. S_IROTH: binding.S_IROTH || 0,
  33. S_IWOTH: binding.S_IWOTH || 0,
  34. S_IXOTH: binding.S_IXOTH || 0,
  35. UV_DIRENT_UNKNOWN: binding.UV_DIRENT_UNKNOWN,
  36. UV_DIRENT_FILE: binding.UV_DIRENT_FILE,
  37. UV_DIRENT_DIR: binding.UV_DIRENT_DIR,
  38. UV_DIRENT_LINK: binding.UV_DIRENT_LINK,
  39. UV_DIRENT_FIFO: binding.UV_DIRENT_FIFO,
  40. UV_DIRENT_SOCKET: binding.UV_DIRENT_SOCKET,
  41. UV_DIRENT_CHAR: binding.UV_DIRENT_CHAR,
  42. UV_DIRENT_BLOCK: binding.UV_DIRENT_BLOCK,
  43. UV_FS_SYMLINK_DIR: binding.UV_FS_SYMLINK_DIR,
  44. UV_FS_SYMLINK_JUNCTION: binding.UV_FS_SYMLINK_JUNCTION
  45. }
  46. const reqs = []
  47. let used = 0
  48. const fs = {
  49. handle: Buffer.allocUnsafe(binding.sizeofFS)
  50. }
  51. binding.init(fs.handle, fs, onresponse)
  52. Bare.on('exit', () => binding.destroy(fs.handle))
  53. // Lightly-modified from the Node FS internal utils.
  54. function flagsToNumber (flags) {
  55. switch (flags) {
  56. case 'r' : return constants.O_RDONLY
  57. case 'rs' : // Fall through.
  58. case 'sr' : return constants.O_RDONLY | constants.O_SYNC
  59. case 'r+' : return constants.O_RDWR
  60. case 'rs+' : // Fall through.
  61. case 'sr+' : return constants.O_RDWR | constants.O_SYNC
  62. case 'w' : return constants.O_TRUNC | constants.O_CREAT | constants.O_WRONLY
  63. case 'wx' : // Fall through.
  64. case 'xw' : return constants.O_TRUNC | constants.O_CREAT | constants.O_WRONLY | constants.O_EXCL
  65. case 'w+' : return constants.O_TRUNC | constants.O_CREAT | constants.O_RDWR
  66. case 'wx+': // Fall through.
  67. case 'xw+': return constants.O_TRUNC | constants.O_CREAT | constants.O_RDWR | constants.O_EXCL
  68. case 'a' : return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY
  69. case 'ax' : // Fall through.
  70. case 'xa' : return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | constants.O_EXCL
  71. case 'as' : // Fall through.
  72. case 'sa' : return constants.O_APPEND | constants.O_CREAT | constants.O_WRONLY | constants.O_SYNC
  73. case 'a+' : return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR
  74. case 'ax+': // Fall through.
  75. case 'xa+': return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR | constants.O_EXCL
  76. case 'as+': // Fall through.
  77. case 'sa+': return constants.O_APPEND | constants.O_CREAT | constants.O_RDWR | constants.O_SYNC
  78. }
  79. throw typeError('ERR_INVALID_ARG_VALUE', `Invalid value in flags: ${flags}`)
  80. }
  81. function modeToNumber (mode) {
  82. mode = parseInt(mode, 8)
  83. if (isNaN(mode)) throw typeError('ERR_INVALID_ARG_VALUE', 'Mode must be a number or octal string')
  84. return mode
  85. }
  86. function alloc () {
  87. const handle = Buffer.alloc(binding.sizeofFSReq)
  88. binding.initReq(fs.handle, handle)
  89. const view = new Uint32Array(handle.buffer, handle.byteOffset + binding.offsetofFSReqID, 1)
  90. view[0] = reqs.length
  91. const req = {
  92. handle,
  93. view,
  94. type: 0,
  95. callback: null
  96. }
  97. used++
  98. reqs.push(req)
  99. return req
  100. }
  101. function getReq () {
  102. return used === reqs.length ? alloc() : reqs[used++]
  103. }
  104. function onresponse (id, err, result) {
  105. const req = reqs[id]
  106. used--
  107. if (used !== id) {
  108. const u = reqs[used]
  109. reqs[u.view[0] = id] = u
  110. reqs[req.view[0] = used] = req
  111. }
  112. const callback = req.callback
  113. req.callback = null
  114. callback(err, result)
  115. }
  116. function open (filepath, flags, mode, cb) {
  117. if (typeof filepath !== 'string') {
  118. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  119. }
  120. if (typeof cb !== 'function') {
  121. if (typeof flags === 'function') {
  122. cb = flags
  123. flags = 'r'
  124. mode = 0o666
  125. } else if (typeof mode === 'function') {
  126. cb = mode
  127. mode = 0o666
  128. } else {
  129. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  130. }
  131. }
  132. if (typeof flags === 'string') flags = flagsToNumber(flags)
  133. if (typeof mode === 'string') mode = modeToNumber(mode)
  134. const req = getReq()
  135. req.callback = cb
  136. binding.open(req.handle, filepath, flags, mode)
  137. }
  138. function openSync (filepath, flags = 'r', mode = 0o666) {
  139. if (typeof filepath !== 'string') {
  140. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  141. }
  142. if (typeof flags === 'string') flags = flagsToNumber(flags)
  143. if (typeof mode === 'string') mode = modeToNumber(mode)
  144. return binding.openSync(filepath, flags, mode)
  145. }
  146. function close (fd, cb = noop) {
  147. if (typeof fd !== 'number') {
  148. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  149. }
  150. if (fd < 0 || fd > 0x7fffffff) {
  151. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  152. }
  153. if (typeof cb !== 'function') {
  154. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  155. }
  156. const req = getReq()
  157. req.callback = cb
  158. binding.close(req.handle, fd)
  159. }
  160. function closeSync (fd) {
  161. if (typeof fd !== 'number') {
  162. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  163. }
  164. if (fd < 0 || fd > 0x7fffffff) {
  165. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  166. }
  167. return binding.closeSync(fd)
  168. }
  169. function access (filepath, mode, cb) {
  170. if (typeof filepath !== 'string') {
  171. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  172. }
  173. if (typeof cb !== 'function') {
  174. if (typeof mode === 'function') {
  175. cb = mode
  176. mode = constants.F_OK
  177. } else {
  178. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  179. }
  180. }
  181. const req = getReq()
  182. req.callback = cb
  183. binding.access(req.handle, filepath, mode)
  184. }
  185. function accessSync (filepath, mode = constants.F_OK) {
  186. if (typeof filepath !== 'string') {
  187. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  188. }
  189. binding.accessSync(filepath, mode)
  190. }
  191. function exists (filepath, cb) {
  192. if (typeof filepath !== 'string') {
  193. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  194. }
  195. if (typeof cb !== 'function') {
  196. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  197. }
  198. return access(filepath, (err) => cb(!!err)) // eslint-disable-line n/no-callback-literal
  199. }
  200. function existsSync (filepath) {
  201. if (typeof filepath !== 'string') {
  202. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  203. }
  204. try {
  205. accessSync(filepath)
  206. return true
  207. } catch {
  208. return false
  209. }
  210. }
  211. function read (fd, buffer, offset, len, pos, cb) {
  212. if (typeof fd !== 'number') {
  213. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  214. }
  215. if (fd < 0 || fd > 0x7fffffff) {
  216. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  217. }
  218. if (!Buffer.isBuffer(buffer) && !ArrayBuffer.isView(buffer)) {
  219. throw typeError('ERR_INVALID_ARG_TYPE', 'Buffer must be a buffer. Received type ' + (typeof buffer) + ' (' + buffer + ')')
  220. }
  221. if (typeof cb !== 'function') {
  222. if (typeof offset === 'function') {
  223. cb = offset
  224. offset = 0
  225. len = buffer.byteLength
  226. pos = -1
  227. } else if (typeof len === 'function') {
  228. cb = len
  229. len = buffer.byteLength - offset
  230. pos = -1
  231. } else if (typeof pos === 'function') {
  232. cb = pos
  233. pos = -1
  234. } else {
  235. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  236. }
  237. }
  238. if (typeof pos !== 'number') pos = -1
  239. const req = getReq()
  240. req.callback = cb
  241. binding.read(req.handle, fd, buffer, offset, len, pos)
  242. }
  243. function readSync (fd, buffer, offset = 0, len = buffer.byteLength - offset, pos = -1) {
  244. if (typeof fd !== 'number') {
  245. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  246. }
  247. if (fd < 0 || fd > 0x7fffffff) {
  248. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  249. }
  250. if (!Buffer.isBuffer(buffer) && !ArrayBuffer.isView(buffer)) {
  251. throw typeError('ERR_INVALID_ARG_TYPE', 'Buffer must be a buffer. Received type ' + (typeof buffer) + ' (' + buffer + ')')
  252. }
  253. return binding.readSync(fd, buffer, offset, len, pos)
  254. }
  255. function readv (fd, buffers, pos, cb) {
  256. if (typeof fd !== 'number') {
  257. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  258. }
  259. if (fd < 0 || fd > 0x7fffffff) {
  260. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  261. }
  262. if (typeof pos === 'function') {
  263. cb = pos
  264. pos = -1
  265. } else if (typeof cb !== 'function') {
  266. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  267. }
  268. if (typeof pos !== 'number') pos = -1
  269. const req = getReq()
  270. req.callback = cb
  271. binding.readv(req.handle, fd, buffers, pos)
  272. }
  273. function write (fd, buffer, offset, len, pos, cb) {
  274. if (typeof fd !== 'number') {
  275. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  276. }
  277. if (fd < 0 || fd > 0x7fffffff) {
  278. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  279. }
  280. if (!Buffer.isBuffer(buffer) && !ArrayBuffer.isView(buffer)) {
  281. throw typeError('ERR_INVALID_ARG_TYPE', 'Buffer must be a buffer. Received type ' + (typeof buffer) + ' (' + buffer + ')')
  282. }
  283. if (typeof cb !== 'function') {
  284. if (typeof offset === 'function') {
  285. cb = offset
  286. offset = 0
  287. len = buffer.byteLength
  288. pos = -1
  289. } else if (typeof len === 'function') {
  290. cb = len
  291. len = buffer.byteLength - offset
  292. pos = -1
  293. } else if (typeof pos === 'function') {
  294. cb = pos
  295. pos = -1
  296. } else {
  297. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  298. }
  299. }
  300. if (typeof pos !== 'number') pos = -1
  301. const req = getReq()
  302. req.callback = cb
  303. binding.write(req.handle, fd, buffer, offset, len, pos)
  304. }
  305. function writeSync (fd, buffer, offset = 0, len = buffer.byteLength - offset, pos = -1) {
  306. if (typeof fd !== 'number') {
  307. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  308. }
  309. if (fd < 0 || fd > 0x7fffffff) {
  310. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  311. }
  312. if (!Buffer.isBuffer(buffer) && !ArrayBuffer.isView(buffer)) {
  313. throw typeError('ERR_INVALID_ARG_TYPE', 'Buffer must be a buffer. Received type ' + (typeof buffer) + ' (' + buffer + ')')
  314. }
  315. return binding.writeSync(fd, buffer, offset, len, pos)
  316. }
  317. function writev (fd, buffers, pos, cb) {
  318. if (typeof fd !== 'number') {
  319. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  320. }
  321. if (fd < 0 || fd > 0x7fffffff) {
  322. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  323. }
  324. if (typeof pos === 'function') {
  325. cb = pos
  326. pos = -1
  327. } else if (typeof cb !== 'function') {
  328. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  329. }
  330. if (typeof pos !== 'number') pos = -1
  331. const req = getReq()
  332. req.callback = cb
  333. binding.writev(req.handle, fd, buffers, pos)
  334. }
  335. function stat (filepath, cb) {
  336. if (typeof filepath !== 'string') {
  337. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  338. }
  339. if (typeof cb !== 'function') {
  340. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  341. }
  342. const data = new Array(Stats.length)
  343. const req = getReq()
  344. req.callback = function (err, _) {
  345. if (err) cb(err, null)
  346. else cb(null, new Stats(...data))
  347. }
  348. binding.stat(req.handle, filepath, data)
  349. }
  350. function statSync (filepath) {
  351. if (typeof filepath !== 'string') {
  352. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  353. }
  354. return new Stats(...binding.statSync(filepath))
  355. }
  356. function lstat (filepath, cb) {
  357. if (typeof filepath !== 'string') {
  358. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  359. }
  360. if (typeof cb !== 'function') {
  361. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  362. }
  363. const data = new Array(Stats.length)
  364. const req = getReq()
  365. req.callback = function (err, _) {
  366. if (err) cb(err, null)
  367. else cb(null, new Stats(...data))
  368. }
  369. binding.lstat(req.handle, filepath, data)
  370. }
  371. function lstatSync (filepath) {
  372. if (typeof filepath !== 'string') {
  373. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  374. }
  375. return new Stats(...binding.lstatSync(filepath))
  376. }
  377. function fstat (fd, cb) {
  378. if (typeof fd !== 'number') {
  379. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  380. }
  381. if (fd < 0 || fd > 0x7fffffff) {
  382. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  383. }
  384. if (typeof cb !== 'function') {
  385. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  386. }
  387. const data = new Array(Stats.length)
  388. const req = getReq()
  389. req.callback = function (err, _) {
  390. if (err) cb(err, null)
  391. else cb(null, new Stats(...data))
  392. }
  393. binding.fstat(req.handle, fd, data)
  394. }
  395. function fstatSync (fd) {
  396. if (typeof fd !== 'number') {
  397. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  398. }
  399. if (fd < 0 || fd > 0x7fffffff) {
  400. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  401. }
  402. return new Stats(...binding.fstatSync(fd))
  403. }
  404. function ftruncate (fd, len, cb) {
  405. if (typeof fd !== 'number') {
  406. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  407. }
  408. if (fd < 0 || fd > 0x7fffffff) {
  409. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  410. }
  411. if (typeof len === 'function') {
  412. cb = len
  413. len = 0
  414. } else if (typeof cb !== 'function') {
  415. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  416. }
  417. const req = getReq()
  418. req.callback = cb
  419. binding.ftruncate(req.handle, fd, len)
  420. }
  421. function chmod (filepath, mode, cb) {
  422. if (typeof filepath !== 'string') {
  423. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  424. }
  425. if (typeof mode === 'string') mode = modeToNumber(mode)
  426. const req = getReq()
  427. req.callback = cb
  428. binding.chmod(req.handle, filepath, mode)
  429. }
  430. function chmodSync (filepath, mode) {
  431. if (typeof filepath !== 'string') {
  432. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  433. }
  434. if (typeof mode === 'string') mode = modeToNumber(mode)
  435. binding.chmodSync(filepath, mode)
  436. }
  437. function fchmod (fd, mode, cb) {
  438. if (typeof fd !== 'number') {
  439. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  440. }
  441. if (fd < 0 || fd > 0x7fffffff) {
  442. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  443. }
  444. if (typeof mode === 'string') mode = modeToNumber(mode)
  445. const req = getReq()
  446. req.callback = cb
  447. binding.fchmod(req.handle, fd, mode)
  448. }
  449. function fchmodSync (fd, mode) {
  450. if (typeof fd !== 'number') {
  451. throw typeError('ERR_INVALID_ARG_TYPE', 'File descriptor must be a number. Received type ' + (typeof fd) + ' (' + fd + ')')
  452. }
  453. if (fd < 0 || fd > 0x7fffffff) {
  454. throw typeError('ERR_OUT_OF_RANGE', 'File descriptor is out of range. It must be >= 0 && <= 2147483647. Received ' + fd)
  455. }
  456. if (typeof mode === 'string') mode = modeToNumber(mode)
  457. binding.fchmodSync(fd, mode)
  458. }
  459. function mkdirRecursive (filepath, mode, cb) {
  460. mkdir(filepath, { mode }, function (err) {
  461. if (err === null) return cb(null, 0, null)
  462. if (err.code !== 'ENOENT') {
  463. stat(filepath, function (e, st) {
  464. if (e) return cb(e, e.errno, null)
  465. if (st.isDirectory()) return cb(null, 0, null)
  466. cb(err, err.errno, null)
  467. })
  468. return
  469. }
  470. while (filepath.endsWith(path.sep)) filepath = filepath.slice(0, -1)
  471. const i = filepath.lastIndexOf(path.sep)
  472. if (i <= 0) return cb(err, err.errno, null)
  473. mkdirRecursive(filepath.slice(0, i), mode, function (err) {
  474. if (err) return cb(err, err.errno, null)
  475. mkdir(filepath, { mode }, function (err) {
  476. if (err === null) return cb(null, 0, null)
  477. stat(filepath, function (e, st) {
  478. if (e) return cb(e, e.errno, null)
  479. if (st.isDirectory()) return cb(null, 0, null)
  480. cb(err, err.errno, null)
  481. })
  482. })
  483. })
  484. })
  485. }
  486. function mkdir (filepath, opts, cb) {
  487. if (typeof filepath !== 'string') {
  488. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  489. }
  490. if (typeof opts === 'function') {
  491. cb = opts
  492. opts = { mode: 0o777 }
  493. } else if (typeof cb !== 'function') {
  494. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  495. }
  496. if (typeof opts === 'number') opts = { mode: opts }
  497. else if (!opts) opts = {}
  498. const mode = typeof opts.mode === 'number' ? opts.mode : 0o777
  499. if (opts.recursive) return mkdirRecursive(filepath.replace(/\//g, path.sep), mode, cb)
  500. const req = getReq()
  501. req.callback = cb
  502. binding.mkdir(req.handle, filepath, mode)
  503. }
  504. function mkdirRecursiveSync (filepath, mode) {
  505. try {
  506. mkdirSync(filepath, { mode })
  507. } catch (err) {
  508. if (err.code !== 'ENOENT' && statSync(filepath).isDirectory()) {
  509. return
  510. }
  511. while (filepath.endsWith(path.sep)) filepath = filepath.slice(0, -1)
  512. const i = filepath.lastIndexOf(path.sep)
  513. if (i <= 0) throw err
  514. mkdirRecursiveSync(filepath.slice(0, i), { mode })
  515. try {
  516. mkdirSync(filepath, { mode })
  517. } catch (err) {
  518. if (statSync(filepath).isDirectory()) {
  519. return
  520. }
  521. throw err
  522. }
  523. }
  524. }
  525. function mkdirSync (filepath, opts) {
  526. if (typeof filepath !== 'string') {
  527. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  528. }
  529. if (typeof opts === 'number') opts = { mode: opts }
  530. else if (!opts) opts = {}
  531. const mode = typeof opts.mode === 'number' ? opts.mode : 0o777
  532. if (opts.recursive) return mkdirRecursiveSync(filepath.replace(/\//g, path.sep), mode)
  533. binding.mkdirSync(filepath, mode)
  534. }
  535. function rmdir (filepath, cb) {
  536. if (typeof filepath !== 'string') {
  537. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  538. }
  539. if (typeof cb !== 'function') {
  540. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  541. }
  542. const req = getReq()
  543. req.callback = cb
  544. binding.rmdir(req.handle, filepath)
  545. }
  546. function rmdirSync (filepath) {
  547. if (typeof filepath !== 'string') {
  548. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  549. }
  550. binding.rmdirSync(filepath)
  551. }
  552. function rmRecursive (filepath, opts, cb) {
  553. rmdir(filepath, function (err) {
  554. if (err === null) return cb(null)
  555. if (err.code !== 'ENOTEMPTY') return cb(err)
  556. readdir(filepath, function (err, files) {
  557. if (err) return cb(err)
  558. if (files.length === 0) return rmdir(filepath, cb)
  559. let missing = files.length
  560. let done = false
  561. for (const file of files) {
  562. rm(filepath + path.sep + file, opts, function (err) {
  563. if (done) return
  564. if (err) {
  565. done = true
  566. return cb(err)
  567. }
  568. if (--missing === 0) rmdir(filepath, cb)
  569. })
  570. }
  571. })
  572. })
  573. }
  574. function rm (filepath, opts, cb) {
  575. if (typeof filepath !== 'string') {
  576. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  577. }
  578. if (typeof opts === 'function') {
  579. cb = opts
  580. opts = {}
  581. } else if (typeof cb !== 'function') {
  582. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  583. }
  584. if (!opts) opts = {}
  585. lstat(filepath, function (err, st) {
  586. if (err) {
  587. return cb(err.code === 'ENOENT' && opts.force ? null : err)
  588. }
  589. if (st.isDirectory()) {
  590. if (opts.recursive) return rmRecursive(filepath, opts, cb)
  591. const err = new Error('is a directory')
  592. err.code = 'EISDIR'
  593. return cb(err)
  594. }
  595. unlink(filepath, cb)
  596. })
  597. }
  598. function rmRecursiveSync (filepath, opts) {
  599. try {
  600. rmdirSync(filepath)
  601. } catch (err) {
  602. if (err.code !== 'ENOTEMPTY') throw err
  603. const files = readdirSync(filepath)
  604. for (const file of files) {
  605. rmSync(filepath + path.sep + file, opts)
  606. }
  607. rmdirSync(filepath)
  608. }
  609. }
  610. function rmSync (filepath, opts) {
  611. if (typeof filepath !== 'string') {
  612. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  613. }
  614. if (!opts) opts = {}
  615. try {
  616. const st = lstatSync(filepath)
  617. if (st.isDirectory()) {
  618. if (opts.recursive) return rmRecursiveSync(filepath, opts)
  619. const err = new Error('is a directory')
  620. err.code = 'EISDIR'
  621. throw err
  622. }
  623. unlinkSync(filepath)
  624. } catch (err) {
  625. if (err.code !== 'ENOENT' || !opts.force) throw err
  626. }
  627. }
  628. function unlink (filepath, cb) {
  629. if (typeof filepath !== 'string') {
  630. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  631. }
  632. if (typeof cb !== 'function') {
  633. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  634. }
  635. const req = getReq()
  636. req.callback = cb
  637. binding.unlink(req.handle, filepath)
  638. }
  639. function unlinkSync (filepath) {
  640. if (typeof filepath !== 'string') {
  641. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  642. }
  643. binding.unlinkSync(filepath)
  644. }
  645. function rename (src, dst, cb) {
  646. if (typeof src !== 'string') {
  647. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof src) + ' (' + src + ')')
  648. }
  649. if (typeof dst !== 'string') {
  650. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof dst) + ' (' + dst + ')')
  651. }
  652. if (typeof cb !== 'function') {
  653. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  654. }
  655. const req = getReq()
  656. req.callback = cb
  657. binding.rename(req.handle, src, dst)
  658. }
  659. function renameSync (src, dst) {
  660. if (typeof src !== 'string') {
  661. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof src) + ' (' + src + ')')
  662. }
  663. if (typeof dst !== 'string') {
  664. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof dst) + ' (' + dst + ')')
  665. }
  666. binding.renameSync(src, dst)
  667. }
  668. function realpath (filepath, opts, cb) {
  669. if (typeof filepath !== 'string') {
  670. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  671. }
  672. if (typeof opts === 'function') {
  673. cb = opts
  674. opts = {}
  675. } else if (typeof cb !== 'function') {
  676. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  677. }
  678. if (typeof opts === 'string') opts = { encoding: opts }
  679. else if (!opts) opts = {}
  680. const {
  681. encoding = 'utf8'
  682. } = opts
  683. const data = Buffer.allocUnsafe(binding.sizeofFSPath)
  684. const req = getReq()
  685. req.callback = function (err, _) {
  686. if (err) return cb(err, null)
  687. let path = data.subarray(0, data.indexOf(0))
  688. if (encoding !== 'buffer') path = path.toString(encoding)
  689. cb(null, path)
  690. }
  691. binding.realpath(req.handle, filepath, data)
  692. }
  693. function realpathSync (filepath, opts) {
  694. if (typeof filepath !== 'string') {
  695. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  696. }
  697. if (typeof opts === 'string') opts = { encoding: opts }
  698. else if (!opts) opts = {}
  699. const {
  700. encoding = 'utf8'
  701. } = opts
  702. const data = Buffer.allocUnsafe(binding.sizeofFSPath)
  703. binding.realpathSync(filepath, data)
  704. filepath = data.subarray(0, data.indexOf(0))
  705. if (encoding !== 'buffer') filepath = filepath.toString(encoding)
  706. return filepath
  707. }
  708. function readlink (filepath, opts, cb) {
  709. if (typeof filepath !== 'string') {
  710. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  711. }
  712. if (typeof opts === 'function') {
  713. cb = opts
  714. opts = {}
  715. } else if (typeof cb !== 'function') {
  716. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  717. }
  718. if (typeof opts === 'string') opts = { encoding: opts }
  719. else if (!opts) opts = {}
  720. const {
  721. encoding = 'utf8'
  722. } = opts
  723. const data = Buffer.allocUnsafe(binding.sizeofFSPath)
  724. const req = getReq()
  725. req.callback = function (err, _) {
  726. if (err) return cb(err, null)
  727. let path = data.subarray(0, data.indexOf(0))
  728. if (encoding !== 'buffer') path = path.toString(encoding)
  729. cb(null, path)
  730. }
  731. binding.readlink(req.handle, filepath, data)
  732. }
  733. function readlinkSync (filepath, opts) {
  734. if (typeof filepath !== 'string') {
  735. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  736. }
  737. if (typeof opts === 'string') opts = { encoding: opts }
  738. else if (!opts) opts = {}
  739. const {
  740. encoding = 'utf8'
  741. } = opts
  742. const data = Buffer.allocUnsafe(binding.sizeofFSPath)
  743. binding.readlinkSync(filepath, data)
  744. filepath = data.subarray(0, data.indexOf(0))
  745. if (encoding !== 'buffer') filepath = filepath.toString(encoding)
  746. return filepath
  747. }
  748. function normalizeSymlinkTarget (target, type, filepath) {
  749. if (isWindows) {
  750. if (type === 'junction') target = path.resolve(filepath, '..', target)
  751. if (path.isAbsolute(target)) return path.toNamespacedPath(target)
  752. return target.replace(/\//g, path.sep)
  753. }
  754. return target
  755. }
  756. function symlink (target, filepath, type, cb) {
  757. if (typeof target !== 'string') {
  758. throw typeError('ERR_INVALID_ARG_TYPE', 'Target must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  759. }
  760. if (typeof filepath !== 'string') {
  761. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  762. }
  763. if (typeof type === 'function') {
  764. cb = type
  765. type = null
  766. } else if (typeof cb !== 'function') {
  767. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  768. }
  769. if (typeof type === 'string') {
  770. switch (type) {
  771. case 'file':
  772. type = 0
  773. break
  774. case 'dir':
  775. type = constants.UV_FS_SYMLINK_DIR
  776. break
  777. case 'junction':
  778. type = constants.UV_FS_SYMLINK_JUNCTION
  779. break
  780. default:
  781. throw typeError('ERR_FS_INVALID_SYMLINK_TYPE', 'Symlink type must be one of "dir", "file", or "junction". Received "' + type + '"')
  782. }
  783. } else if (typeof type !== 'number') {
  784. if (isWindows) {
  785. target = path.resolve(filepath, '..', target)
  786. stat(target, (err, st) => {
  787. type = err === null && st.isDirectory() ? constants.UV_FS_SYMLINK_DIR : constants.UV_FS_SYMLINK_JUNCTION
  788. symlink(target, filepath, type, cb)
  789. })
  790. return
  791. }
  792. type = 0
  793. }
  794. const req = getReq()
  795. req.callback = cb
  796. binding.symlink(req.handle, normalizeSymlinkTarget(target), path.toNamespacedPath(filepath), type)
  797. }
  798. function symlinkSync (target, filepath, type) {
  799. if (typeof target !== 'string') {
  800. throw typeError('ERR_INVALID_ARG_TYPE', 'Target must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  801. }
  802. if (typeof filepath !== 'string') {
  803. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  804. }
  805. if (typeof type === 'string') {
  806. switch (type) {
  807. case 'file':
  808. type = 0
  809. break
  810. case 'dir':
  811. type = constants.UV_FS_SYMLINK_DIR
  812. break
  813. case 'junction':
  814. type = constants.UV_FS_SYMLINK_JUNCTION
  815. break
  816. default:
  817. throw typeError('ERR_FS_INVALID_SYMLINK_TYPE', 'Symlink type must be one of "dir", "file", or "junction". Received "' + type + '"')
  818. }
  819. } else if (typeof type !== 'number') {
  820. if (isWindows) {
  821. target = path.resolve(filepath, '..', target)
  822. type = statSync(target).isDirectory() ? constants.UV_FS_SYMLINK_DIR : constants.UV_FS_SYMLINK_JUNCTION
  823. } else {
  824. type = 0
  825. }
  826. }
  827. binding.symlinkSync(normalizeSymlinkTarget(target), path.toNamespacedPath(filepath), type)
  828. }
  829. function opendir (filepath, opts, cb) {
  830. if (typeof filepath !== 'string') {
  831. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  832. }
  833. if (typeof opts === 'function') {
  834. cb = opts
  835. opts = {}
  836. } else if (typeof cb !== 'function') {
  837. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  838. }
  839. if (typeof opts === 'string') opts = { encoding: opts }
  840. else if (!opts) opts = {}
  841. const data = Buffer.allocUnsafe(binding.sizeofFSDir)
  842. const req = getReq()
  843. req.callback = function (err, _) {
  844. if (err) return cb(err, null)
  845. cb(null, new Dir(filepath, data, opts))
  846. }
  847. binding.opendir(req.handle, filepath, data)
  848. }
  849. function opendirSync (filepath, opts) {
  850. if (typeof filepath !== 'string') {
  851. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  852. }
  853. if (typeof opts === 'string') opts = { encoding: opts }
  854. else if (!opts) opts = {}
  855. const data = Buffer.allocUnsafe(binding.sizeofFSDir)
  856. binding.opendirSync(filepath, data)
  857. return new Dir(filepath, data, opts)
  858. }
  859. function readdir (filepath, opts, cb) {
  860. if (typeof filepath !== 'string') {
  861. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  862. }
  863. if (typeof opts === 'function') {
  864. cb = opts
  865. opts = {}
  866. } else if (typeof cb !== 'function') {
  867. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  868. }
  869. if (typeof opts === 'string') opts = { encoding: opts }
  870. else if (!opts) opts = {}
  871. const {
  872. withFileTypes = false
  873. } = opts
  874. opendir(filepath, opts, async (err, dir) => {
  875. if (err) return cb(err, null)
  876. const result = []
  877. for await (const entry of dir) {
  878. result.push(withFileTypes ? entry : entry.name)
  879. }
  880. cb(null, result)
  881. })
  882. }
  883. function readdirSync (filepath, opts) {
  884. if (typeof filepath !== 'string') {
  885. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  886. }
  887. if (typeof opts === 'string') opts = { encoding: opts }
  888. else if (!opts) opts = {}
  889. const {
  890. withFileTypes = false
  891. } = opts
  892. const dir = opendirSync(filepath, opts)
  893. const result = []
  894. while (true) {
  895. const entry = dir.readSync()
  896. if (entry === null) break
  897. result.push(withFileTypes ? entry : entry.name)
  898. }
  899. return result
  900. }
  901. function readFile (filepath, opts, cb) {
  902. if (typeof filepath !== 'string') {
  903. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  904. }
  905. if (typeof opts === 'function') {
  906. cb = opts
  907. opts = {}
  908. } else if (typeof cb !== 'function') {
  909. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  910. }
  911. if (typeof opts === 'string') opts = { encoding: opts }
  912. else if (!opts) opts = {}
  913. const {
  914. encoding = 'buffer'
  915. } = opts
  916. open(filepath, opts.flag || 'r', function (err, fd) {
  917. if (err) return cb(err)
  918. fstat(fd, function (err, st) {
  919. if (err) return closeAndError(err)
  920. let buffer = Buffer.allocUnsafe(st.size)
  921. let len = 0
  922. read(fd, buffer, loop)
  923. function loop (err, r) {
  924. if (err) return closeAndError(err)
  925. len += r
  926. if (r === 0 || len === buffer.byteLength) return done()
  927. read(fd, buffer.subarray(len), loop)
  928. }
  929. function done () {
  930. if (len !== buffer.byteLength) buffer = buffer.subarray(0, len)
  931. close(fd, function (err) {
  932. if (err) return cb(err)
  933. if (encoding !== 'buffer') buffer = buffer.toString(encoding)
  934. cb(null, buffer)
  935. })
  936. }
  937. })
  938. function closeAndError (err) {
  939. close(fd, function () {
  940. cb(err)
  941. })
  942. }
  943. })
  944. }
  945. function readFileSync (filepath, opts) {
  946. if (typeof filepath !== 'string') {
  947. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  948. }
  949. if (typeof opts === 'string') opts = { encoding: opts }
  950. else if (!opts) opts = {}
  951. const {
  952. encoding = 'buffer'
  953. } = opts
  954. const fd = openSync(filepath, opts.flag || 'r')
  955. try {
  956. const st = fstatSync(fd)
  957. let buffer = Buffer.allocUnsafe(st.size)
  958. let len = 0
  959. while (true) {
  960. const r = readSync(fd, len ? buffer.subarray(len) : buffer)
  961. len += r
  962. if (r === 0 || len === buffer.byteLength) break
  963. }
  964. if (len !== buffer.byteLength) buffer = buffer.subarray(0, len)
  965. if (encoding !== 'buffer') buffer = buffer.toString(encoding)
  966. return buffer
  967. } finally {
  968. try {
  969. closeSync(fd)
  970. } catch {}
  971. }
  972. }
  973. function writeFile (filepath, data, opts, cb) {
  974. if (typeof filepath !== 'string') {
  975. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  976. }
  977. if (typeof data !== 'string' && !Buffer.isBuffer(data) && !ArrayBuffer.isView(data)) {
  978. throw typeError('ERR_INVALID_ARG_TYPE', 'Data must be a string or buffer. Received type ' + (typeof data) + ' (' + data + ')')
  979. }
  980. if (typeof opts === 'function') {
  981. cb = opts
  982. opts = {}
  983. } else if (typeof cb !== 'function') {
  984. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  985. }
  986. if (typeof opts === 'string') opts = { encoding: opts }
  987. else if (!opts) opts = {}
  988. if (typeof data === 'string') data = Buffer.from(data, opts.encoding)
  989. open(filepath, opts.flag || 'w', opts.mode || 0o666, function (err, fd) {
  990. if (err) return cb(err)
  991. write(fd, data, loop)
  992. function loop (err, w) {
  993. if (err) return closeAndError(err)
  994. if (w === data.byteLength) return done()
  995. write(fd, data.subarray(w), loop)
  996. }
  997. function done () {
  998. close(fd, function (err) {
  999. if (err) return cb(err)
  1000. return cb(null)
  1001. })
  1002. }
  1003. function closeAndError (err) {
  1004. close(fd, function () {
  1005. cb(err)
  1006. })
  1007. }
  1008. })
  1009. }
  1010. function writeFileSync (filepath, data, opts) {
  1011. if (typeof filepath !== 'string') {
  1012. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  1013. }
  1014. if (typeof data !== 'string' && !Buffer.isBuffer(data) && !ArrayBuffer.isView(data)) {
  1015. throw typeError('ERR_INVALID_ARG_TYPE', 'Data must be a string or buffer. Received type ' + (typeof data) + ' (' + data + ')')
  1016. }
  1017. if (typeof opts === 'string') opts = { encoding: opts }
  1018. else if (!opts) opts = {}
  1019. if (typeof data === 'string') data = Buffer.from(data, opts.encoding)
  1020. const fd = openSync(filepath, opts.flag || 'w', opts.mode)
  1021. try {
  1022. let len = 0
  1023. while (true) {
  1024. len += writeSync(fd, len ? data.subarray(len) : data)
  1025. if (len === data.byteLength) break
  1026. }
  1027. } finally {
  1028. try {
  1029. closeSync(fd)
  1030. } catch {}
  1031. }
  1032. }
  1033. function appendFile (filepath, data, opts, cb) {
  1034. if (typeof filepath !== 'string') {
  1035. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  1036. }
  1037. if (typeof data !== 'string' && !Buffer.isBuffer(data) && !ArrayBuffer.isView(data)) {
  1038. throw typeError('ERR_INVALID_ARG_TYPE', 'Data must be a string or buffer. Received type ' + (typeof data) + ' (' + data + ')')
  1039. }
  1040. if (typeof opts === 'function') {
  1041. cb = opts
  1042. opts = {}
  1043. } else if (typeof cb !== 'function') {
  1044. throw typeError('ERR_INVALID_ARG_TYPE', 'Callback must be a function. Received type ' + (typeof cb) + ' (' + cb + ')')
  1045. }
  1046. if (typeof opts === 'string') opts = { encoding: opts }
  1047. else if (!opts) opts = {}
  1048. opts = { ...opts }
  1049. if (!opts.flags) opts.flag = 'a'
  1050. return writeFile(filepath, data, opts, cb)
  1051. }
  1052. function appendFileSync (filepath, data, opts) {
  1053. if (typeof filepath !== 'string') {
  1054. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  1055. }
  1056. if (typeof data !== 'string' && !Buffer.isBuffer(data) && !ArrayBuffer.isView(data)) {
  1057. throw typeError('ERR_INVALID_ARG_TYPE', 'Data must be a string or buffer. Received type ' + (typeof data) + ' (' + data + ')')
  1058. }
  1059. if (typeof opts === 'string') opts = { encoding: opts }
  1060. else if (!opts) opts = {}
  1061. opts = { ...opts }
  1062. if (!opts.flags) opts.flag = 'a'
  1063. return writeFileSync(filepath, data, opts)
  1064. }
  1065. function watch (filepath, opts, cb) {
  1066. if (typeof filepath !== 'string') {
  1067. throw typeError('ERR_INVALID_ARG_TYPE', 'Path must be a string. Received type ' + (typeof filepath) + ' (' + filepath + ')')
  1068. }
  1069. if (typeof opts === 'function') {
  1070. cb = opts
  1071. opts = {}
  1072. }
  1073. if (typeof opts === 'string') opts = { encoding: opts }
  1074. else if (!opts) opts = {}
  1075. const watcher = new Watcher(filepath, opts)
  1076. if (cb) watcher.on('change', cb)
  1077. return watcher
  1078. }
  1079. class Stats {
  1080. constructor (dev, mode, nlink, uid, gid, rdev, blksize, ino, size, blocks, atimeMs, mtimeMs, ctimeMs, birthtimeMs) {
  1081. this.dev = dev
  1082. this.mode = mode
  1083. this.nlink = nlink
  1084. this.uid = uid
  1085. this.gid = gid
  1086. this.rdev = rdev
  1087. this.blksize = blksize
  1088. this.ino = ino
  1089. this.size = size
  1090. this.blocks = blocks
  1091. this.atimeMs = atimeMs
  1092. this.mtimeMs = mtimeMs
  1093. this.ctimeMs = ctimeMs
  1094. this.birthtimeMs = birthtimeMs
  1095. this.atime = new Date(atimeMs)
  1096. this.mtime = new Date(mtimeMs)
  1097. this.ctime = new Date(ctimeMs)
  1098. this.birthtime = new Date(birthtimeMs)
  1099. }
  1100. isDirectory () {
  1101. return (this.mode & constants.S_IFMT) === constants.S_IFDIR
  1102. }
  1103. isFile () {
  1104. return (this.mode & constants.S_IFMT) === constants.S_IFREG
  1105. }
  1106. isBlockDevice () {
  1107. return (this.mode & constants.S_IFMT) === constants.S_IFBLK
  1108. }
  1109. isCharacterDevice () {
  1110. return (this.mode & constants.S_IFCHR) === constants.S_IFCHR
  1111. }
  1112. isFIFO () {
  1113. return (this.mode & constants.S_IFMT) === constants.S_IFIFO
  1114. }
  1115. isSymbolicLink () {
  1116. return (this.mode & constants.S_IFMT) === constants.S_IFLNK
  1117. }
  1118. isSocket () {
  1119. return (this.mode & constants.S_IFMT) === constants.S_IFSOCK
  1120. }
  1121. }
  1122. class Dir {
  1123. constructor (path, handle, opts = {}) {
  1124. const {
  1125. encoding = 'utf8',
  1126. bufferSize = 32
  1127. } = opts
  1128. this._handle = handle
  1129. this._dirents = Buffer.allocUnsafe(binding.sizeofFSDirent * bufferSize)
  1130. this._encoding = encoding
  1131. this._buffer = []
  1132. this._ended = false
  1133. this.path = path
  1134. }
  1135. read (cb) {
  1136. if (!cb) return promisify(this.read.bind(this))
  1137. if (this._buffer.length) return queueMicrotask(() => cb(null, this._buffer.shift()))
  1138. if (this._ended) return queueMicrotask(() => cb(null, null))
  1139. const data = []
  1140. const req = getReq()
  1141. req.callback = (err, _) => {
  1142. if (err) return cb(err, null)
  1143. if (data.length === 0) this._ended = true
  1144. else {
  1145. for (const entry of data) {
  1146. let name = Buffer.from(entry.name)
  1147. if (this._encoding !== 'buffer') name = name.toString(this._encoding)
  1148. this._buffer.push(new Dirent(this.path, name, entry.type))
  1149. }
  1150. }
  1151. if (this._ended) return cb(null, null)
  1152. cb(null, this._buffer.shift())
  1153. }
  1154. binding.readdir(req.handle, this._handle, this._dirents, data)
  1155. }
  1156. readSync () {
  1157. if (this._buffer.length) return this._buffer.shift()
  1158. if (this._ended) return null
  1159. const data = []
  1160. binding.readdirSync(this._handle, this._dirents, data)
  1161. if (data.length === 0) this._ended = true
  1162. else {
  1163. for (const entry of data) {
  1164. let name = Buffer.from(entry.name)
  1165. if (this._encoding !== 'buffer') name = name.toString(this._encoding)
  1166. this._buffer.push(new Dirent(this.path, name, entry.type))
  1167. }
  1168. }
  1169. if (this._ended) return null
  1170. return this._buffer.shift()
  1171. }
  1172. close (cb) {
  1173. if (!cb) return promisify(this.close.bind(this))
  1174. const req = getReq()
  1175. req.callback = (err, _) => {
  1176. this._handle = null
  1177. cb(err)
  1178. }
  1179. binding.closedir(req.handle, this._handle)
  1180. }
  1181. closeSync () {
  1182. binding.closedirSync(this._handle)
  1183. this._handle = null
  1184. }
  1185. [Symbol.iterator] () {
  1186. return {
  1187. next: () => {
  1188. if (this._buffer.length) {
  1189. return { done: false, value: this._buffer.shift() }
  1190. }
  1191. if (this._ended) {
  1192. return { done: true }
  1193. }
  1194. const entry = this.readSync()
  1195. if (entry) {
  1196. return { done: false, value: entry }
  1197. }
  1198. this.closeSync()
  1199. return { done: true }
  1200. }
  1201. }
  1202. }
  1203. [Symbol.asyncIterator] () {
  1204. return {
  1205. next: () => new Promise((resolve, reject) => {
  1206. if (this._buffer.length) {
  1207. return resolve({ done: false, value: this._buffer.shift() })
  1208. }
  1209. if (this._ended) {
  1210. return resolve({ done: true })
  1211. }
  1212. this.read((err, entry) => {
  1213. if (err) return reject(err)
  1214. if (entry) {
  1215. return resolve({ done: false, value: entry })
  1216. }
  1217. this.close((err) => err ? reject(err) : resolve({ done: true }))
  1218. })
  1219. })
  1220. }
  1221. }
  1222. }
  1223. class Dirent {
  1224. constructor (path, name, type) {
  1225. this.type = type
  1226. this.path = path
  1227. this.name = name
  1228. }
  1229. isFile () {
  1230. return this.type === constants.UV_DIRENT_FILE
  1231. }
  1232. isDirectory () {
  1233. return this.type === constants.UV_DIRENT_DIR
  1234. }
  1235. isSymbolicLink () {
  1236. return this.type === constants.UV_DIRENT_LINK
  1237. }
  1238. isFIFO () {
  1239. return this.type === constants.UV_DIRENT_FIFO
  1240. }
  1241. isSocket () {
  1242. return this.type === constants.UV_DIRENT_SOCKET
  1243. }
  1244. isCharacterDevice () {
  1245. return this.type === constants.UV_DIRENT_CHAR
  1246. }
  1247. isBlockDevice () {
  1248. return this.type === constants.UV_DIRENT_BLOCK
  1249. }
  1250. }
  1251. class FileWriteStream extends Writable {
  1252. constructor (path, opts = {}) {
  1253. super({ map })
  1254. this.path = path
  1255. this.fd = 0
  1256. this.flags = opts.flags || 'w'
  1257. this.mode = opts.mode || 0o666
  1258. }
  1259. _open (cb) {
  1260. open(this.path, this.flags, this.mode, (err, fd) => {
  1261. if (err) return cb(err)
  1262. this.fd = fd
  1263. cb(null)
  1264. })
  1265. }
  1266. _writev (datas, cb) {
  1267. writev(this.fd, datas, cb)
  1268. }
  1269. _destroy (cb) {
  1270. if (!this.fd) return cb(null)
  1271. close(this.fd, () => cb(null))
  1272. }
  1273. }
  1274. class FileReadStream extends Readable {
  1275. constructor (path, opts = {}) {
  1276. super()
  1277. this.path = path
  1278. this.fd = 0
  1279. this._offset = opts.start || 0
  1280. this._missing = 0
  1281. if (opts.length) this._missing = opts.length
  1282. else if (typeof opts.end === 'number') this._missing = opts.end - this._offset + 1
  1283. else this._missing = -1
  1284. }
  1285. _open (cb) {
  1286. open(this.path, constants.O_RDONLY, (err, fd) => {
  1287. if (err) return cb(err)
  1288. const onerror = (err) => close(fd, () => cb(err))
  1289. fstat(fd, (err, st) => {
  1290. if (err) return onerror(err)
  1291. if (!st.isFile()) return onerror(new Error(this.path + ' is not a file'))
  1292. this.fd = fd
  1293. if (this._missing === -1) this._missing = st.size
  1294. if (st.size < this._offset) {
  1295. this._offset = st.size
  1296. this._missing = 0
  1297. return cb(null)
  1298. }
  1299. if (st.size < this._offset + this._missing) {
  1300. this._missing = st.size - this._offset
  1301. return cb(null)
  1302. }
  1303. cb(null)
  1304. })
  1305. })
  1306. }
  1307. _read (cb) {
  1308. if (!this._missing) {
  1309. this.push(null)
  1310. return cb(null)
  1311. }
  1312. const data = Buffer.allocUnsafe(Math.min(this._missing, 65536))
  1313. read(this.fd, data, 0, data.byteLength, this._offset, (err, read) => {
  1314. if (err) return cb(err)
  1315. if (!read) {
  1316. this.push(null)
  1317. return cb(null)
  1318. }
  1319. if (this._missing < read) read = this._missing
  1320. this.push(data.subarray(0, read))
  1321. this._missing -= read
  1322. this._offset += read
  1323. if (!this._missing) this.push(null)
  1324. cb(null)
  1325. })
  1326. }
  1327. _destroy (cb) {
  1328. if (!this.fd) return cb(null)
  1329. close(this.fd, () => cb(null))
  1330. }
  1331. }
  1332. class Watcher extends EventEmitter {
  1333. constructor (path, opts) {
  1334. const {
  1335. persistent = true,
  1336. recursive = false,
  1337. encoding = 'utf8'
  1338. } = opts
  1339. super()
  1340. this._closed = false
  1341. this._encoding = encoding
  1342. this._handle = binding.watcherInit(path, recursive, this, this._onevent, this._onclose)
  1343. if (!persistent) this.unref()
  1344. }
  1345. _onevent (err, events, filename) {
  1346. if (err) {
  1347. this.close()
  1348. this.emit('error', err)
  1349. } else {
  1350. const path = this._encoding === 'buffer'
  1351. ? Buffer.from(filename)
  1352. : Buffer.from(filename).toString(this._encoding)
  1353. if (events & binding.UV_RENAME) {
  1354. this.emit('change', 'rename', path)
  1355. }
  1356. if (events & binding.UV_CHANGE) {
  1357. this.emit('change', 'change', path)
  1358. }
  1359. }
  1360. }
  1361. _onclose () {
  1362. this._handle = null
  1363. this.emit('close')
  1364. }
  1365. close () {
  1366. if (this._closed) return
  1367. this._closed = true
  1368. binding.watcherClose(this._handle)
  1369. }
  1370. ref () {
  1371. if (this._handle) binding.watcherRef(this._handle)
  1372. return this
  1373. }
  1374. unref () {
  1375. if (this._handle) binding.watcherUnref(this._handle)
  1376. return this
  1377. }
  1378. [Symbol.asyncIterator] () {
  1379. const buffer = []
  1380. let done = false
  1381. let error = null
  1382. let next = null
  1383. this
  1384. .on('change', (eventType, filename) => {
  1385. if (next) {
  1386. next.resolve({ done: false, value: { eventType, filename } })
  1387. next = null
  1388. } else {
  1389. buffer.push({ eventType, filename })
  1390. }
  1391. })
  1392. .on('error', (err) => {
  1393. done = true
  1394. error = err
  1395. if (next) {
  1396. next.reject(error)
  1397. next = null
  1398. }
  1399. })
  1400. .on('close', () => {
  1401. done = true
  1402. if (next) {
  1403. next.resolve({ done })
  1404. next = null
  1405. }
  1406. })
  1407. return {
  1408. next: () => new Promise((resolve, reject) => {
  1409. if (error) return reject(error)
  1410. if (buffer.length) return resolve({ done: false, value: buffer.shift() })
  1411. if (done) return resolve({ done })
  1412. next = { resolve, reject }
  1413. })
  1414. }
  1415. }
  1416. }
  1417. exports.promises = {}
  1418. function typeError (code, message) {
  1419. const error = new TypeError(message)
  1420. error.code = code
  1421. return error
  1422. }
  1423. function noop () {}
  1424. exports.access = access
  1425. exports.appendFile = appendFile
  1426. exports.chmod = chmod
  1427. exports.close = close
  1428. exports.exists = exists
  1429. exports.fchmod = fchmod
  1430. exports.fstat = fstat
  1431. exports.ftruncate = ftruncate
  1432. exports.lstat = lstat
  1433. exports.mkdir = mkdir
  1434. exports.open = open
  1435. exports.opendir = opendir
  1436. exports.read = read
  1437. exports.readFile = readFile
  1438. exports.readdir = readdir
  1439. exports.readlink = readlink
  1440. exports.readv = readv
  1441. exports.realpath = realpath
  1442. exports.rename = rename
  1443. exports.rm = rm
  1444. exports.rmdir = rmdir
  1445. exports.stat = stat
  1446. exports.symlink = symlink
  1447. exports.unlink = unlink
  1448. exports.watch = watch
  1449. exports.write = write
  1450. exports.writeFile = writeFile
  1451. exports.writev = writev
  1452. exports.accessSync = accessSync
  1453. exports.appendFileSync = appendFileSync
  1454. exports.chmodSync = chmodSync
  1455. exports.closeSync = closeSync
  1456. exports.existsSync = existsSync
  1457. exports.fchmodSync = fchmodSync
  1458. exports.fstatSync = fstatSync
  1459. exports.lstatSync = lstatSync
  1460. exports.mkdirSync = mkdirSync
  1461. exports.openSync = openSync
  1462. exports.opendirSync = opendirSync
  1463. exports.readFileSync = readFileSync
  1464. exports.readSync = readSync
  1465. exports.readdirSync = readdirSync
  1466. exports.readlinkSync = readlinkSync
  1467. exports.realpathSync = realpathSync
  1468. exports.renameSync = renameSync
  1469. exports.rmSync = rmSync
  1470. exports.rmdirSync = rmdirSync
  1471. exports.statSync = statSync
  1472. exports.symlinkSync = symlinkSync
  1473. exports.unlinkSync = unlinkSync
  1474. exports.writeFileSync = writeFileSync
  1475. exports.writeSync = writeSync
  1476. exports.promises.access = promisify(access)
  1477. exports.promises.appendFile = promisify(appendFile)
  1478. exports.promises.chmod = promisify(chmod)
  1479. exports.promises.lstat = promisify(lstat)
  1480. exports.promises.mkdir = promisify(mkdir)
  1481. exports.promises.opendir = promisify(opendir)
  1482. exports.promises.readFile = promisify(readFile)
  1483. exports.promises.readdir = promisify(readdir)
  1484. exports.promises.readlink = promisify(readlink)
  1485. exports.promises.realpath = promisify(realpath)
  1486. exports.promises.rename = promisify(rename)
  1487. exports.promises.rm = promisify(rm)
  1488. exports.promises.rmdir = promisify(rmdir)
  1489. exports.promises.stat = promisify(stat)
  1490. exports.promises.symlink = promisify(symlink)
  1491. exports.promises.unlink = promisify(unlink)
  1492. exports.promises.writeFile = promisify(writeFile)
  1493. exports.promises.watch = watch // Already async iterable
  1494. exports.Stats = Stats
  1495. exports.Dir = Dir
  1496. exports.Dirent = Dirent
  1497. exports.Watcher = Watcher
  1498. exports.ReadStream = FileReadStream
  1499. exports.createReadStream = function createReadStream (path, opts) {
  1500. return new FileReadStream(path, opts)
  1501. }
  1502. exports.WriteStream = FileWriteStream
  1503. exports.createWriteStream = function createWriteStream (path, opts) {
  1504. return new FileWriteStream(path, opts)
  1505. }
  1506. function promisify (fn) {
  1507. return function (...args) {
  1508. return new Promise((resolve, reject) => {
  1509. fn(...args, function (err, res) {
  1510. if (err) return reject(err)
  1511. resolve(res)
  1512. })
  1513. })
  1514. }
  1515. }
  1516. function map (data) {
  1517. return typeof data === 'string' ? Buffer.from(data) : data
  1518. }