feat: extend shell with removeFile and removeDir
This commit is contained in:
1 parent
9e1f907da5
commit
230e271ea1
1 file changed
+172
-4
+172
-4
@@ -1150,7 +1150,172 @@ static int makeDir(const char* argument)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void changeDir(const char* argument)
|
||||
/* Real `rm`: refuses a directory outright (real rm without -r never
|
||||
descends), matching vfsUnlink's own EISDIR-shaped refusal (vfs.c) --
|
||||
the vfsStat check here exists only to give a friendlier message than
|
||||
vfsUnlink's plain -1 would on its own, the actual enforcement is
|
||||
vfsUnlink's, not this. */
|
||||
static int removeFile(const char* argument)
|
||||
{
|
||||
if (argument[0] == 0) {
|
||||
kprintf("rm: missing path\n");
|
||||
return 1;
|
||||
}
|
||||
char path[pathCapacity];
|
||||
buildPath(argument, path);
|
||||
|
||||
FbStat stat;
|
||||
if (vfsStat(path, &stat) != 0) {
|
||||
kprintf("rm: no such file: %s\n", path);
|
||||
return 1;
|
||||
}
|
||||
if (stat.type == fsTypeDir) {
|
||||
kprintf("rm: %s: is a directory\n", path);
|
||||
return 1;
|
||||
}
|
||||
if (vfsUnlink(path) != 0) {
|
||||
kprintf("rm: cannot remove %s\n", path);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Real `rmdir`: only ever removes an EMPTY directory, same split from `rm`
|
||||
above that real rmdir(2)/unlink(2) have. */
|
||||
static int removeDir(const char* argument)
|
||||
{
|
||||
if (argument[0] == 0) {
|
||||
kprintf("rmdir: missing path\n");
|
||||
return 1;
|
||||
}
|
||||
char path[pathCapacity];
|
||||
buildPath(argument, path);
|
||||
|
||||
FbStat stat;
|
||||
if (vfsStat(path, &stat) != 0) {
|
||||
kprintf("rmdir: no such directory: %s\n", path);
|
||||
return 1;
|
||||
}
|
||||
if (stat.type != fsTypeDir) {
|
||||
kprintf("rmdir: %s: not a directory\n", path);
|
||||
return 1;
|
||||
}
|
||||
if (vfsRmdir(path) != 0) {
|
||||
kprintf("rmdir: %s: not empty\n", path);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Real `chmod MODE PATH`: MODE is parsed as octal (strtoul base 8, klib.h),
|
||||
matching real chmod(1)'s numeric-mode convention -- "755" already means
|
||||
0755, no leading 0 required. Both the owner AND other triads are
|
||||
meaningful now that a real uid model exists (fs.h's fsModeOwner and
|
||||
fsModeOther bits, vfs.c's vfsPermitted) -- refused outright unless the
|
||||
caller owns the target or is uid 0 (vfsChmod's own vfsOwnerOrRoot check).
|
||||
Symbolic modes (u+x, a=r, ...) are not supported, the same "numeric only"
|
||||
scope every other new builtin in this shell has picked over a fuller
|
||||
grammar it does not need. */
|
||||
static int doChmod(const char* argument)
|
||||
{
|
||||
char modeText[16];
|
||||
uint64 i = 0;
|
||||
while (argument[i] && argument[i] != ' ' && i < sizeof(modeText) - 1) {
|
||||
modeText[i] = argument[i];
|
||||
i++;
|
||||
}
|
||||
modeText[i] = 0;
|
||||
|
||||
const char* rest = argument + i;
|
||||
while (*rest == ' ')
|
||||
rest++;
|
||||
|
||||
if (modeText[0] == 0 || rest[0] == 0) {
|
||||
kprintf("chmod: usage: chmod MODE PATH\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32 mode = (uint32)strtoul(modeText, nullptr, 8);
|
||||
char path[pathCapacity];
|
||||
buildPath(rest, path);
|
||||
if (vfsChmod(path, mode) != 0) {
|
||||
kprintf("chmod: cannot chmod %s\n", path);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Real `chown UID PATH`: UID is parsed as a plain decimal number (strtoul
|
||||
base 10, klib.h), unlike chmod's octal MODE -- a uid is never a bitmask,
|
||||
so there is no "leading digit means octal" convention to match. Refused
|
||||
outright unless the caller is uid 0 (vfsChown's own root-only check) --
|
||||
even the file's own owner may not give it away, matching real Unix's
|
||||
_POSIX_CHOWN_RESTRICTED default. */
|
||||
static int doChown(const char* argument)
|
||||
{
|
||||
char uidText[16];
|
||||
uint64 i = 0;
|
||||
while (argument[i] && argument[i] != ' ' && i < sizeof(uidText) - 1) {
|
||||
uidText[i] = argument[i];
|
||||
i++;
|
||||
}
|
||||
uidText[i] = 0;
|
||||
|
||||
const char* rest = argument + i;
|
||||
while (*rest == ' ')
|
||||
rest++;
|
||||
|
||||
if (uidText[0] == 0 || rest[0] == 0) {
|
||||
kprintf("chown: usage: chown UID PATH\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32 uid = (uint32)strtoul(uidText, nullptr, 10);
|
||||
char path[pathCapacity];
|
||||
buildPath(rest, path);
|
||||
if (vfsChown(path, uid) != 0) {
|
||||
kprintf("chown: cannot chown %s\n", path);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Real `chgrp GID PATH`: decimal like chown, not octal like chmod -- a gid
|
||||
is never a bitmask either. Unlike chown (root-only, full stop), the
|
||||
file's own owner may also call this, but only to set the group to THIS
|
||||
shell's own current gid (vfsChgrp's own owner-may-only-name-their-own-gid
|
||||
rule, see its doc comment) -- root may still set any gid. */
|
||||
static int doChgrp(const char* argument)
|
||||
{
|
||||
char gidText[16];
|
||||
uint64 i = 0;
|
||||
while (argument[i] && argument[i] != ' ' && i < sizeof(gidText) - 1) {
|
||||
gidText[i] = argument[i];
|
||||
i++;
|
||||
}
|
||||
gidText[i] = 0;
|
||||
|
||||
const char* rest = argument + i;
|
||||
while (*rest == ' ')
|
||||
rest++;
|
||||
|
||||
if (gidText[0] == 0 || rest[0] == 0) {
|
||||
kprintf("chgrp: usage: chgrp GID PATH\n");
|
||||
return 1;
|
||||
}
|
||||
|
||||
uint32 gid = (uint32)strtoul(gidText, nullptr, 10);
|
||||
char path[pathCapacity];
|
||||
buildPath(rest, path);
|
||||
if (vfsChgrp(path, gid) != 0) {
|
||||
kprintf("chgrp: cannot chgrp %s\n", path);
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Same "0 success, 1 failure" shape as above. */
|
||||
static int changeDir(const char* argument)
|
||||
{
|
||||
char path[pathCapacity];
|
||||
if (argument[0] == 0)
|
||||
@@ -1158,10 +1323,13 @@ static void changeDir(const char* argument)
|
||||
else
|
||||
buildPath(argument, path);
|
||||
|
||||
VfsNode* node = vfsLookup(path);
|
||||
if (!node || !vfsIsDir(node)) {
|
||||
/* vfsChdir (vfs.h) also understands "/mnt" directories -- unlike the
|
||||
vfsLookup+vfsIsDir check this used to do, which only ever walked the
|
||||
VfsNode tree (ustar/tmpfs) and so could never actually cd into the
|
||||
persistent on-disk filesystem at all. */
|
||||
if (vfsChdir(path) != 0) {
|
||||
kprintf("cd: no such directory: %s\n", path);
|
||||
return;
|
||||
return 1;
|
||||
}
|
||||
vfsPath(node, cwd, sizeof(cwd));
|
||||
}
|
||||
|
||||
Reference in new issue
Block a user