patch-2.1.4 linux/fs/namei.c
Next file: linux/fs/ncpfs/inode.c
Previous file: linux/fs/minix/inode.c
Back to the patch index
Back to the overall index
- Lines: 126
- Date:
Sun Oct 13 21:11:19 1996
- Orig file:
v2.1.3/linux/fs/namei.c
- Orig date:
Thu Oct 10 19:10:56 1996
diff -u --recursive --new-file v2.1.3/linux/fs/namei.c linux/fs/namei.c
@@ -8,8 +8,6 @@
* Some corrections by tytso.
*/
-#include <asm/segment.h>
-
#include <linux/errno.h>
#include <linux/sched.h>
#include <linux/kernel.h>
@@ -18,69 +16,73 @@
#include <linux/stat.h>
#include <linux/mm.h>
+#include <asm/segment.h>
+
#define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE])
/*
+ * How long a filename can we get from user space?
+ * -EFAULT if invalid area
+ * 0 if ok (ENAMETOOLONG before EFAULT)
+ * >0 EFAULT after xx bytes
+ */
+static inline int get_max_filename(unsigned long address)
+{
+ struct vm_area_struct * vma;
+
+ if (get_fs() == KERNEL_DS)
+ return 0;
+ vma = find_vma(current->mm, address);
+ if (!vma || vma->vm_start > address || !(vma->vm_flags & VM_READ))
+ return -EFAULT;
+ address = vma->vm_end - address;
+ if (address > PAGE_SIZE)
+ return 0;
+ if (vma->vm_next && vma->vm_next->vm_start == vma->vm_end &&
+ (vma->vm_next->vm_flags & VM_READ))
+ return 0;
+ return address;
+}
+
+/*
* In order to reduce some races, while at the same time doing additional
* checking and hopefully speeding things up, we copy filenames to the
* kernel data space before using them..
*
* POSIX.1 2.4: an empty pathname is invalid (ENOENT).
*/
-static inline int do_getname(const char * filename, char *buf)
+int getname(const char * filename, char **result)
{
- int error, maxlen = PAGE_SIZE;
- int c;
-
- error = -ENAMETOOLONG;
- if (get_fs() != KERNEL_DS) {
- error = -EFAULT;
- if (TASK_SIZE <= (unsigned long) filename)
- return error;
- maxlen = TASK_SIZE - (unsigned long) filename;
- if (maxlen >= PAGE_SIZE) {
- maxlen = PAGE_SIZE;
- error = -ENAMETOOLONG;
- }
+ int i, error;
+ unsigned long page;
+ char * tmp, c;
+
+ i = get_max_filename((unsigned long) filename);
+ if (i < 0)
+ return i;
+ error = -EFAULT;
+ if (!i) {
+ error = -ENAMETOOLONG;
+ i = PAGE_SIZE;
}
-
- c = (unsigned char) get_user(filename++);
+ get_user(c, filename++);
if (!c)
return -ENOENT;
-
- while (--maxlen) {
- *(buf++) = c;
- c = get_user(filename++);
+ if(!(page = __get_free_page(GFP_KERNEL)))
+ return -ENOMEM;
+ *result = tmp = (char *) page;
+ while (--i) {
+ *(tmp++) = c;
+ get_user(c, filename++);
if (!c) {
- *buf = '\0';
+ *tmp = '\0';
return 0;
}
}
+ free_page(page);
return error;
}
-int getname(const char *filename, char **result)
-{
- int error;
- unsigned long page = __get_free_page(GFP_KERNEL);
-
- error = -ENOMEM;
- if (page) {
- error = -EFAULT;
- if (!exception()) {
- int retval = do_getname(filename, (char *) page);
- end_exception();
- if (!retval) {
- *result = (char *) page;
- return 0;
- }
- error = retval;
- }
- free_page(page);
- }
- return error;
-}
-
void putname(char * name)
{
free_page((unsigned long) name);
FUNET's LINUX-ADM group, [email protected]
TCL-scripts by Sam Shen, [email protected]