diff options
Diffstat (limited to 'sound/core/info.c')
-rw-r--r-- | sound/core/info.c | 74 |
1 files changed, 43 insertions, 31 deletions
diff --git a/sound/core/info.c b/sound/core/info.c index cc4a53d4b7f8..b70564ed8b37 100644 --- a/sound/core/info.c +++ b/sound/core/info.c | |||
@@ -164,40 +164,44 @@ static loff_t snd_info_entry_llseek(struct file *file, loff_t offset, int orig) | |||
164 | { | 164 | { |
165 | struct snd_info_private_data *data; | 165 | struct snd_info_private_data *data; |
166 | struct snd_info_entry *entry; | 166 | struct snd_info_entry *entry; |
167 | loff_t ret; | 167 | loff_t ret = -EINVAL, size; |
168 | 168 | ||
169 | data = file->private_data; | 169 | data = file->private_data; |
170 | entry = data->entry; | 170 | entry = data->entry; |
171 | lock_kernel(); | 171 | mutex_lock(&entry->access); |
172 | switch (entry->content) { | 172 | if (entry->content == SNDRV_INFO_CONTENT_DATA && |
173 | case SNDRV_INFO_CONTENT_TEXT: | 173 | entry->c.ops->llseek) { |
174 | switch (orig) { | 174 | offset = entry->c.ops->llseek(entry, |
175 | case SEEK_SET: | 175 | data->file_private_data, |
176 | file->f_pos = offset; | 176 | file, offset, orig); |
177 | ret = file->f_pos; | 177 | goto out; |
178 | goto out; | 178 | } |
179 | case SEEK_CUR: | 179 | if (entry->content == SNDRV_INFO_CONTENT_DATA) |
180 | file->f_pos += offset; | 180 | size = entry->size; |
181 | ret = file->f_pos; | 181 | else |
182 | goto out; | 182 | size = 0; |
183 | case SEEK_END: | 183 | switch (orig) { |
184 | default: | 184 | case SEEK_SET: |
185 | ret = -EINVAL; | ||
186 | goto out; | ||
187 | } | ||
188 | break; | 185 | break; |
189 | case SNDRV_INFO_CONTENT_DATA: | 186 | case SEEK_CUR: |
190 | if (entry->c.ops->llseek) { | 187 | offset += file->f_pos; |
191 | ret = entry->c.ops->llseek(entry, | 188 | break; |
192 | data->file_private_data, | 189 | case SEEK_END: |
193 | file, offset, orig); | 190 | if (!size) |
194 | goto out; | 191 | goto out; |
195 | } | 192 | offset += size; |
196 | break; | 193 | break; |
197 | } | 194 | default: |
198 | ret = -ENXIO; | 195 | goto out; |
199 | out: | 196 | } |
200 | unlock_kernel(); | 197 | if (offset < 0) |
198 | goto out; | ||
199 | if (size && offset > size) | ||
200 | offset = size; | ||
201 | file->f_pos = offset; | ||
202 | ret = offset; | ||
203 | out: | ||
204 | mutex_unlock(&entry->access); | ||
201 | return ret; | 205 | return ret; |
202 | } | 206 | } |
203 | 207 | ||
@@ -232,10 +236,15 @@ static ssize_t snd_info_entry_read(struct file *file, char __user *buffer, | |||
232 | return -EFAULT; | 236 | return -EFAULT; |
233 | break; | 237 | break; |
234 | case SNDRV_INFO_CONTENT_DATA: | 238 | case SNDRV_INFO_CONTENT_DATA: |
235 | if (entry->c.ops->read) | 239 | if (pos >= entry->size) |
240 | return 0; | ||
241 | if (entry->c.ops->read) { | ||
242 | size = entry->size - pos; | ||
243 | size = min(count, size); | ||
236 | size = entry->c.ops->read(entry, | 244 | size = entry->c.ops->read(entry, |
237 | data->file_private_data, | 245 | data->file_private_data, |
238 | file, buffer, count, pos); | 246 | file, buffer, size, pos); |
247 | } | ||
239 | break; | 248 | break; |
240 | } | 249 | } |
241 | if ((ssize_t) size > 0) | 250 | if ((ssize_t) size > 0) |
@@ -282,10 +291,13 @@ static ssize_t snd_info_entry_write(struct file *file, const char __user *buffer | |||
282 | size = count; | 291 | size = count; |
283 | break; | 292 | break; |
284 | case SNDRV_INFO_CONTENT_DATA: | 293 | case SNDRV_INFO_CONTENT_DATA: |
285 | if (entry->c.ops->write) | 294 | if (entry->c.ops->write && count > 0) { |
295 | size_t maxsize = entry->size - pos; | ||
296 | count = min(count, maxsize); | ||
286 | size = entry->c.ops->write(entry, | 297 | size = entry->c.ops->write(entry, |
287 | data->file_private_data, | 298 | data->file_private_data, |
288 | file, buffer, count, pos); | 299 | file, buffer, count, pos); |
300 | } | ||
289 | break; | 301 | break; |
290 | } | 302 | } |
291 | if ((ssize_t) size > 0) | 303 | if ((ssize_t) size > 0) |