Blame view
fs/ncpfs/file.c
5.76 KB
1da177e4c
|
1 2 3 4 5 6 7 |
/* * file.c * * Copyright (C) 1995, 1996 by Volker Lendecke * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache * */ |
b41f8b84d
|
8 |
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt |
1da177e4c
|
9 |
#include <asm/uaccess.h> |
1da177e4c
|
10 11 12 13 14 15 16 |
#include <linux/time.h> #include <linux/kernel.h> #include <linux/errno.h> #include <linux/fcntl.h> #include <linux/stat.h> #include <linux/mm.h> |
1da177e4c
|
17 |
#include <linux/vmalloc.h> |
e8edc6e03
|
18 |
#include <linux/sched.h> |
1da177e4c
|
19 |
|
32c419d95
|
20 |
#include "ncp_fs.h" |
1da177e4c
|
21 |
|
02c24a821
|
22 |
static int ncp_fsync(struct file *file, loff_t start, loff_t end, int datasync) |
1da177e4c
|
23 |
{ |
02c24a821
|
24 |
return filemap_write_and_wait_range(file->f_mapping, start, end); |
1da177e4c
|
25 26 27 28 29 30 31 32 33 34 35 36 |
} /* * Open a file with the specified read/write mode. */ int ncp_make_open(struct inode *inode, int right) { int error; int access; error = -EINVAL; if (!inode) { |
b41f8b84d
|
37 38 |
pr_err("%s: got NULL inode ", __func__); |
1da177e4c
|
39 40 |
goto out; } |
d3b73ca1b
|
41 42 |
ncp_dbg(1, "opened=%d, volume # %u, dir entry # %u ", |
1da177e4c
|
43 44 45 46 |
atomic_read(&NCP_FINFO(inode)->opened), NCP_FINFO(inode)->volNumber, NCP_FINFO(inode)->dirEntNum); error = -EACCES; |
8e3f90459
|
47 |
mutex_lock(&NCP_FINFO(inode)->open_mutex); |
1da177e4c
|
48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 |
if (!atomic_read(&NCP_FINFO(inode)->opened)) { struct ncp_entry_info finfo; int result; /* tries max. rights */ finfo.access = O_RDWR; result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), inode, NULL, OC_MODE_OPEN, 0, AR_READ | AR_WRITE, &finfo); if (!result) goto update; /* RDWR did not succeeded, try readonly or writeonly as requested */ switch (right) { case O_RDONLY: finfo.access = O_RDONLY; result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), inode, NULL, OC_MODE_OPEN, 0, AR_READ, &finfo); break; case O_WRONLY: finfo.access = O_WRONLY; result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), inode, NULL, OC_MODE_OPEN, 0, AR_WRITE, &finfo); break; } if (result) { |
e45ca8baa
|
75 76 |
ncp_vdbg("failed, result=%d ", result); |
1da177e4c
|
77 78 79 80 81 82 83 84 85 86 87 |
goto out_unlock; } /* * Update the inode information. */ update: ncp_update_inode(inode, &finfo); atomic_set(&NCP_FINFO(inode)->opened, 1); } access = NCP_FINFO(inode)->access; |
e45ca8baa
|
88 89 |
ncp_vdbg("file open, access=%x ", access); |
1da177e4c
|
90 91 92 93 94 95 |
if (access == right || access == O_RDWR) { atomic_inc(&NCP_FINFO(inode)->opened); error = 0; } out_unlock: |
8e3f90459
|
96 |
mutex_unlock(&NCP_FINFO(inode)->open_mutex); |
1da177e4c
|
97 98 99 100 101 |
out: return error; } static ssize_t |
274a48869
|
102 |
ncp_file_read_iter(struct kiocb *iocb, struct iov_iter *to) |
1da177e4c
|
103 |
{ |
274a48869
|
104 |
struct file *file = iocb->ki_filp; |
a67f797db
|
105 |
struct inode *inode = file_inode(file); |
1da177e4c
|
106 |
size_t already_read = 0; |
274a48869
|
107 |
off_t pos = iocb->ki_pos; |
1da177e4c
|
108 109 |
size_t bufsize; int error; |
274a48869
|
110 |
void *freepage; |
1da177e4c
|
111 |
size_t freelen; |
a67f797db
|
112 113 |
ncp_dbg(1, "enter %pD2 ", file); |
1da177e4c
|
114 |
|
274a48869
|
115 |
if (!iov_iter_count(to)) |
1da177e4c
|
116 117 118 |
return 0; if (pos > inode->i_sb->s_maxbytes) return 0; |
274a48869
|
119 |
iov_iter_truncate(to, inode->i_sb->s_maxbytes - pos); |
1da177e4c
|
120 121 122 |
error = ncp_make_open(inode, O_RDONLY); if (error) { |
d3b73ca1b
|
123 124 |
ncp_dbg(1, "open failed, error=%d ", error); |
1da177e4c
|
125 126 127 128 129 130 131 132 133 134 135 136 |
return error; } bufsize = NCP_SERVER(inode)->buffer_size; error = -EIO; freelen = ncp_read_bounce_size(bufsize); freepage = vmalloc(freelen); if (!freepage) goto outrel; error = 0; /* First read in as much as possible for each bufsize. */ |
274a48869
|
137 |
while (iov_iter_count(to)) { |
1da177e4c
|
138 |
int read_this_time; |
274a48869
|
139 |
size_t to_read = min_t(size_t, |
1da177e4c
|
140 |
bufsize - (pos % bufsize), |
274a48869
|
141 |
iov_iter_count(to)); |
1da177e4c
|
142 143 144 |
error = ncp_read_bounce(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, |
274a48869
|
145 |
pos, to_read, to, &read_this_time, |
1da177e4c
|
146 147 148 149 150 151 |
freepage, freelen); if (error) { error = -EIO; /* NW errno -> Linux errno */ break; } pos += read_this_time; |
1da177e4c
|
152 |
already_read += read_this_time; |
274a48869
|
153 |
if (read_this_time != to_read) |
1da177e4c
|
154 |
break; |
1da177e4c
|
155 156 |
} vfree(freepage); |
274a48869
|
157 |
iocb->ki_pos = pos; |
1da177e4c
|
158 159 |
file_accessed(file); |
a67f797db
|
160 161 |
ncp_dbg(1, "exit %pD2 ", file); |
1da177e4c
|
162 163 164 165 166 167 |
outrel: ncp_inode_close(inode); return already_read ? already_read : error; } static ssize_t |
274a48869
|
168 |
ncp_file_write_iter(struct kiocb *iocb, struct iov_iter *from) |
1da177e4c
|
169 |
{ |
274a48869
|
170 |
struct file *file = iocb->ki_filp; |
a67f797db
|
171 |
struct inode *inode = file_inode(file); |
1da177e4c
|
172 |
size_t already_written = 0; |
1da177e4c
|
173 174 |
size_t bufsize; int errno; |
274a48869
|
175 |
void *bouncebuffer; |
3309dd04c
|
176 |
off_t pos; |
1da177e4c
|
177 |
|
a67f797db
|
178 179 |
ncp_dbg(1, "enter %pD2 ", file); |
3309dd04c
|
180 181 |
errno = generic_write_checks(iocb, from); if (errno <= 0) |
274a48869
|
182 |
return errno; |
274a48869
|
183 |
|
1da177e4c
|
184 185 |
errno = ncp_make_open(inode, O_WRONLY); if (errno) { |
d3b73ca1b
|
186 187 |
ncp_dbg(1, "open failed, error=%d ", errno); |
1da177e4c
|
188 189 190 |
return errno; } bufsize = NCP_SERVER(inode)->buffer_size; |
c3b2da314
|
191 192 193 |
errno = file_update_time(file); if (errno) goto outrel; |
1da177e4c
|
194 195 196 197 198 |
bouncebuffer = vmalloc(bufsize); if (!bouncebuffer) { errno = -EIO; /* -ENOMEM */ goto outrel; } |
3309dd04c
|
199 |
pos = iocb->ki_pos; |
274a48869
|
200 |
while (iov_iter_count(from)) { |
1da177e4c
|
201 |
int written_this_time; |
274a48869
|
202 |
size_t to_write = min_t(size_t, |
3309dd04c
|
203 |
bufsize - (pos % bufsize), |
274a48869
|
204 |
iov_iter_count(from)); |
1da177e4c
|
205 |
|
274a48869
|
206 |
if (copy_from_iter(bouncebuffer, to_write, from) != to_write) { |
1da177e4c
|
207 208 209 210 211 212 213 214 215 216 |
errno = -EFAULT; break; } if (ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, pos, to_write, bouncebuffer, &written_this_time) != 0) { errno = -EIO; break; } pos += written_this_time; |
1da177e4c
|
217 |
already_written += written_this_time; |
274a48869
|
218 |
if (written_this_time != to_write) |
1da177e4c
|
219 |
break; |
1da177e4c
|
220 221 |
} vfree(bouncebuffer); |
274a48869
|
222 |
iocb->ki_pos = pos; |
1da177e4c
|
223 |
|
2e54eb96e
|
224 |
if (pos > i_size_read(inode)) { |
5955102c9
|
225 |
inode_lock(inode); |
2e54eb96e
|
226 227 |
if (pos > i_size_read(inode)) i_size_write(inode, pos); |
5955102c9
|
228 |
inode_unlock(inode); |
1da177e4c
|
229 |
} |
a67f797db
|
230 231 |
ncp_dbg(1, "exit %pD2 ", file); |
1da177e4c
|
232 233 234 235 236 237 238 |
outrel: ncp_inode_close(inode); return already_written ? already_written : errno; } static int ncp_release(struct inode *inode, struct file *file) { if (ncp_make_closed(inode)) { |
d3b73ca1b
|
239 240 |
ncp_dbg(1, "failed to close "); |
1da177e4c
|
241 242 243 |
} return 0; } |
4b6f5d20b
|
244 |
const struct file_operations ncp_file_operations = |
1da177e4c
|
245 |
{ |
2e54eb96e
|
246 |
.llseek = generic_file_llseek, |
274a48869
|
247 248 |
.read_iter = ncp_file_read_iter, .write_iter = ncp_file_write_iter, |
93d84b6d9
|
249 |
.unlocked_ioctl = ncp_ioctl, |
54f67f631
|
250 251 252 |
#ifdef CONFIG_COMPAT .compat_ioctl = ncp_compat_ioctl, #endif |
1da177e4c
|
253 254 255 256 |
.mmap = ncp_mmap, .release = ncp_release, .fsync = ncp_fsync, }; |
92e1d5be9
|
257 |
const struct inode_operations ncp_file_inode_operations = |
1da177e4c
|
258 259 260 |
{ .setattr = ncp_notify_change, }; |