summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjdike <jdike>2003-02-02 18:11:15 +0000
committerjdike <jdike>2003-02-02 18:11:15 +0000
commite4dea0b1281a1cfe452d54245ac542dc7f6db4cd (patch)
tree6f7e2310e83da79effc2fe8345d6c9ffb68d8274
parent9ccde2faf5d6d5370519e191b3d08d79c7e7c084 (diff)
downloaduml-history-e4dea0b1281a1cfe452d54245ac542dc7f6db4cd.tar.gz
Symlinks that point to a directory can now be mounted.
Tidied the code a bit.
-rw-r--r--arch/um/fs/hostfs/hostfs_kern.c97
-rw-r--r--arch/um/fs/hostfs/hostfs_user.c19
2 files changed, 100 insertions, 16 deletions
diff --git a/arch/um/fs/hostfs/hostfs_kern.c b/arch/um/fs/hostfs/hostfs_kern.c
index b678922..2b63356 100644
--- a/arch/um/fs/hostfs/hostfs_kern.c
+++ b/arch/um/fs/hostfs/hostfs_kern.c
@@ -104,23 +104,87 @@ static int read_name(struct inode *ino, char *name)
return(0);
}
+static char *follow_link(char *link)
+{
+ int len, n;
+ char *name, *resolved, *end;
+
+ len = 64;
+ while(1){
+ n = -ENOMEM;
+ name = kmalloc(len, GFP_KERNEL);
+ if(name == NULL)
+ goto out;
+
+ n = do_readlink(link, name, len);
+ if(n < len)
+ break;
+ len *= 2;
+ kfree(name);
+ }
+ if(n < 0)
+ goto out_free;
+
+ if(*name == '/')
+ return(name);
+
+ end = strrchr(link, '/');
+ if(end == NULL)
+ return(name);
+
+ *(end + 1) = '\0';
+ len = strlen(link) + strlen(name) + 1;
+
+ resolved = kmalloc(len, GFP_KERNEL);
+ if(resolved == NULL){
+ n = -ENOMEM;
+ goto out_free;
+ }
+
+ sprintf(resolved, "%s%s", link, name);
+ kfree(name);
+ kfree(link);
+ return(resolved);
+
+ out_free:
+ kfree(name);
+ out:
+ return(ERR_PTR(n));
+}
+
static int read_inode(struct inode *ino)
{
char *name;
int err;
+ err = -ENOMEM;
name = inode_name(ino, 0);
- if(name == NULL) return(-ENOMEM);
+ if(name == NULL)
+ goto out;
+
+ if(file_type(name, NULL) == OS_TYPE_SYMLINK){
+ name = follow_link(name);
+ if(IS_ERR(name)){
+ err = PTR_ERR(name);
+ goto out;
+ }
+ }
+
err = read_name(ino, name);
kfree(name);
+ out:
return(err);
}
void hostfs_delete_inode(struct inode *ino)
{
- if(ino->u.hostfs_i.host_filename) kfree(ino->u.hostfs_i.host_filename);
+ if(ino->u.hostfs_i.host_filename)
+ kfree(ino->u.hostfs_i.host_filename);
ino->u.hostfs_i.host_filename = NULL;
- if(ino->u.hostfs_i.fd != -1) close_file(&ino->u.hostfs_i.fd);
+
+ if(ino->u.hostfs_i.fd != -1)
+ close_file(&ino->u.hostfs_i.fd);
+
ino->u.hostfs_i.mode = 0;
clear_inode(ino);
}
@@ -187,22 +251,34 @@ int hostfs_file_open(struct inode *ino, struct file *file)
int mode = 0, r = 0, w = 0, fd;
mode = file->f_mode & (FMODE_READ | FMODE_WRITE);
- if((mode & ino->u.hostfs_i.mode) == mode) return(0);
+ if((mode & ino->u.hostfs_i.mode) == mode)
+ return(0);
+ /* The file may already have been opened, but with the wrong access,
+ * so this resets things and reopens the file with the new access.
+ */
if(ino->u.hostfs_i.fd != -1){
close_file(&ino->u.hostfs_i.fd);
ino->u.hostfs_i.fd = -1;
}
+
ino->u.hostfs_i.mode |= mode;
- if(ino->u.hostfs_i.mode & FMODE_READ) r = 1;
- if(ino->u.hostfs_i.mode & FMODE_WRITE) w = 1;
- if(w) r = 1;
+ if(ino->u.hostfs_i.mode & FMODE_READ)
+ r = 1;
+ if(ino->u.hostfs_i.mode & FMODE_WRITE)
+ w = 1;
+ if(w)
+ r = 1;
+
name = dentry_name(file->f_dentry, 0);
- if(name == NULL) return(-ENOMEM);
+ if(name == NULL)
+ return(-ENOMEM);
+
fd = open_file(name, r, w);
kfree(name);
if(fd < 0) return(fd);
file_hostfs_i(file)->fd = fd;
+
return(0);
}
@@ -712,10 +788,13 @@ int hostfs_link_readpage(struct file *file, struct page *page)
if(name == NULL) return(-ENOMEM);
err = do_readlink(name, buffer, PAGE_CACHE_SIZE);
kfree(name);
- if(err == 0){
+ if(err == PAGE_CACHE_SIZE)
+ err = -E2BIG;
+ else if(err > 0){
flush_dcache_page(page);
SetPageUptodate(page);
if (PageError(page)) ClearPageError(page);
+ err = 0;
}
kunmap(page);
UnlockPage(page);
diff --git a/arch/um/fs/hostfs/hostfs_user.c b/arch/um/fs/hostfs/hostfs_user.c
index a81f3e9..97e40ac 100644
--- a/arch/um/fs/hostfs/hostfs_user.c
+++ b/arch/um/fs/hostfs/hostfs_user.c
@@ -50,8 +50,11 @@ int file_type(const char *path, int *rdev)
{
struct stat64 buf;
- if(lstat64(path, &buf) < 0) return(-errno);
- *rdev = buf.st_rdev;
+ if(lstat64(path, &buf) < 0)
+ return(-errno);
+ if(rdev != NULL)
+ *rdev = buf.st_rdev;
+
if(S_ISDIR(buf.st_mode)) return(OS_TYPE_DIR);
else if(S_ISLNK(buf.st_mode)) return(OS_TYPE_SYMLINK);
else if(S_ISCHR(buf.st_mode)) return(OS_TYPE_CHARDEV);
@@ -277,12 +280,14 @@ int link_file(const char *to, const char *from)
int do_readlink(char *file, char *buf, int size)
{
- int err;
+ int n;
- err = readlink(file, buf, size);
- if(err < 0) return(-errno);
- if(err < size) buf[err] = '\0';
- return(0);
+ n = readlink(file, buf, size);
+ if(n < 0)
+ return(-errno);
+ if(n < size)
+ buf[n] = '\0';
+ return(n);
}
int rename_file(char *from, char *to)