source: trip-planner-front/node_modules/fs-extra/lib/util/stat.js@ 6a80231

Last change on this file since 6a80231 was 6a3a178, checked in by Ema <ema_spirova@…>, 3 years ago

initial commit

  • Property mode set to 100644
File size: 5.6 KB
Line 
1'use strict'
2
3const fs = require('graceful-fs')
4const path = require('path')
5
6const NODE_VERSION_MAJOR_WITH_BIGINT = 10
7const NODE_VERSION_MINOR_WITH_BIGINT = 5
8const NODE_VERSION_PATCH_WITH_BIGINT = 0
9const nodeVersion = process.versions.node.split('.')
10const nodeVersionMajor = Number.parseInt(nodeVersion[0], 10)
11const nodeVersionMinor = Number.parseInt(nodeVersion[1], 10)
12const nodeVersionPatch = Number.parseInt(nodeVersion[2], 10)
13
14function nodeSupportsBigInt () {
15 if (nodeVersionMajor > NODE_VERSION_MAJOR_WITH_BIGINT) {
16 return true
17 } else if (nodeVersionMajor === NODE_VERSION_MAJOR_WITH_BIGINT) {
18 if (nodeVersionMinor > NODE_VERSION_MINOR_WITH_BIGINT) {
19 return true
20 } else if (nodeVersionMinor === NODE_VERSION_MINOR_WITH_BIGINT) {
21 if (nodeVersionPatch >= NODE_VERSION_PATCH_WITH_BIGINT) {
22 return true
23 }
24 }
25 }
26 return false
27}
28
29function getStats (src, dest, cb) {
30 if (nodeSupportsBigInt()) {
31 fs.stat(src, { bigint: true }, (err, srcStat) => {
32 if (err) return cb(err)
33 fs.stat(dest, { bigint: true }, (err, destStat) => {
34 if (err) {
35 if (err.code === 'ENOENT') return cb(null, { srcStat, destStat: null })
36 return cb(err)
37 }
38 return cb(null, { srcStat, destStat })
39 })
40 })
41 } else {
42 fs.stat(src, (err, srcStat) => {
43 if (err) return cb(err)
44 fs.stat(dest, (err, destStat) => {
45 if (err) {
46 if (err.code === 'ENOENT') return cb(null, { srcStat, destStat: null })
47 return cb(err)
48 }
49 return cb(null, { srcStat, destStat })
50 })
51 })
52 }
53}
54
55function getStatsSync (src, dest) {
56 let srcStat, destStat
57 if (nodeSupportsBigInt()) {
58 srcStat = fs.statSync(src, { bigint: true })
59 } else {
60 srcStat = fs.statSync(src)
61 }
62 try {
63 if (nodeSupportsBigInt()) {
64 destStat = fs.statSync(dest, { bigint: true })
65 } else {
66 destStat = fs.statSync(dest)
67 }
68 } catch (err) {
69 if (err.code === 'ENOENT') return { srcStat, destStat: null }
70 throw err
71 }
72 return { srcStat, destStat }
73}
74
75function checkPaths (src, dest, funcName, cb) {
76 getStats(src, dest, (err, stats) => {
77 if (err) return cb(err)
78 const { srcStat, destStat } = stats
79 if (destStat && destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) {
80 return cb(new Error('Source and destination must not be the same.'))
81 }
82 if (srcStat.isDirectory() && isSrcSubdir(src, dest)) {
83 return cb(new Error(errMsg(src, dest, funcName)))
84 }
85 return cb(null, { srcStat, destStat })
86 })
87}
88
89function checkPathsSync (src, dest, funcName) {
90 const { srcStat, destStat } = getStatsSync(src, dest)
91 if (destStat && destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) {
92 throw new Error('Source and destination must not be the same.')
93 }
94 if (srcStat.isDirectory() && isSrcSubdir(src, dest)) {
95 throw new Error(errMsg(src, dest, funcName))
96 }
97 return { srcStat, destStat }
98}
99
100// recursively check if dest parent is a subdirectory of src.
101// It works for all file types including symlinks since it
102// checks the src and dest inodes. It starts from the deepest
103// parent and stops once it reaches the src parent or the root path.
104function checkParentPaths (src, srcStat, dest, funcName, cb) {
105 const srcParent = path.resolve(path.dirname(src))
106 const destParent = path.resolve(path.dirname(dest))
107 if (destParent === srcParent || destParent === path.parse(destParent).root) return cb()
108 if (nodeSupportsBigInt()) {
109 fs.stat(destParent, { bigint: true }, (err, destStat) => {
110 if (err) {
111 if (err.code === 'ENOENT') return cb()
112 return cb(err)
113 }
114 if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) {
115 return cb(new Error(errMsg(src, dest, funcName)))
116 }
117 return checkParentPaths(src, srcStat, destParent, funcName, cb)
118 })
119 } else {
120 fs.stat(destParent, (err, destStat) => {
121 if (err) {
122 if (err.code === 'ENOENT') return cb()
123 return cb(err)
124 }
125 if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) {
126 return cb(new Error(errMsg(src, dest, funcName)))
127 }
128 return checkParentPaths(src, srcStat, destParent, funcName, cb)
129 })
130 }
131}
132
133function checkParentPathsSync (src, srcStat, dest, funcName) {
134 const srcParent = path.resolve(path.dirname(src))
135 const destParent = path.resolve(path.dirname(dest))
136 if (destParent === srcParent || destParent === path.parse(destParent).root) return
137 let destStat
138 try {
139 if (nodeSupportsBigInt()) {
140 destStat = fs.statSync(destParent, { bigint: true })
141 } else {
142 destStat = fs.statSync(destParent)
143 }
144 } catch (err) {
145 if (err.code === 'ENOENT') return
146 throw err
147 }
148 if (destStat.ino && destStat.dev && destStat.ino === srcStat.ino && destStat.dev === srcStat.dev) {
149 throw new Error(errMsg(src, dest, funcName))
150 }
151 return checkParentPathsSync(src, srcStat, destParent, funcName)
152}
153
154// return true if dest is a subdir of src, otherwise false.
155// It only checks the path strings.
156function isSrcSubdir (src, dest) {
157 const srcArr = path.resolve(src).split(path.sep).filter(i => i)
158 const destArr = path.resolve(dest).split(path.sep).filter(i => i)
159 return srcArr.reduce((acc, cur, i) => acc && destArr[i] === cur, true)
160}
161
162function errMsg (src, dest, funcName) {
163 return `Cannot ${funcName} '${src}' to a subdirectory of itself, '${dest}'.`
164}
165
166module.exports = {
167 checkPaths,
168 checkPathsSync,
169 checkParentPaths,
170 checkParentPathsSync,
171 isSrcSubdir
172}
Note: See TracBrowser for help on using the repository browser.