@samitouri / QOSami-HFS / commits / 7087c2ea

better error code for del_vfs

Massimo Melina committed Jan 24, 2026 at 12:01 UTC 7087c2ea8667ea799a31e55e01eb87c40c8d4a71
3 files changed +13 -12
src/api.vfs.ts
+9 -10
@@ -151,21 +151,20 @@ export default {
151 errors: await Promise.all(uris.map(async uri => {
152 if (typeof uri !== 'string')
153 return HTTP_BAD_REQUEST
154 - if (uri === '/')
155 - return HTTP_NOT_ACCEPTABLE
154 const node = await urlToNodeOriginal(uri)
155 if (!node)
156 return HTTP_NOT_FOUND
159 - const parent = dirname(uri)
160 - const parentNode = await urlToNodeOriginal(parent)
161 - if (!parentNode) // shouldn't happen
157 + if (isRoot(node))
158 + return HTTP_NOT_ACCEPTABLE
159 + const parentNode = await urlToNodeOriginal(dirname(uri))
160 + const c = parentNode?.children // since node is not root, parentNode must exist and have children
161 + if (!c) // inconsistent state
162 return HTTP_SERVER_ERROR
163 - const { children } = parentNode
164 - if (!children) // shouldn't happen
163 + const idx = c.indexOf(node)
164 + if (idx < 0) // inconsistent state
165 return HTTP_SERVER_ERROR
166 - const idx = children.indexOf(node)
167 - children.splice(idx, 1)
168 - if (!children.length)
166 + c.splice(idx, 1)
167 + if (!c.length)
168 parentNode.children = undefined
169 return 0 // error code 0 is OK
170 })).finally(saveVfs)
src/vfs.ts
+1 -1
@@ -42,7 +42,7 @@ export interface VfsNodeStored extends VfsPerms {
42 export interface VfsNode extends VfsNodeStored { // include fields that are only filled at run-time
43 isTemp?: true // this node doesn't belong to the tree and was created by necessity
44 original?: VfsNode // if this is a temp node but reflecting an existing node
45 - parent?: VfsNode // available when original is available
45 + parent?: VfsNode // available when original is available (therefore, only for isTemp)
46 isFolder?: boolean // use nodeIsFolder() instead of relying on this field
47 stats?: Promise<Stats>
48 }
tests/test.ts
+3 -1
@@ -456,9 +456,11 @@ describe('admin', () => {
456 await reqList(name, { inList: ['plugins/'] })()
457 }
458 finally {
459 - await reqApi('del_vfs', { uris: ['/'+name] }, 200, { auth })() // remove
459 + await reqApi('del_vfs', { uris: ['/'+name] }, data => data?.errors?.[0] === 0, { auth })() // remove
460 }
461 })
462 + test('del_vfs.bad uris', reqApi('del_vfs', { uris: ['', '/', '//'] }, (res: any) =>
463 + throwIf(res?.errors.some((x: any) => x === 406) ? '' : res?.errors || 'missing'), { auth }))
464 test('plugins.missing', reqApi('set_plugin', { id: 'missing-plugin', enabled: true }, { status: 400, re: /miss/ }, { auth }))
465 test('plugins.update.missing', reqApi('update_plugin', { id: 'missing-plugin' }, 404, { auth }))
466 test('monitor.connections safe path decode', async () => {