diff --git a/composables/umask.ts b/composables/umask.ts new file mode 100644 index 0000000..d9d2f73 --- /dev/null +++ b/composables/umask.ts @@ -0,0 +1,18 @@ +import { createGlobalState } from '@vueuse/core'; + +export const useUmaskStore = createGlobalState(() => { + const umask = ref(window?.localStorage?.getItem('umask') || '000000000010'); + function changeUmask(newUmask: string & { length: 12 } & { [index: number]: '0' | '1' }) { + umask.value = newUmask; + localStorage.setItem('umask', newUmask); + } + function clearUmask() { + umask.value = '000000000010'; + localStorage.setItem('umask', umask.value); + } + return { + umask, + changeUmask, + clearUmask, + }; +}); diff --git a/composables/user.ts b/composables/user.ts index 15eb397..c8de507 100644 --- a/composables/user.ts +++ b/composables/user.ts @@ -1,6 +1,7 @@ import { createGlobalState } from '@vueuse/core'; export const useUserStore = createGlobalState(() => { + const { clearUmask } = useUmaskStore(); const username = ref(window?.localStorage?.getItem('username') || 'guest'); onMounted(async () => { if (username.value === 'guest') { @@ -19,6 +20,7 @@ export const useUserStore = createGlobalState(() => { function switchUser(name: string) { username.value = name; localStorage.setItem('username', name); + clearUmask(); } watch(username, async () => { const meta = (await useFetch('/api/users', { diff --git a/lib/command/impls/help.ts b/lib/command/impls/help.ts index e3c7e81..a25a8cc 100644 --- a/lib/command/impls/help.ts +++ b/lib/command/impls/help.ts @@ -45,6 +45,12 @@ const commandDescriptions: Record = { { args: ['-u ', '-p '] }, ], }, + [Command.UMASK]: { + description: 'Set file mode creation mask', + usages: [ + { args: ['()?'] }, + ], + }, }; function getDescription(commandName: string): string[] { diff --git a/lib/command/impls/mkdir.ts b/lib/command/impls/mkdir.ts new file mode 100644 index 0000000..50469a5 --- /dev/null +++ b/lib/command/impls/mkdir.ts @@ -0,0 +1,12 @@ +import { formatArg } from '../utils'; +import type { CommandFunc } from './types'; + +export const mkdir: CommandFunc = async function(...args) { + // discard `mkdir` + args.shift(); + // discard first space + args.shift(); + + return [ + ]; +}; diff --git a/lib/command/impls/touch.ts b/lib/command/impls/touch.ts new file mode 100644 index 0000000..994625c --- /dev/null +++ b/lib/command/impls/touch.ts @@ -0,0 +1,12 @@ +import { formatArg } from '../utils'; +import type { CommandFunc } from './types'; + +export const touch: CommandFunc = async function(...args) { + // discard `touch` + args.shift(); + // discard first space + args.shift(); + + return [ + ]; +}; diff --git a/lib/command/impls/types.ts b/lib/command/impls/types.ts index 096b1af..7a710db 100644 --- a/lib/command/impls/types.ts +++ b/lib/command/impls/types.ts @@ -7,4 +7,7 @@ export enum Command { SU = 'su', LS = 'ls', USERADD = 'useradd', + TOUCH = 'touch', + MKDIR = 'mkdir', + UMASK = 'umask', } diff --git a/lib/command/impls/umask.ts b/lib/command/impls/umask.ts new file mode 100644 index 0000000..28b4242 --- /dev/null +++ b/lib/command/impls/umask.ts @@ -0,0 +1,58 @@ +import { formatArg } from '../utils'; +import type { CommandFunc } from './types'; + +export const umask: CommandFunc = async function(...args) { + // discard `umask` + args.shift(); + // discard first space + args.shift(); + + if (args.length === 0) { + const { umask } = useUmaskStore(); + return [umaskToOct(umask.value)]; + } + + if (args.length > 1) { + return [ + 'Invalid use of umask. Run \'help umask\'', + ]; + } + + const umask = formatArg(args[0]); + if (umask.length !== 3 || !isOctDigit(umask[0]) || !isOctDigit(umask[1]) || !isOctDigit(umask[2])) { + return ['Invalid umask']; + } + const { changeUmask } = useUmaskStore(); + changeUmask(umaskFromOct(umask as any)); + return [ + 'Change umask successfully', + ]; +}; + +function isOctDigit(c: string): boolean { + const n = Number.parseInt(c); + return c.length === 1 && 0 <= n && n <= 7; +} + +function umaskToOct(umask: string): string { + const ownerRead = Number.parseInt(umask[3]); + const ownerWrite = Number.parseInt(umask[4]); + const ownerExecute = Number.parseInt(umask[5]); + const ownerOct = ownerRead * 4 + ownerWrite * 2 + ownerExecute; + const groupRead = Number.parseInt(umask[6]); + const groupWrite = Number.parseInt(umask[7]); + const groupExecute = Number.parseInt(umask[8]); + const groupOct = groupRead * 4 + groupWrite * 2 + groupExecute; + const otherRead = Number.parseInt(umask[9]); + const otherWrite = Number.parseInt(umask[10]); + const otherExecute = Number.parseInt(umask[11]); + const otherOct = otherRead * 4 + otherWrite * 2 + otherExecute; + return `${ownerOct}${groupOct}${otherOct}`; +} + +function umaskFromOct(octs: string): string { + const ownerOct = octs[0]; + const groupOct = octs[1]; + const otherOct = octs[2]; + return `000${ownerOct.toString(2).padStart(3, '0')}${groupOct.toString(2).padStart(3, '0')}${otherOct.toString(2).padStart(3, '0')}`; +} diff --git a/lib/command/index.ts b/lib/command/index.ts index 3c19ea9..50c5fcb 100644 --- a/lib/command/index.ts +++ b/lib/command/index.ts @@ -8,6 +8,9 @@ import { cd } from './impls/cd'; import { su } from './impls/su'; import { ls } from './impls/ls'; import { useradd } from './impls/useradd'; +import { touch } from './impls/touch'; +import { mkdir } from './impls/mkdir'; +import { umask } from './impls/umask'; export async function execute(command: string): Promise { const args = parse(command); @@ -37,6 +40,15 @@ export async function execute(command: string): Promise { case Command.USERADD: res = await useradd(...args as any); break; + case Command.TOUCH: + res = await touch(...args as any); + break; + case Command.MKDIR: + res = await mkdir(...args as any); + break; + case Command.UMASK: + res = await umask(...args as any); + break; default: res = echo('echo', ' ', `Unknown command:\\u001b[31m ${args[0]}`); break; diff --git a/services/files.ts b/services/files.ts index 0716744..25fb861 100644 --- a/services/files.ts +++ b/services/files.ts @@ -69,6 +69,8 @@ export const fileService = { }, async createFile(filename: string): Promise> { }, + async createFolder(filename: string): Promise> { + }, async changeDirectory(filename: string): Promise> { try { const { cwd, switchCwd } = useCwdStore();