admin/fs: adding an item with existing name, append number in name
Massimo Melina committed
Mar 29, 2023 at 23:46 UTC
7e42b4f88b254238b496202539876e77d29848a4
2 files changed
+17
-13
src/api.vfs.ts
+9
-7
@@ -4,7 +4,7 @@ import { defaultPerms, getNodeName, isSameFilenameAs, nodeIsDirectory, saveVfs,
4
import _ from 'lodash'
5
import { stat } from 'fs/promises'
6
import { ApiError, ApiHandlers } from './apiMiddleware'
7
-import { dirname, join, resolve } from 'path'
7
+import { dirname, extname, join, resolve } from 'path'
8
import { dirStream, isWindowsDrive, matches, newObj } from './misc'
9
import {
10
IS_WINDOWS,
@@ -106,15 +106,17 @@ const apis: ApiHandlers = {
106
return new ApiError(HTTP_NOT_ACCEPTABLE, 'invalid parent')
107
if (isWindowsDrive(source))
108
source += '\\' // slash must be included, otherwise it will refer to the cwd of that drive
109
- else if (source === '/')
110
- name ||= 'root'
109
+ let tryName = getNodeName({ name, source })
110
+ const ext = extname(tryName)
111
+ const noExt = ext ? tryName.slice(0, -ext.length) : tryName
112
+ let idx = 2
113
+ while (n.children?.find(isSameFilenameAs(tryName)))
114
+ tryName = `${noExt} ${idx++}${ext}`
115
+ name = tryName
116
n.children ||= []
112
- const sameName = name && isSameFilenameAs(name)
113
- if (n.children.find(x => source && source === x.source || sameName?.(x)))
114
- return new ApiError(HTTP_CONFLICT, 'already present')
117
n.children.unshift({ source, name })
118
await saveVfs()
117
- return {}
119
+ return { name }
120
},
121
122
async del_vfs({ uris }) {
src/vfs.ts
+8
-6
@@ -133,16 +133,18 @@ export function saveVfs() {
133
}
134
135
export function getNodeName(node: VfsNode) {
136
- const { name, source: s } = node
136
+ const { name, source } = node
137
if (name)
138
return name
139
- if (!s)
139
+ if (!source)
140
return '' // should happen only for root
141
- if (/^[a-zA-Z]:\\?$/.test(s))
142
- return s.slice(0, 2) // exclude trailing slash
143
- const base = basename(s)
141
+ if (source === '/')
142
+ return 'root'
143
+ if (/^[a-zA-Z]:\\?$/.test(source))
144
+ return source.slice(0, 2) // exclude trailing slash
145
+ const base = basename(source)
146
if (/^[./\\]*$/.test(base)) // if empty or special-chars-only
145
- return basename(resolve(s)) // resolve to try to get more
147
+ return basename(resolve(source)) // resolve to try to get more
148
return base
149
}
150