diff options
author | jdike <jdike> | 2003-02-02 18:11:15 +0000 |
---|---|---|
committer | jdike <jdike> | 2003-02-02 18:11:15 +0000 |
commit | e4dea0b1281a1cfe452d54245ac542dc7f6db4cd (patch) | |
tree | 6f7e2310e83da79effc2fe8345d6c9ffb68d8274 | |
parent | 9ccde2faf5d6d5370519e191b3d08d79c7e7c084 (diff) | |
download | uml-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.c | 97 | ||||
-rw-r--r-- | arch/um/fs/hostfs/hostfs_user.c | 19 |
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) |