diff --git a/fs/namei.c b/fs/namei.c index fa85129efb3555d49543a392a62584b009fe58fd..5383ad943b5bc8dc5ec17614155d584bc5f862ed 100644 --- a/fs/namei.c +++ b/fs/namei.c @@ -12,6 +12,12 @@ #define MAY_WRITE 2 #define MAY_READ 4 +#define ACC_MODE(x) ("\004\002\006\377"[(x)&O_ACCMODE]) + +static struct m_inode * _namei(const char * filename, struct m_inode * base, + int follow_links); + + static int permission(struct m_inode * inode,int mask) { int mode = inode->i_mode; if (inode->i_dev && !inode->i_nlinks) @@ -147,6 +153,39 @@ static struct buffer_head * add_entry(struct m_inode * dir, } } +static struct m_inode * follow_link(struct m_inode * dir, struct m_inode * inode) { + unsigned short fs; + struct buffer_head * bh; + + if (!dir) { + dir = current->root; + dir->i_count++; + } + if (!inode) { + iput(dir); + return NULL; + } + if (!S_ISLNK(inode->i_mode)) { + iput(dir); + return inode; + } + + __asm__("mov %%fs,%0":"=r" (fs)); + if (fs != 0x17 || !inode->i_zone[0] || + !(bh = bread(inode->i_dev, inode->i_zone[0]))) { + iput(dir); + iput(inode); + return NULL; + } + + iput(inode); + __asm__("mov %0,%%fs"::"r" ((unsigned short) 0x10)); + inode = _namei(bh->b_data,dir,0); + __asm__("mov %0,%%fs"::"r" (fs)); + brelse(bh); + return inode; +} + static struct m_inode * get_dir(const char * pathname, struct m_inode * inode) { char c; const char * thisname; @@ -230,17 +269,70 @@ int open_namei(const char * pathname, int flag, int mode, if (!(dir = dir_namei(pathname,&namelen,&basename,NULL))) return -ENOENT; + if (!namelen) { + if (!(flag & (O_ACCMODE|O_CREAT|O_TRUNC))) { + *res_inode=dir; + return 0; + } + iput(dir); + return -EISDIR; + } + bh = find_entry(&dir,basename,namelen,&de); if (!bh) { - return -EINVAL; + if (!(flag & O_CREAT)) { + iput(dir); + return -ENOENT; + } + if (!permission(dir,MAY_WRITE)) { + iput(dir); + return -EACCES; + } + inode = new_inode(dir->i_dev); + if (!inode) { + iput(dir); + return -ENOSPC; + } + inode->i_uid = current->euid; + inode->i_mode = mode; + inode->i_dirt = 1; + bh = add_entry(dir,basename,namelen,&de); + if (!bh) { + inode->i_nlinks--; + iput(inode); + iput(dir); + return -ENOSPC; + } + de->inode = inode->i_num; + bh->b_dirt = 1; + brelse(bh); + iput(dir); + *res_inode = inode; + return 0; } inr = de->inode; dev = dir->i_dev; brelse(bh); + if (flag & O_EXCL) { + iput(dir); + return -EEXIST; + } + + if (!(inode = follow_link(dir,iget(dev,inr)))) + return -EACCES; + + if ((S_ISDIR(inode->i_mode) && (flag & O_ACCMODE)) || + !permission(inode,ACC_MODE(flag))) { + iput(inode); + return -EPERM; + } + + inode->i_atime = CURRENT_TIME; + if (flag & O_TRUNC) + truncate(inode); - inode = iget(dev,inr); *res_inode = inode; return 0; } diff --git a/fs/open.c b/fs/open.c index d6c1970d0ddb7083c2edbbb7624e5ed4b3044c1a..041b846d098a1d81ef2f33e765b7fb249e011b48 100644 --- a/fs/open.c +++ b/fs/open.c @@ -108,10 +108,6 @@ int sys_open(const char * filename,int flag,int mode) { return i; } - if (S_ISCHR(inode->i_mode)) { - printk("open char dev %s\n", filename); - } - f->f_mode = inode->i_mode; f->f_flags = flag; f->f_count = 1; @@ -121,6 +117,10 @@ int sys_open(const char * filename,int flag,int mode) { return fd; } +int sys_creat(const char * pathname, int mode) { + return sys_open(pathname, O_CREAT | O_TRUNC, mode); +} + int sys_close(unsigned int fd) { struct file * filp; if (fd >= NR_OPEN) diff --git a/include/linux/sys.h b/include/linux/sys.h index 2f292bfdfe22496118cf0c0c791109e857a7861f..e87ea4ba1fad3f613e435de847b6bd0d20b3f084 100644 --- a/include/linux/sys.h +++ b/include/linux/sys.h @@ -6,7 +6,7 @@ extern int sys_write(); extern int sys_open(); extern int sys_close(); extern int sys_waitpid(); -//extern int sys_creat(); +extern int sys_creat(); //extern int sys_link(); //extern int sys_unlink(); extern int sys_execve(); @@ -95,7 +95,7 @@ fn_ptr sys_call_table[] = { sys_open, sys_close, sys_waitpid, - 0, //sys_creat, + sys_creat, 0, //sys_link, 0, //sys_unlink, diff --git a/include/sys/types.h b/include/sys/types.h index b75fb69c89ccd35e68b1340dbe04c246218a9a20..15fd2c50fa5774cd7677906f0dbeeeb250c970af 100644 --- a/include/sys/types.h +++ b/include/sys/types.h @@ -30,8 +30,19 @@ typedef unsigned short gid_t; typedef unsigned short dev_t; typedef unsigned short umode_t; typedef unsigned char nlink_t; +typedef int daddr_t; typedef unsigned char cc_t; typedef unsigned int speed_t; typedef unsigned long tcflag_t; +typedef struct { int quot,rem; } div_t; +typedef struct { long quot,rem; } ldiv_t; + +struct ustat { + daddr_t f_tfree; + ino_t f_tinode; + char f_fname[6]; + char f_fpack[6]; +}; + #endif