vfs: names up to 255 bytes and paths up to 4096, like Linux
Every path component was copied into a DIRSIZ buffer and every path into a MAXPATH one, so names were cut at 29 bytes and paths at 127 without an error. Two names sharing their first 29 bytes opened the same file, on SchFS and FAT alike, though both hold 255. VFS_NAME_MAX (255) and VFS_PATH_MAX (4096) are the limits now, and anything longer is ENAMETOOLONG. namex_from() takes its path buffers from kalloc(), a page each, rather than putting two of them on an 8 KB kernel stack. The v1 format still stores DIRSIZ bytes, and refuses a longer name instead of matching on its first 30. Checked: 255-byte names on SchFS and FAT (fsck.fat clean, and the FAT name answers to its uppercase form), 256 refused, a 200-byte path and a link to it, and no pages lost over 700 lookups through links. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01S1giNvrHTrPMPw7V6x1kQ4
This commit is contained in:
parent
b213ab5778
commit
67db42b460
7 changed files with 121 additions and 38 deletions
|
|
@ -186,14 +186,31 @@ at_nameiparent(int dirfd, char *path, char *name)
|
|||
return nameiparentfrom(start, path, name);
|
||||
}
|
||||
|
||||
// 1 if some component of `path` is longer than NAME_MAX, which is why a
|
||||
// lookup through nameiparent() failed when it did. It reports no reason.
|
||||
static int
|
||||
path_toolong(const char *path)
|
||||
{
|
||||
int n = 0;
|
||||
if (strnlen(path, VFS_PATH_MAX) >= VFS_PATH_MAX) return 1;
|
||||
for (; *path; path++) {
|
||||
n = (*path == '/') ? 0 : n + 1;
|
||||
if (n > VFS_NAME_MAX) return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct inode*
|
||||
createat_x(int dirfd, char *path, short type, short major, short minor,
|
||||
int *err)
|
||||
{
|
||||
struct inode *ip, *dp;
|
||||
char name[DIRSIZ];
|
||||
char name[VFS_NAME_MAX + 1];
|
||||
uint off;
|
||||
if (!(dp = at_nameiparent(dirfd, path, name))) return 0;
|
||||
if (!(dp = at_nameiparent(dirfd, path, name))) {
|
||||
if (err && path && path_toolong(path)) *err = ENAMETOOLONG;
|
||||
return 0;
|
||||
}
|
||||
ilock(dp);
|
||||
// `err` lets the caller report why. Returning 0 alone made a refused
|
||||
// write say "No such file or directory", which is what a shell prints for
|
||||
|
|
@ -884,7 +901,7 @@ addr_t sys_mknod(void)
|
|||
// renameat() is corrected alongside rename() because musl's rename() calls it.
|
||||
addr_t sys_link(void)
|
||||
{
|
||||
char name[DIRSIZ], *new, *old;
|
||||
char name[VFS_NAME_MAX + 1], *new, *old;
|
||||
struct inode *dp, *ip;
|
||||
int err = EPERM;
|
||||
if (argstr(0, &old) < 0 || argstr(1, &new) < 0) return -EFAULT;
|
||||
|
|
@ -936,7 +953,7 @@ int
|
|||
unlink_path(char *path)
|
||||
{
|
||||
struct inode *ip, *dp;
|
||||
char name[DIRSIZ];
|
||||
char name[VFS_NAME_MAX + 1];
|
||||
uint off;
|
||||
int err = EPERM;
|
||||
|
||||
|
|
@ -1067,7 +1084,7 @@ addr_t sys_rename(void)
|
|||
{
|
||||
char *oldpath, *newpath;
|
||||
struct inode *ip, *dp_old, *dp_new, *ip_src, *ip_dst;
|
||||
char oldname[DIRSIZ], newname[DIRSIZ];
|
||||
char oldname[VFS_NAME_MAX + 1], newname[VFS_NAME_MAX + 1];
|
||||
uint off, dstoff;
|
||||
int err = EPERM;
|
||||
if (argstr(0, &oldpath) < 0 || argstr(1, &newpath) < 0) return -EFAULT;
|
||||
|
|
@ -1244,7 +1261,7 @@ sys_getdents64(void)
|
|||
addr_t sys_delete(void)
|
||||
{
|
||||
struct inode *ip, *dp, *ip2;
|
||||
char name[DIRSIZ], *path;
|
||||
char name[VFS_NAME_MAX + 1], *path;
|
||||
uint off;
|
||||
if (argstr(0, &path) < 0) return -1;
|
||||
begin_op();
|
||||
|
|
@ -1897,7 +1914,7 @@ addr_t sys_unlinkat(void)
|
|||
int dirfd, flags;
|
||||
char *path;
|
||||
struct inode *ip, *dp;
|
||||
char name[DIRSIZ];
|
||||
char name[VFS_NAME_MAX + 1];
|
||||
uint off;
|
||||
argint(0, &dirfd);
|
||||
if (argstr(1, &path) < 0) return -1;
|
||||
|
|
@ -1937,7 +1954,7 @@ addr_t sys_renameat(void)
|
|||
// Delegate to sys_rename internals — fake the args for rename.
|
||||
// Easiest: place path pointers in registers and call rename logic directly.
|
||||
struct inode *ip, *dp_old, *dp_new, *ip_src;
|
||||
char oldname[DIRSIZ], newname[DIRSIZ];
|
||||
char oldname[VFS_NAME_MAX + 1], newname[VFS_NAME_MAX + 1];
|
||||
uint off;
|
||||
struct dirent de;
|
||||
begin_op();
|
||||
|
|
@ -1981,7 +1998,7 @@ addr_t sys_linkat(void)
|
|||
int olddirfd, newdirfd;
|
||||
char *old, *new;
|
||||
struct inode *dp, *ip;
|
||||
char name[DIRSIZ];
|
||||
char name[VFS_NAME_MAX + 1];
|
||||
argint(0, &olddirfd); argstr(1, &old);
|
||||
argint(2, &newdirfd); argstr(3, &new);
|
||||
argint(4, &(int){0}); // flags
|
||||
|
|
|
|||
Loading…
Reference in a new issue