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;
|
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];
|
char path[pathCapacity];
|
||||||
if (argument[0] == 0)
|
if (argument[0] == 0)
|
||||||
@@ -1158,10 +1323,13 @@ static void changeDir(const char* argument)
|
|||||||
else
|
else
|
||||||
buildPath(argument, path);
|
buildPath(argument, path);
|
||||||
|
|
||||||
VfsNode* node = vfsLookup(path);
|
/* vfsChdir (vfs.h) also understands "/mnt" directories -- unlike the
|
||||||
if (!node || !vfsIsDir(node)) {
|
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);
|
kprintf("cd: no such directory: %s\n", path);
|
||||||
return;
|
return 1;
|
||||||
}
|
}
|
||||||
vfsPath(node, cwd, sizeof(cwd));
|
vfsPath(node, cwd, sizeof(cwd));
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in new issue
Block a user