diff options
author | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@ppc970.osdl.org> | 2005-04-16 18:20:36 -0400 |
commit | 1da177e4c3f41524e886b7f1b8a0c1fc7321cac2 (patch) | |
tree | 0bba044c4ce775e45a88a51686b5d9f90697ea9d /fs/udf/file.c |
Linux-2.6.12-rc2v2.6.12-rc2
Initial git repository build. I'm not bothering with the full history,
even though we have it. We can create a separate "historical" git
archive of that later if we want to, and in the meantime it's about
3.2GB when imported into git - space that would just make the early
git days unnecessarily complicated, when we don't have a lot of good
infrastructure for it.
Let it rip!
Diffstat (limited to 'fs/udf/file.c')
-rw-r--r-- | fs/udf/file.c | 270 |
1 files changed, 270 insertions, 0 deletions
diff --git a/fs/udf/file.c b/fs/udf/file.c new file mode 100644 index 000000000000..2faa4172b9f7 --- /dev/null +++ b/fs/udf/file.c | |||
@@ -0,0 +1,270 @@ | |||
1 | /* | ||
2 | * file.c | ||
3 | * | ||
4 | * PURPOSE | ||
5 | * File handling routines for the OSTA-UDF(tm) filesystem. | ||
6 | * | ||
7 | * CONTACTS | ||
8 | * E-mail regarding any portion of the Linux UDF file system should be | ||
9 | * directed to the development team mailing list (run by majordomo): | ||
10 | * linux_udf@hpesjro.fc.hp.com | ||
11 | * | ||
12 | * COPYRIGHT | ||
13 | * This file is distributed under the terms of the GNU General Public | ||
14 | * License (GPL). Copies of the GPL can be obtained from: | ||
15 | * ftp://prep.ai.mit.edu/pub/gnu/GPL | ||
16 | * Each contributing author retains all rights to their own work. | ||
17 | * | ||
18 | * (C) 1998-1999 Dave Boynton | ||
19 | * (C) 1998-2004 Ben Fennema | ||
20 | * (C) 1999-2000 Stelias Computing Inc | ||
21 | * | ||
22 | * HISTORY | ||
23 | * | ||
24 | * 10/02/98 dgb Attempt to integrate into udf.o | ||
25 | * 10/07/98 Switched to using generic_readpage, etc., like isofs | ||
26 | * And it works! | ||
27 | * 12/06/98 blf Added udf_file_read. uses generic_file_read for all cases but | ||
28 | * ICBTAG_FLAG_AD_IN_ICB. | ||
29 | * 04/06/99 64 bit file handling on 32 bit systems taken from ext2 file.c | ||
30 | * 05/12/99 Preliminary file write support | ||
31 | */ | ||
32 | |||
33 | #include "udfdecl.h" | ||
34 | #include <linux/fs.h> | ||
35 | #include <linux/udf_fs.h> | ||
36 | #include <asm/uaccess.h> | ||
37 | #include <linux/kernel.h> | ||
38 | #include <linux/string.h> /* memset */ | ||
39 | #include <linux/errno.h> | ||
40 | #include <linux/smp_lock.h> | ||
41 | #include <linux/pagemap.h> | ||
42 | #include <linux/buffer_head.h> | ||
43 | |||
44 | #include "udf_i.h" | ||
45 | #include "udf_sb.h" | ||
46 | |||
47 | static int udf_adinicb_readpage(struct file *file, struct page * page) | ||
48 | { | ||
49 | struct inode *inode = page->mapping->host; | ||
50 | char *kaddr; | ||
51 | |||
52 | if (!PageLocked(page)) | ||
53 | PAGE_BUG(page); | ||
54 | |||
55 | kaddr = kmap(page); | ||
56 | memset(kaddr, 0, PAGE_CACHE_SIZE); | ||
57 | memcpy(kaddr, UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), inode->i_size); | ||
58 | flush_dcache_page(page); | ||
59 | SetPageUptodate(page); | ||
60 | kunmap(page); | ||
61 | unlock_page(page); | ||
62 | return 0; | ||
63 | } | ||
64 | |||
65 | static int udf_adinicb_writepage(struct page *page, struct writeback_control *wbc) | ||
66 | { | ||
67 | struct inode *inode = page->mapping->host; | ||
68 | char *kaddr; | ||
69 | |||
70 | if (!PageLocked(page)) | ||
71 | PAGE_BUG(page); | ||
72 | |||
73 | kaddr = kmap(page); | ||
74 | memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode), kaddr, inode->i_size); | ||
75 | mark_inode_dirty(inode); | ||
76 | SetPageUptodate(page); | ||
77 | kunmap(page); | ||
78 | unlock_page(page); | ||
79 | return 0; | ||
80 | } | ||
81 | |||
82 | static int udf_adinicb_prepare_write(struct file *file, struct page *page, unsigned offset, unsigned to) | ||
83 | { | ||
84 | kmap(page); | ||
85 | return 0; | ||
86 | } | ||
87 | |||
88 | static int udf_adinicb_commit_write(struct file *file, struct page *page, unsigned offset, unsigned to) | ||
89 | { | ||
90 | struct inode *inode = page->mapping->host; | ||
91 | char *kaddr = page_address(page); | ||
92 | |||
93 | memcpy(UDF_I_DATA(inode) + UDF_I_LENEATTR(inode) + offset, | ||
94 | kaddr + offset, to - offset); | ||
95 | mark_inode_dirty(inode); | ||
96 | SetPageUptodate(page); | ||
97 | kunmap(page); | ||
98 | /* only one page here */ | ||
99 | if (to > inode->i_size) | ||
100 | inode->i_size = to; | ||
101 | return 0; | ||
102 | } | ||
103 | |||
104 | struct address_space_operations udf_adinicb_aops = { | ||
105 | .readpage = udf_adinicb_readpage, | ||
106 | .writepage = udf_adinicb_writepage, | ||
107 | .sync_page = block_sync_page, | ||
108 | .prepare_write = udf_adinicb_prepare_write, | ||
109 | .commit_write = udf_adinicb_commit_write, | ||
110 | }; | ||
111 | |||
112 | static ssize_t udf_file_write(struct file * file, const char __user * buf, | ||
113 | size_t count, loff_t *ppos) | ||
114 | { | ||
115 | ssize_t retval; | ||
116 | struct inode *inode = file->f_dentry->d_inode; | ||
117 | int err, pos; | ||
118 | |||
119 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
120 | { | ||
121 | if (file->f_flags & O_APPEND) | ||
122 | pos = inode->i_size; | ||
123 | else | ||
124 | pos = *ppos; | ||
125 | |||
126 | if (inode->i_sb->s_blocksize < (udf_file_entry_alloc_offset(inode) + | ||
127 | pos + count)) | ||
128 | { | ||
129 | udf_expand_file_adinicb(inode, pos + count, &err); | ||
130 | if (UDF_I_ALLOCTYPE(inode) == ICBTAG_FLAG_AD_IN_ICB) | ||
131 | { | ||
132 | udf_debug("udf_expand_adinicb: err=%d\n", err); | ||
133 | return err; | ||
134 | } | ||
135 | } | ||
136 | else | ||
137 | { | ||
138 | if (pos + count > inode->i_size) | ||
139 | UDF_I_LENALLOC(inode) = pos + count; | ||
140 | else | ||
141 | UDF_I_LENALLOC(inode) = inode->i_size; | ||
142 | } | ||
143 | } | ||
144 | |||
145 | retval = generic_file_write(file, buf, count, ppos); | ||
146 | |||
147 | if (retval > 0) | ||
148 | mark_inode_dirty(inode); | ||
149 | return retval; | ||
150 | } | ||
151 | |||
152 | /* | ||
153 | * udf_ioctl | ||
154 | * | ||
155 | * PURPOSE | ||
156 | * Issue an ioctl. | ||
157 | * | ||
158 | * DESCRIPTION | ||
159 | * Optional - sys_ioctl() will return -ENOTTY if this routine is not | ||
160 | * available, and the ioctl cannot be handled without filesystem help. | ||
161 | * | ||
162 | * sys_ioctl() handles these ioctls that apply only to regular files: | ||
163 | * FIBMAP [requires udf_block_map()], FIGETBSZ, FIONREAD | ||
164 | * These ioctls are also handled by sys_ioctl(): | ||
165 | * FIOCLEX, FIONCLEX, FIONBIO, FIOASYNC | ||
166 | * All other ioctls are passed to the filesystem. | ||
167 | * | ||
168 | * Refer to sys_ioctl() in fs/ioctl.c | ||
169 | * sys_ioctl() -> . | ||
170 | * | ||
171 | * PRE-CONDITIONS | ||
172 | * inode Pointer to inode that ioctl was issued on. | ||
173 | * filp Pointer to file that ioctl was issued on. | ||
174 | * cmd The ioctl command. | ||
175 | * arg The ioctl argument [can be interpreted as a | ||
176 | * user-space pointer if desired]. | ||
177 | * | ||
178 | * POST-CONDITIONS | ||
179 | * <return> Success (>=0) or an error code (<=0) that | ||
180 | * sys_ioctl() will return. | ||
181 | * | ||
182 | * HISTORY | ||
183 | * July 1, 1997 - Andrew E. Mileski | ||
184 | * Written, tested, and released. | ||
185 | */ | ||
186 | int udf_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, | ||
187 | unsigned long arg) | ||
188 | { | ||
189 | int result = -EINVAL; | ||
190 | |||
191 | if ( permission(inode, MAY_READ, NULL) != 0 ) | ||
192 | { | ||
193 | udf_debug("no permission to access inode %lu\n", | ||
194 | inode->i_ino); | ||
195 | return -EPERM; | ||
196 | } | ||
197 | |||
198 | if ( !arg ) | ||
199 | { | ||
200 | udf_debug("invalid argument to udf_ioctl\n"); | ||
201 | return -EINVAL; | ||
202 | } | ||
203 | |||
204 | switch (cmd) | ||
205 | { | ||
206 | case UDF_GETVOLIDENT: | ||
207 | return copy_to_user((char __user *)arg, | ||
208 | UDF_SB_VOLIDENT(inode->i_sb), 32) ? -EFAULT : 0; | ||
209 | case UDF_RELOCATE_BLOCKS: | ||
210 | { | ||
211 | long old, new; | ||
212 | |||
213 | if (!capable(CAP_SYS_ADMIN)) return -EACCES; | ||
214 | if (get_user(old, (long __user *)arg)) return -EFAULT; | ||
215 | if ((result = udf_relocate_blocks(inode->i_sb, | ||
216 | old, &new)) == 0) | ||
217 | result = put_user(new, (long __user *)arg); | ||
218 | |||
219 | return result; | ||
220 | } | ||
221 | case UDF_GETEASIZE: | ||
222 | result = put_user(UDF_I_LENEATTR(inode), (int __user *)arg); | ||
223 | break; | ||
224 | |||
225 | case UDF_GETEABLOCK: | ||
226 | result = copy_to_user((char __user *)arg, UDF_I_DATA(inode), | ||
227 | UDF_I_LENEATTR(inode)) ? -EFAULT : 0; | ||
228 | break; | ||
229 | } | ||
230 | |||
231 | return result; | ||
232 | } | ||
233 | |||
234 | /* | ||
235 | * udf_release_file | ||
236 | * | ||
237 | * PURPOSE | ||
238 | * Called when all references to the file are closed | ||
239 | * | ||
240 | * DESCRIPTION | ||
241 | * Discard prealloced blocks | ||
242 | * | ||
243 | * HISTORY | ||
244 | * | ||
245 | */ | ||
246 | static int udf_release_file(struct inode * inode, struct file * filp) | ||
247 | { | ||
248 | if (filp->f_mode & FMODE_WRITE) | ||
249 | { | ||
250 | lock_kernel(); | ||
251 | udf_discard_prealloc(inode); | ||
252 | unlock_kernel(); | ||
253 | } | ||
254 | return 0; | ||
255 | } | ||
256 | |||
257 | struct file_operations udf_file_operations = { | ||
258 | .read = generic_file_read, | ||
259 | .ioctl = udf_ioctl, | ||
260 | .open = generic_file_open, | ||
261 | .mmap = generic_file_mmap, | ||
262 | .write = udf_file_write, | ||
263 | .release = udf_release_file, | ||
264 | .fsync = udf_fsync_file, | ||
265 | .sendfile = generic_file_sendfile, | ||
266 | }; | ||
267 | |||
268 | struct inode_operations udf_file_inode_operations = { | ||
269 | .truncate = udf_truncate, | ||
270 | }; | ||