Commit 92e5baef8578a03335059a3dec933955c361edc1
Committed by
Linus Torvalds
1 parent
17506041de
Exists in
master
and in
7 other branches
[PATCH] struct path: convert ncpfs
Signed-off-by: Josef Sipek <jsipek@fsl.cs.sunysb.edu> Signed-off-by: Andrew Morton <akpm@osdl.org> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Showing 5 changed files with 14 additions and 14 deletions Inline Diff
fs/ncpfs/dir.c
1 | /* | 1 | /* |
2 | * dir.c | 2 | * dir.c |
3 | * | 3 | * |
4 | * Copyright (C) 1995, 1996 by Volker Lendecke | 4 | * Copyright (C) 1995, 1996 by Volker Lendecke |
5 | * Modified for big endian by J.F. Chadima and David S. Miller | 5 | * Modified for big endian by J.F. Chadima and David S. Miller |
6 | * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache | 6 | * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache |
7 | * Modified 1998, 1999 Wolfram Pienkoss for NLS | 7 | * Modified 1998, 1999 Wolfram Pienkoss for NLS |
8 | * Modified 1999 Wolfram Pienkoss for directory caching | 8 | * Modified 1999 Wolfram Pienkoss for directory caching |
9 | * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info | 9 | * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info |
10 | * | 10 | * |
11 | */ | 11 | */ |
12 | 12 | ||
13 | 13 | ||
14 | #include <linux/time.h> | 14 | #include <linux/time.h> |
15 | #include <linux/errno.h> | 15 | #include <linux/errno.h> |
16 | #include <linux/stat.h> | 16 | #include <linux/stat.h> |
17 | #include <linux/kernel.h> | 17 | #include <linux/kernel.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
20 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
21 | #include <asm/uaccess.h> | 21 | #include <asm/uaccess.h> |
22 | #include <asm/byteorder.h> | 22 | #include <asm/byteorder.h> |
23 | #include <linux/smp_lock.h> | 23 | #include <linux/smp_lock.h> |
24 | 24 | ||
25 | #include <linux/ncp_fs.h> | 25 | #include <linux/ncp_fs.h> |
26 | 26 | ||
27 | #include "ncplib_kernel.h" | 27 | #include "ncplib_kernel.h" |
28 | 28 | ||
29 | static void ncp_read_volume_list(struct file *, void *, filldir_t, | 29 | static void ncp_read_volume_list(struct file *, void *, filldir_t, |
30 | struct ncp_cache_control *); | 30 | struct ncp_cache_control *); |
31 | static void ncp_do_readdir(struct file *, void *, filldir_t, | 31 | static void ncp_do_readdir(struct file *, void *, filldir_t, |
32 | struct ncp_cache_control *); | 32 | struct ncp_cache_control *); |
33 | 33 | ||
34 | static int ncp_readdir(struct file *, void *, filldir_t); | 34 | static int ncp_readdir(struct file *, void *, filldir_t); |
35 | 35 | ||
36 | static int ncp_create(struct inode *, struct dentry *, int, struct nameidata *); | 36 | static int ncp_create(struct inode *, struct dentry *, int, struct nameidata *); |
37 | static struct dentry *ncp_lookup(struct inode *, struct dentry *, struct nameidata *); | 37 | static struct dentry *ncp_lookup(struct inode *, struct dentry *, struct nameidata *); |
38 | static int ncp_unlink(struct inode *, struct dentry *); | 38 | static int ncp_unlink(struct inode *, struct dentry *); |
39 | static int ncp_mkdir(struct inode *, struct dentry *, int); | 39 | static int ncp_mkdir(struct inode *, struct dentry *, int); |
40 | static int ncp_rmdir(struct inode *, struct dentry *); | 40 | static int ncp_rmdir(struct inode *, struct dentry *); |
41 | static int ncp_rename(struct inode *, struct dentry *, | 41 | static int ncp_rename(struct inode *, struct dentry *, |
42 | struct inode *, struct dentry *); | 42 | struct inode *, struct dentry *); |
43 | static int ncp_mknod(struct inode * dir, struct dentry *dentry, | 43 | static int ncp_mknod(struct inode * dir, struct dentry *dentry, |
44 | int mode, dev_t rdev); | 44 | int mode, dev_t rdev); |
45 | #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) | 45 | #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) |
46 | extern int ncp_symlink(struct inode *, struct dentry *, const char *); | 46 | extern int ncp_symlink(struct inode *, struct dentry *, const char *); |
47 | #else | 47 | #else |
48 | #define ncp_symlink NULL | 48 | #define ncp_symlink NULL |
49 | #endif | 49 | #endif |
50 | 50 | ||
51 | const struct file_operations ncp_dir_operations = | 51 | const struct file_operations ncp_dir_operations = |
52 | { | 52 | { |
53 | .read = generic_read_dir, | 53 | .read = generic_read_dir, |
54 | .readdir = ncp_readdir, | 54 | .readdir = ncp_readdir, |
55 | .ioctl = ncp_ioctl, | 55 | .ioctl = ncp_ioctl, |
56 | #ifdef CONFIG_COMPAT | 56 | #ifdef CONFIG_COMPAT |
57 | .compat_ioctl = ncp_compat_ioctl, | 57 | .compat_ioctl = ncp_compat_ioctl, |
58 | #endif | 58 | #endif |
59 | }; | 59 | }; |
60 | 60 | ||
61 | struct inode_operations ncp_dir_inode_operations = | 61 | struct inode_operations ncp_dir_inode_operations = |
62 | { | 62 | { |
63 | .create = ncp_create, | 63 | .create = ncp_create, |
64 | .lookup = ncp_lookup, | 64 | .lookup = ncp_lookup, |
65 | .unlink = ncp_unlink, | 65 | .unlink = ncp_unlink, |
66 | .symlink = ncp_symlink, | 66 | .symlink = ncp_symlink, |
67 | .mkdir = ncp_mkdir, | 67 | .mkdir = ncp_mkdir, |
68 | .rmdir = ncp_rmdir, | 68 | .rmdir = ncp_rmdir, |
69 | .mknod = ncp_mknod, | 69 | .mknod = ncp_mknod, |
70 | .rename = ncp_rename, | 70 | .rename = ncp_rename, |
71 | .setattr = ncp_notify_change, | 71 | .setattr = ncp_notify_change, |
72 | }; | 72 | }; |
73 | 73 | ||
74 | /* | 74 | /* |
75 | * Dentry operations routines | 75 | * Dentry operations routines |
76 | */ | 76 | */ |
77 | static int ncp_lookup_validate(struct dentry *, struct nameidata *); | 77 | static int ncp_lookup_validate(struct dentry *, struct nameidata *); |
78 | static int ncp_hash_dentry(struct dentry *, struct qstr *); | 78 | static int ncp_hash_dentry(struct dentry *, struct qstr *); |
79 | static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); | 79 | static int ncp_compare_dentry (struct dentry *, struct qstr *, struct qstr *); |
80 | static int ncp_delete_dentry(struct dentry *); | 80 | static int ncp_delete_dentry(struct dentry *); |
81 | 81 | ||
82 | static struct dentry_operations ncp_dentry_operations = | 82 | static struct dentry_operations ncp_dentry_operations = |
83 | { | 83 | { |
84 | .d_revalidate = ncp_lookup_validate, | 84 | .d_revalidate = ncp_lookup_validate, |
85 | .d_hash = ncp_hash_dentry, | 85 | .d_hash = ncp_hash_dentry, |
86 | .d_compare = ncp_compare_dentry, | 86 | .d_compare = ncp_compare_dentry, |
87 | .d_delete = ncp_delete_dentry, | 87 | .d_delete = ncp_delete_dentry, |
88 | }; | 88 | }; |
89 | 89 | ||
90 | struct dentry_operations ncp_root_dentry_operations = | 90 | struct dentry_operations ncp_root_dentry_operations = |
91 | { | 91 | { |
92 | .d_hash = ncp_hash_dentry, | 92 | .d_hash = ncp_hash_dentry, |
93 | .d_compare = ncp_compare_dentry, | 93 | .d_compare = ncp_compare_dentry, |
94 | .d_delete = ncp_delete_dentry, | 94 | .d_delete = ncp_delete_dentry, |
95 | }; | 95 | }; |
96 | 96 | ||
97 | 97 | ||
98 | /* | 98 | /* |
99 | * Note: leave the hash unchanged if the directory | 99 | * Note: leave the hash unchanged if the directory |
100 | * is case-sensitive. | 100 | * is case-sensitive. |
101 | */ | 101 | */ |
102 | static int | 102 | static int |
103 | ncp_hash_dentry(struct dentry *dentry, struct qstr *this) | 103 | ncp_hash_dentry(struct dentry *dentry, struct qstr *this) |
104 | { | 104 | { |
105 | struct nls_table *t; | 105 | struct nls_table *t; |
106 | unsigned long hash; | 106 | unsigned long hash; |
107 | int i; | 107 | int i; |
108 | 108 | ||
109 | t = NCP_IO_TABLE(dentry); | 109 | t = NCP_IO_TABLE(dentry); |
110 | 110 | ||
111 | if (!ncp_case_sensitive(dentry->d_inode)) { | 111 | if (!ncp_case_sensitive(dentry->d_inode)) { |
112 | hash = init_name_hash(); | 112 | hash = init_name_hash(); |
113 | for (i=0; i<this->len ; i++) | 113 | for (i=0; i<this->len ; i++) |
114 | hash = partial_name_hash(ncp_tolower(t, this->name[i]), | 114 | hash = partial_name_hash(ncp_tolower(t, this->name[i]), |
115 | hash); | 115 | hash); |
116 | this->hash = end_name_hash(hash); | 116 | this->hash = end_name_hash(hash); |
117 | } | 117 | } |
118 | return 0; | 118 | return 0; |
119 | } | 119 | } |
120 | 120 | ||
121 | static int | 121 | static int |
122 | ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) | 122 | ncp_compare_dentry(struct dentry *dentry, struct qstr *a, struct qstr *b) |
123 | { | 123 | { |
124 | if (a->len != b->len) | 124 | if (a->len != b->len) |
125 | return 1; | 125 | return 1; |
126 | 126 | ||
127 | if (ncp_case_sensitive(dentry->d_inode)) | 127 | if (ncp_case_sensitive(dentry->d_inode)) |
128 | return strncmp(a->name, b->name, a->len); | 128 | return strncmp(a->name, b->name, a->len); |
129 | 129 | ||
130 | return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len); | 130 | return ncp_strnicmp(NCP_IO_TABLE(dentry), a->name, b->name, a->len); |
131 | } | 131 | } |
132 | 132 | ||
133 | /* | 133 | /* |
134 | * This is the callback from dput() when d_count is going to 0. | 134 | * This is the callback from dput() when d_count is going to 0. |
135 | * We use this to unhash dentries with bad inodes. | 135 | * We use this to unhash dentries with bad inodes. |
136 | * Closing files can be safely postponed until iput() - it's done there anyway. | 136 | * Closing files can be safely postponed until iput() - it's done there anyway. |
137 | */ | 137 | */ |
138 | static int | 138 | static int |
139 | ncp_delete_dentry(struct dentry * dentry) | 139 | ncp_delete_dentry(struct dentry * dentry) |
140 | { | 140 | { |
141 | struct inode *inode = dentry->d_inode; | 141 | struct inode *inode = dentry->d_inode; |
142 | 142 | ||
143 | if (inode) { | 143 | if (inode) { |
144 | if (is_bad_inode(inode)) | 144 | if (is_bad_inode(inode)) |
145 | return 1; | 145 | return 1; |
146 | } else | 146 | } else |
147 | { | 147 | { |
148 | /* N.B. Unhash negative dentries? */ | 148 | /* N.B. Unhash negative dentries? */ |
149 | } | 149 | } |
150 | return 0; | 150 | return 0; |
151 | } | 151 | } |
152 | 152 | ||
153 | static inline int | 153 | static inline int |
154 | ncp_single_volume(struct ncp_server *server) | 154 | ncp_single_volume(struct ncp_server *server) |
155 | { | 155 | { |
156 | return (server->m.mounted_vol[0] != '\0'); | 156 | return (server->m.mounted_vol[0] != '\0'); |
157 | } | 157 | } |
158 | 158 | ||
159 | static inline int ncp_is_server_root(struct inode *inode) | 159 | static inline int ncp_is_server_root(struct inode *inode) |
160 | { | 160 | { |
161 | return (!ncp_single_volume(NCP_SERVER(inode)) && | 161 | return (!ncp_single_volume(NCP_SERVER(inode)) && |
162 | inode == inode->i_sb->s_root->d_inode); | 162 | inode == inode->i_sb->s_root->d_inode); |
163 | } | 163 | } |
164 | 164 | ||
165 | 165 | ||
166 | /* | 166 | /* |
167 | * This is the callback when the dcache has a lookup hit. | 167 | * This is the callback when the dcache has a lookup hit. |
168 | */ | 168 | */ |
169 | 169 | ||
170 | 170 | ||
171 | #ifdef CONFIG_NCPFS_STRONG | 171 | #ifdef CONFIG_NCPFS_STRONG |
172 | /* try to delete a readonly file (NW R bit set) */ | 172 | /* try to delete a readonly file (NW R bit set) */ |
173 | 173 | ||
174 | static int | 174 | static int |
175 | ncp_force_unlink(struct inode *dir, struct dentry* dentry) | 175 | ncp_force_unlink(struct inode *dir, struct dentry* dentry) |
176 | { | 176 | { |
177 | int res=0x9c,res2; | 177 | int res=0x9c,res2; |
178 | struct nw_modify_dos_info info; | 178 | struct nw_modify_dos_info info; |
179 | __le32 old_nwattr; | 179 | __le32 old_nwattr; |
180 | struct inode *inode; | 180 | struct inode *inode; |
181 | 181 | ||
182 | memset(&info, 0, sizeof(info)); | 182 | memset(&info, 0, sizeof(info)); |
183 | 183 | ||
184 | /* remove the Read-Only flag on the NW server */ | 184 | /* remove the Read-Only flag on the NW server */ |
185 | inode = dentry->d_inode; | 185 | inode = dentry->d_inode; |
186 | 186 | ||
187 | old_nwattr = NCP_FINFO(inode)->nwattr; | 187 | old_nwattr = NCP_FINFO(inode)->nwattr; |
188 | info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT); | 188 | info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT); |
189 | res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info); | 189 | res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info); |
190 | if (res2) | 190 | if (res2) |
191 | goto leave_me; | 191 | goto leave_me; |
192 | 192 | ||
193 | /* now try again the delete operation */ | 193 | /* now try again the delete operation */ |
194 | res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry); | 194 | res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry); |
195 | 195 | ||
196 | if (res) /* delete failed, set R bit again */ | 196 | if (res) /* delete failed, set R bit again */ |
197 | { | 197 | { |
198 | info.attributes = old_nwattr; | 198 | info.attributes = old_nwattr; |
199 | res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info); | 199 | res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info); |
200 | if (res2) | 200 | if (res2) |
201 | goto leave_me; | 201 | goto leave_me; |
202 | } | 202 | } |
203 | leave_me: | 203 | leave_me: |
204 | return(res); | 204 | return(res); |
205 | } | 205 | } |
206 | #endif /* CONFIG_NCPFS_STRONG */ | 206 | #endif /* CONFIG_NCPFS_STRONG */ |
207 | 207 | ||
208 | #ifdef CONFIG_NCPFS_STRONG | 208 | #ifdef CONFIG_NCPFS_STRONG |
209 | static int | 209 | static int |
210 | ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name, | 210 | ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name, |
211 | struct inode *new_dir, struct dentry* new_dentry, char *_new_name) | 211 | struct inode *new_dir, struct dentry* new_dentry, char *_new_name) |
212 | { | 212 | { |
213 | struct nw_modify_dos_info info; | 213 | struct nw_modify_dos_info info; |
214 | int res=0x90,res2; | 214 | int res=0x90,res2; |
215 | struct inode *old_inode = old_dentry->d_inode; | 215 | struct inode *old_inode = old_dentry->d_inode; |
216 | __le32 old_nwattr = NCP_FINFO(old_inode)->nwattr; | 216 | __le32 old_nwattr = NCP_FINFO(old_inode)->nwattr; |
217 | __le32 new_nwattr = 0; /* shut compiler warning */ | 217 | __le32 new_nwattr = 0; /* shut compiler warning */ |
218 | int old_nwattr_changed = 0; | 218 | int old_nwattr_changed = 0; |
219 | int new_nwattr_changed = 0; | 219 | int new_nwattr_changed = 0; |
220 | 220 | ||
221 | memset(&info, 0, sizeof(info)); | 221 | memset(&info, 0, sizeof(info)); |
222 | 222 | ||
223 | /* remove the Read-Only flag on the NW server */ | 223 | /* remove the Read-Only flag on the NW server */ |
224 | 224 | ||
225 | info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); | 225 | info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); |
226 | res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info); | 226 | res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info); |
227 | if (!res2) | 227 | if (!res2) |
228 | old_nwattr_changed = 1; | 228 | old_nwattr_changed = 1; |
229 | if (new_dentry && new_dentry->d_inode) { | 229 | if (new_dentry && new_dentry->d_inode) { |
230 | new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr; | 230 | new_nwattr = NCP_FINFO(new_dentry->d_inode)->nwattr; |
231 | info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); | 231 | info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); |
232 | res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info); | 232 | res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info); |
233 | if (!res2) | 233 | if (!res2) |
234 | new_nwattr_changed = 1; | 234 | new_nwattr_changed = 1; |
235 | } | 235 | } |
236 | /* now try again the rename operation */ | 236 | /* now try again the rename operation */ |
237 | /* but only if something really happened */ | 237 | /* but only if something really happened */ |
238 | if (new_nwattr_changed || old_nwattr_changed) { | 238 | if (new_nwattr_changed || old_nwattr_changed) { |
239 | res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir), | 239 | res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir), |
240 | old_dir, _old_name, | 240 | old_dir, _old_name, |
241 | new_dir, _new_name); | 241 | new_dir, _new_name); |
242 | } | 242 | } |
243 | if (res) | 243 | if (res) |
244 | goto leave_me; | 244 | goto leave_me; |
245 | /* file was successfully renamed, so: | 245 | /* file was successfully renamed, so: |
246 | do not set attributes on old file - it no longer exists | 246 | do not set attributes on old file - it no longer exists |
247 | copy attributes from old file to new */ | 247 | copy attributes from old file to new */ |
248 | new_nwattr_changed = old_nwattr_changed; | 248 | new_nwattr_changed = old_nwattr_changed; |
249 | new_nwattr = old_nwattr; | 249 | new_nwattr = old_nwattr; |
250 | old_nwattr_changed = 0; | 250 | old_nwattr_changed = 0; |
251 | 251 | ||
252 | leave_me:; | 252 | leave_me:; |
253 | if (old_nwattr_changed) { | 253 | if (old_nwattr_changed) { |
254 | info.attributes = old_nwattr; | 254 | info.attributes = old_nwattr; |
255 | res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info); | 255 | res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info); |
256 | /* ignore errors */ | 256 | /* ignore errors */ |
257 | } | 257 | } |
258 | if (new_nwattr_changed) { | 258 | if (new_nwattr_changed) { |
259 | info.attributes = new_nwattr; | 259 | info.attributes = new_nwattr; |
260 | res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info); | 260 | res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info); |
261 | /* ignore errors */ | 261 | /* ignore errors */ |
262 | } | 262 | } |
263 | return(res); | 263 | return(res); |
264 | } | 264 | } |
265 | #endif /* CONFIG_NCPFS_STRONG */ | 265 | #endif /* CONFIG_NCPFS_STRONG */ |
266 | 266 | ||
267 | 267 | ||
268 | static int | 268 | static int |
269 | __ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd) | 269 | __ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd) |
270 | { | 270 | { |
271 | struct ncp_server *server; | 271 | struct ncp_server *server; |
272 | struct dentry *parent; | 272 | struct dentry *parent; |
273 | struct inode *dir; | 273 | struct inode *dir; |
274 | struct ncp_entry_info finfo; | 274 | struct ncp_entry_info finfo; |
275 | int res, val = 0, len; | 275 | int res, val = 0, len; |
276 | __u8 __name[NCP_MAXPATHLEN + 1]; | 276 | __u8 __name[NCP_MAXPATHLEN + 1]; |
277 | 277 | ||
278 | parent = dget_parent(dentry); | 278 | parent = dget_parent(dentry); |
279 | dir = parent->d_inode; | 279 | dir = parent->d_inode; |
280 | 280 | ||
281 | if (!dentry->d_inode) | 281 | if (!dentry->d_inode) |
282 | goto finished; | 282 | goto finished; |
283 | 283 | ||
284 | server = NCP_SERVER(dir); | 284 | server = NCP_SERVER(dir); |
285 | 285 | ||
286 | if (!ncp_conn_valid(server)) | 286 | if (!ncp_conn_valid(server)) |
287 | goto finished; | 287 | goto finished; |
288 | 288 | ||
289 | /* | 289 | /* |
290 | * Inspired by smbfs: | 290 | * Inspired by smbfs: |
291 | * The default validation is based on dentry age: | 291 | * The default validation is based on dentry age: |
292 | * We set the max age at mount time. (But each | 292 | * We set the max age at mount time. (But each |
293 | * successful server lookup renews the timestamp.) | 293 | * successful server lookup renews the timestamp.) |
294 | */ | 294 | */ |
295 | val = NCP_TEST_AGE(server, dentry); | 295 | val = NCP_TEST_AGE(server, dentry); |
296 | if (val) | 296 | if (val) |
297 | goto finished; | 297 | goto finished; |
298 | 298 | ||
299 | DDPRINTK("ncp_lookup_validate: %s/%s not valid, age=%ld, server lookup\n", | 299 | DDPRINTK("ncp_lookup_validate: %s/%s not valid, age=%ld, server lookup\n", |
300 | dentry->d_parent->d_name.name, dentry->d_name.name, | 300 | dentry->d_parent->d_name.name, dentry->d_name.name, |
301 | NCP_GET_AGE(dentry)); | 301 | NCP_GET_AGE(dentry)); |
302 | 302 | ||
303 | len = sizeof(__name); | 303 | len = sizeof(__name); |
304 | if (ncp_is_server_root(dir)) { | 304 | if (ncp_is_server_root(dir)) { |
305 | res = ncp_io2vol(server, __name, &len, dentry->d_name.name, | 305 | res = ncp_io2vol(server, __name, &len, dentry->d_name.name, |
306 | dentry->d_name.len, 1); | 306 | dentry->d_name.len, 1); |
307 | if (!res) | 307 | if (!res) |
308 | res = ncp_lookup_volume(server, __name, &(finfo.i)); | 308 | res = ncp_lookup_volume(server, __name, &(finfo.i)); |
309 | } else { | 309 | } else { |
310 | res = ncp_io2vol(server, __name, &len, dentry->d_name.name, | 310 | res = ncp_io2vol(server, __name, &len, dentry->d_name.name, |
311 | dentry->d_name.len, !ncp_preserve_case(dir)); | 311 | dentry->d_name.len, !ncp_preserve_case(dir)); |
312 | if (!res) | 312 | if (!res) |
313 | res = ncp_obtain_info(server, dir, __name, &(finfo.i)); | 313 | res = ncp_obtain_info(server, dir, __name, &(finfo.i)); |
314 | } | 314 | } |
315 | finfo.volume = finfo.i.volNumber; | 315 | finfo.volume = finfo.i.volNumber; |
316 | DDPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n", | 316 | DDPRINTK("ncp_lookup_validate: looked for %s/%s, res=%d\n", |
317 | dentry->d_parent->d_name.name, __name, res); | 317 | dentry->d_parent->d_name.name, __name, res); |
318 | /* | 318 | /* |
319 | * If we didn't find it, or if it has a different dirEntNum to | 319 | * If we didn't find it, or if it has a different dirEntNum to |
320 | * what we remember, it's not valid any more. | 320 | * what we remember, it's not valid any more. |
321 | */ | 321 | */ |
322 | if (!res) { | 322 | if (!res) { |
323 | if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum) { | 323 | if (finfo.i.dirEntNum == NCP_FINFO(dentry->d_inode)->dirEntNum) { |
324 | ncp_new_dentry(dentry); | 324 | ncp_new_dentry(dentry); |
325 | val=1; | 325 | val=1; |
326 | } else | 326 | } else |
327 | DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n"); | 327 | DDPRINTK("ncp_lookup_validate: found, but dirEntNum changed\n"); |
328 | 328 | ||
329 | ncp_update_inode2(dentry->d_inode, &finfo); | 329 | ncp_update_inode2(dentry->d_inode, &finfo); |
330 | } | 330 | } |
331 | 331 | ||
332 | finished: | 332 | finished: |
333 | DDPRINTK("ncp_lookup_validate: result=%d\n", val); | 333 | DDPRINTK("ncp_lookup_validate: result=%d\n", val); |
334 | dput(parent); | 334 | dput(parent); |
335 | return val; | 335 | return val; |
336 | } | 336 | } |
337 | 337 | ||
338 | static int | 338 | static int |
339 | ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd) | 339 | ncp_lookup_validate(struct dentry * dentry, struct nameidata *nd) |
340 | { | 340 | { |
341 | int res; | 341 | int res; |
342 | lock_kernel(); | 342 | lock_kernel(); |
343 | res = __ncp_lookup_validate(dentry, nd); | 343 | res = __ncp_lookup_validate(dentry, nd); |
344 | unlock_kernel(); | 344 | unlock_kernel(); |
345 | return res; | 345 | return res; |
346 | } | 346 | } |
347 | 347 | ||
348 | static struct dentry * | 348 | static struct dentry * |
349 | ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) | 349 | ncp_dget_fpos(struct dentry *dentry, struct dentry *parent, unsigned long fpos) |
350 | { | 350 | { |
351 | struct dentry *dent = dentry; | 351 | struct dentry *dent = dentry; |
352 | struct list_head *next; | 352 | struct list_head *next; |
353 | 353 | ||
354 | if (d_validate(dent, parent)) { | 354 | if (d_validate(dent, parent)) { |
355 | if (dent->d_name.len <= NCP_MAXPATHLEN && | 355 | if (dent->d_name.len <= NCP_MAXPATHLEN && |
356 | (unsigned long)dent->d_fsdata == fpos) { | 356 | (unsigned long)dent->d_fsdata == fpos) { |
357 | if (!dent->d_inode) { | 357 | if (!dent->d_inode) { |
358 | dput(dent); | 358 | dput(dent); |
359 | dent = NULL; | 359 | dent = NULL; |
360 | } | 360 | } |
361 | return dent; | 361 | return dent; |
362 | } | 362 | } |
363 | dput(dent); | 363 | dput(dent); |
364 | } | 364 | } |
365 | 365 | ||
366 | /* If a pointer is invalid, we search the dentry. */ | 366 | /* If a pointer is invalid, we search the dentry. */ |
367 | spin_lock(&dcache_lock); | 367 | spin_lock(&dcache_lock); |
368 | next = parent->d_subdirs.next; | 368 | next = parent->d_subdirs.next; |
369 | while (next != &parent->d_subdirs) { | 369 | while (next != &parent->d_subdirs) { |
370 | dent = list_entry(next, struct dentry, d_u.d_child); | 370 | dent = list_entry(next, struct dentry, d_u.d_child); |
371 | if ((unsigned long)dent->d_fsdata == fpos) { | 371 | if ((unsigned long)dent->d_fsdata == fpos) { |
372 | if (dent->d_inode) | 372 | if (dent->d_inode) |
373 | dget_locked(dent); | 373 | dget_locked(dent); |
374 | else | 374 | else |
375 | dent = NULL; | 375 | dent = NULL; |
376 | spin_unlock(&dcache_lock); | 376 | spin_unlock(&dcache_lock); |
377 | goto out; | 377 | goto out; |
378 | } | 378 | } |
379 | next = next->next; | 379 | next = next->next; |
380 | } | 380 | } |
381 | spin_unlock(&dcache_lock); | 381 | spin_unlock(&dcache_lock); |
382 | return NULL; | 382 | return NULL; |
383 | 383 | ||
384 | out: | 384 | out: |
385 | return dent; | 385 | return dent; |
386 | } | 386 | } |
387 | 387 | ||
388 | static time_t ncp_obtain_mtime(struct dentry *dentry) | 388 | static time_t ncp_obtain_mtime(struct dentry *dentry) |
389 | { | 389 | { |
390 | struct inode *inode = dentry->d_inode; | 390 | struct inode *inode = dentry->d_inode; |
391 | struct ncp_server *server = NCP_SERVER(inode); | 391 | struct ncp_server *server = NCP_SERVER(inode); |
392 | struct nw_info_struct i; | 392 | struct nw_info_struct i; |
393 | 393 | ||
394 | if (!ncp_conn_valid(server) || ncp_is_server_root(inode)) | 394 | if (!ncp_conn_valid(server) || ncp_is_server_root(inode)) |
395 | return 0; | 395 | return 0; |
396 | 396 | ||
397 | if (ncp_obtain_info(server, inode, NULL, &i)) | 397 | if (ncp_obtain_info(server, inode, NULL, &i)) |
398 | return 0; | 398 | return 0; |
399 | 399 | ||
400 | return ncp_date_dos2unix(i.modifyTime, i.modifyDate); | 400 | return ncp_date_dos2unix(i.modifyTime, i.modifyDate); |
401 | } | 401 | } |
402 | 402 | ||
403 | static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) | 403 | static int ncp_readdir(struct file *filp, void *dirent, filldir_t filldir) |
404 | { | 404 | { |
405 | struct dentry *dentry = filp->f_dentry; | 405 | struct dentry *dentry = filp->f_path.dentry; |
406 | struct inode *inode = dentry->d_inode; | 406 | struct inode *inode = dentry->d_inode; |
407 | struct page *page = NULL; | 407 | struct page *page = NULL; |
408 | struct ncp_server *server = NCP_SERVER(inode); | 408 | struct ncp_server *server = NCP_SERVER(inode); |
409 | union ncp_dir_cache *cache = NULL; | 409 | union ncp_dir_cache *cache = NULL; |
410 | struct ncp_cache_control ctl; | 410 | struct ncp_cache_control ctl; |
411 | int result, mtime_valid = 0; | 411 | int result, mtime_valid = 0; |
412 | time_t mtime = 0; | 412 | time_t mtime = 0; |
413 | 413 | ||
414 | lock_kernel(); | 414 | lock_kernel(); |
415 | 415 | ||
416 | ctl.page = NULL; | 416 | ctl.page = NULL; |
417 | ctl.cache = NULL; | 417 | ctl.cache = NULL; |
418 | 418 | ||
419 | DDPRINTK("ncp_readdir: reading %s/%s, pos=%d\n", | 419 | DDPRINTK("ncp_readdir: reading %s/%s, pos=%d\n", |
420 | dentry->d_parent->d_name.name, dentry->d_name.name, | 420 | dentry->d_parent->d_name.name, dentry->d_name.name, |
421 | (int) filp->f_pos); | 421 | (int) filp->f_pos); |
422 | 422 | ||
423 | result = -EIO; | 423 | result = -EIO; |
424 | if (!ncp_conn_valid(server)) | 424 | if (!ncp_conn_valid(server)) |
425 | goto out; | 425 | goto out; |
426 | 426 | ||
427 | result = 0; | 427 | result = 0; |
428 | if (filp->f_pos == 0) { | 428 | if (filp->f_pos == 0) { |
429 | if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR)) | 429 | if (filldir(dirent, ".", 1, 0, inode->i_ino, DT_DIR)) |
430 | goto out; | 430 | goto out; |
431 | filp->f_pos = 1; | 431 | filp->f_pos = 1; |
432 | } | 432 | } |
433 | if (filp->f_pos == 1) { | 433 | if (filp->f_pos == 1) { |
434 | if (filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR)) | 434 | if (filldir(dirent, "..", 2, 1, parent_ino(dentry), DT_DIR)) |
435 | goto out; | 435 | goto out; |
436 | filp->f_pos = 2; | 436 | filp->f_pos = 2; |
437 | } | 437 | } |
438 | 438 | ||
439 | page = grab_cache_page(&inode->i_data, 0); | 439 | page = grab_cache_page(&inode->i_data, 0); |
440 | if (!page) | 440 | if (!page) |
441 | goto read_really; | 441 | goto read_really; |
442 | 442 | ||
443 | ctl.cache = cache = kmap(page); | 443 | ctl.cache = cache = kmap(page); |
444 | ctl.head = cache->head; | 444 | ctl.head = cache->head; |
445 | 445 | ||
446 | if (!PageUptodate(page) || !ctl.head.eof) | 446 | if (!PageUptodate(page) || !ctl.head.eof) |
447 | goto init_cache; | 447 | goto init_cache; |
448 | 448 | ||
449 | if (filp->f_pos == 2) { | 449 | if (filp->f_pos == 2) { |
450 | if (jiffies - ctl.head.time >= NCP_MAX_AGE(server)) | 450 | if (jiffies - ctl.head.time >= NCP_MAX_AGE(server)) |
451 | goto init_cache; | 451 | goto init_cache; |
452 | 452 | ||
453 | mtime = ncp_obtain_mtime(dentry); | 453 | mtime = ncp_obtain_mtime(dentry); |
454 | mtime_valid = 1; | 454 | mtime_valid = 1; |
455 | if ((!mtime) || (mtime != ctl.head.mtime)) | 455 | if ((!mtime) || (mtime != ctl.head.mtime)) |
456 | goto init_cache; | 456 | goto init_cache; |
457 | } | 457 | } |
458 | 458 | ||
459 | if (filp->f_pos > ctl.head.end) | 459 | if (filp->f_pos > ctl.head.end) |
460 | goto finished; | 460 | goto finished; |
461 | 461 | ||
462 | ctl.fpos = filp->f_pos + (NCP_DIRCACHE_START - 2); | 462 | ctl.fpos = filp->f_pos + (NCP_DIRCACHE_START - 2); |
463 | ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE; | 463 | ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE; |
464 | ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE; | 464 | ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE; |
465 | 465 | ||
466 | for (;;) { | 466 | for (;;) { |
467 | if (ctl.ofs != 0) { | 467 | if (ctl.ofs != 0) { |
468 | ctl.page = find_lock_page(&inode->i_data, ctl.ofs); | 468 | ctl.page = find_lock_page(&inode->i_data, ctl.ofs); |
469 | if (!ctl.page) | 469 | if (!ctl.page) |
470 | goto invalid_cache; | 470 | goto invalid_cache; |
471 | ctl.cache = kmap(ctl.page); | 471 | ctl.cache = kmap(ctl.page); |
472 | if (!PageUptodate(ctl.page)) | 472 | if (!PageUptodate(ctl.page)) |
473 | goto invalid_cache; | 473 | goto invalid_cache; |
474 | } | 474 | } |
475 | while (ctl.idx < NCP_DIRCACHE_SIZE) { | 475 | while (ctl.idx < NCP_DIRCACHE_SIZE) { |
476 | struct dentry *dent; | 476 | struct dentry *dent; |
477 | int res; | 477 | int res; |
478 | 478 | ||
479 | dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx], | 479 | dent = ncp_dget_fpos(ctl.cache->dentry[ctl.idx], |
480 | dentry, filp->f_pos); | 480 | dentry, filp->f_pos); |
481 | if (!dent) | 481 | if (!dent) |
482 | goto invalid_cache; | 482 | goto invalid_cache; |
483 | res = filldir(dirent, dent->d_name.name, | 483 | res = filldir(dirent, dent->d_name.name, |
484 | dent->d_name.len, filp->f_pos, | 484 | dent->d_name.len, filp->f_pos, |
485 | dent->d_inode->i_ino, DT_UNKNOWN); | 485 | dent->d_inode->i_ino, DT_UNKNOWN); |
486 | dput(dent); | 486 | dput(dent); |
487 | if (res) | 487 | if (res) |
488 | goto finished; | 488 | goto finished; |
489 | filp->f_pos += 1; | 489 | filp->f_pos += 1; |
490 | ctl.idx += 1; | 490 | ctl.idx += 1; |
491 | if (filp->f_pos > ctl.head.end) | 491 | if (filp->f_pos > ctl.head.end) |
492 | goto finished; | 492 | goto finished; |
493 | } | 493 | } |
494 | if (ctl.page) { | 494 | if (ctl.page) { |
495 | kunmap(ctl.page); | 495 | kunmap(ctl.page); |
496 | SetPageUptodate(ctl.page); | 496 | SetPageUptodate(ctl.page); |
497 | unlock_page(ctl.page); | 497 | unlock_page(ctl.page); |
498 | page_cache_release(ctl.page); | 498 | page_cache_release(ctl.page); |
499 | ctl.page = NULL; | 499 | ctl.page = NULL; |
500 | } | 500 | } |
501 | ctl.idx = 0; | 501 | ctl.idx = 0; |
502 | ctl.ofs += 1; | 502 | ctl.ofs += 1; |
503 | } | 503 | } |
504 | invalid_cache: | 504 | invalid_cache: |
505 | if (ctl.page) { | 505 | if (ctl.page) { |
506 | kunmap(ctl.page); | 506 | kunmap(ctl.page); |
507 | unlock_page(ctl.page); | 507 | unlock_page(ctl.page); |
508 | page_cache_release(ctl.page); | 508 | page_cache_release(ctl.page); |
509 | ctl.page = NULL; | 509 | ctl.page = NULL; |
510 | } | 510 | } |
511 | ctl.cache = cache; | 511 | ctl.cache = cache; |
512 | init_cache: | 512 | init_cache: |
513 | ncp_invalidate_dircache_entries(dentry); | 513 | ncp_invalidate_dircache_entries(dentry); |
514 | if (!mtime_valid) { | 514 | if (!mtime_valid) { |
515 | mtime = ncp_obtain_mtime(dentry); | 515 | mtime = ncp_obtain_mtime(dentry); |
516 | mtime_valid = 1; | 516 | mtime_valid = 1; |
517 | } | 517 | } |
518 | ctl.head.mtime = mtime; | 518 | ctl.head.mtime = mtime; |
519 | ctl.head.time = jiffies; | 519 | ctl.head.time = jiffies; |
520 | ctl.head.eof = 0; | 520 | ctl.head.eof = 0; |
521 | ctl.fpos = 2; | 521 | ctl.fpos = 2; |
522 | ctl.ofs = 0; | 522 | ctl.ofs = 0; |
523 | ctl.idx = NCP_DIRCACHE_START; | 523 | ctl.idx = NCP_DIRCACHE_START; |
524 | ctl.filled = 0; | 524 | ctl.filled = 0; |
525 | ctl.valid = 1; | 525 | ctl.valid = 1; |
526 | read_really: | 526 | read_really: |
527 | if (ncp_is_server_root(inode)) { | 527 | if (ncp_is_server_root(inode)) { |
528 | ncp_read_volume_list(filp, dirent, filldir, &ctl); | 528 | ncp_read_volume_list(filp, dirent, filldir, &ctl); |
529 | } else { | 529 | } else { |
530 | ncp_do_readdir(filp, dirent, filldir, &ctl); | 530 | ncp_do_readdir(filp, dirent, filldir, &ctl); |
531 | } | 531 | } |
532 | ctl.head.end = ctl.fpos - 1; | 532 | ctl.head.end = ctl.fpos - 1; |
533 | ctl.head.eof = ctl.valid; | 533 | ctl.head.eof = ctl.valid; |
534 | finished: | 534 | finished: |
535 | if (page) { | 535 | if (page) { |
536 | cache->head = ctl.head; | 536 | cache->head = ctl.head; |
537 | kunmap(page); | 537 | kunmap(page); |
538 | SetPageUptodate(page); | 538 | SetPageUptodate(page); |
539 | unlock_page(page); | 539 | unlock_page(page); |
540 | page_cache_release(page); | 540 | page_cache_release(page); |
541 | } | 541 | } |
542 | if (ctl.page) { | 542 | if (ctl.page) { |
543 | kunmap(ctl.page); | 543 | kunmap(ctl.page); |
544 | SetPageUptodate(ctl.page); | 544 | SetPageUptodate(ctl.page); |
545 | unlock_page(ctl.page); | 545 | unlock_page(ctl.page); |
546 | page_cache_release(ctl.page); | 546 | page_cache_release(ctl.page); |
547 | } | 547 | } |
548 | out: | 548 | out: |
549 | unlock_kernel(); | 549 | unlock_kernel(); |
550 | return result; | 550 | return result; |
551 | } | 551 | } |
552 | 552 | ||
553 | static int | 553 | static int |
554 | ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, | 554 | ncp_fill_cache(struct file *filp, void *dirent, filldir_t filldir, |
555 | struct ncp_cache_control *ctrl, struct ncp_entry_info *entry) | 555 | struct ncp_cache_control *ctrl, struct ncp_entry_info *entry) |
556 | { | 556 | { |
557 | struct dentry *newdent, *dentry = filp->f_dentry; | 557 | struct dentry *newdent, *dentry = filp->f_path.dentry; |
558 | struct inode *newino, *inode = dentry->d_inode; | 558 | struct inode *newino, *inode = dentry->d_inode; |
559 | struct ncp_cache_control ctl = *ctrl; | 559 | struct ncp_cache_control ctl = *ctrl; |
560 | struct qstr qname; | 560 | struct qstr qname; |
561 | int valid = 0; | 561 | int valid = 0; |
562 | int hashed = 0; | 562 | int hashed = 0; |
563 | ino_t ino = 0; | 563 | ino_t ino = 0; |
564 | __u8 __name[NCP_MAXPATHLEN + 1]; | 564 | __u8 __name[NCP_MAXPATHLEN + 1]; |
565 | 565 | ||
566 | qname.len = sizeof(__name); | 566 | qname.len = sizeof(__name); |
567 | if (ncp_vol2io(NCP_SERVER(inode), __name, &qname.len, | 567 | if (ncp_vol2io(NCP_SERVER(inode), __name, &qname.len, |
568 | entry->i.entryName, entry->i.nameLen, | 568 | entry->i.entryName, entry->i.nameLen, |
569 | !ncp_preserve_entry_case(inode, entry->i.NSCreator))) | 569 | !ncp_preserve_entry_case(inode, entry->i.NSCreator))) |
570 | return 1; /* I'm not sure */ | 570 | return 1; /* I'm not sure */ |
571 | 571 | ||
572 | qname.name = __name; | 572 | qname.name = __name; |
573 | qname.hash = full_name_hash(qname.name, qname.len); | 573 | qname.hash = full_name_hash(qname.name, qname.len); |
574 | 574 | ||
575 | if (dentry->d_op && dentry->d_op->d_hash) | 575 | if (dentry->d_op && dentry->d_op->d_hash) |
576 | if (dentry->d_op->d_hash(dentry, &qname) != 0) | 576 | if (dentry->d_op->d_hash(dentry, &qname) != 0) |
577 | goto end_advance; | 577 | goto end_advance; |
578 | 578 | ||
579 | newdent = d_lookup(dentry, &qname); | 579 | newdent = d_lookup(dentry, &qname); |
580 | 580 | ||
581 | if (!newdent) { | 581 | if (!newdent) { |
582 | newdent = d_alloc(dentry, &qname); | 582 | newdent = d_alloc(dentry, &qname); |
583 | if (!newdent) | 583 | if (!newdent) |
584 | goto end_advance; | 584 | goto end_advance; |
585 | } else { | 585 | } else { |
586 | hashed = 1; | 586 | hashed = 1; |
587 | memcpy((char *) newdent->d_name.name, qname.name, | 587 | memcpy((char *) newdent->d_name.name, qname.name, |
588 | newdent->d_name.len); | 588 | newdent->d_name.len); |
589 | } | 589 | } |
590 | 590 | ||
591 | if (!newdent->d_inode) { | 591 | if (!newdent->d_inode) { |
592 | entry->opened = 0; | 592 | entry->opened = 0; |
593 | entry->ino = iunique(inode->i_sb, 2); | 593 | entry->ino = iunique(inode->i_sb, 2); |
594 | newino = ncp_iget(inode->i_sb, entry); | 594 | newino = ncp_iget(inode->i_sb, entry); |
595 | if (newino) { | 595 | if (newino) { |
596 | newdent->d_op = &ncp_dentry_operations; | 596 | newdent->d_op = &ncp_dentry_operations; |
597 | d_instantiate(newdent, newino); | 597 | d_instantiate(newdent, newino); |
598 | if (!hashed) | 598 | if (!hashed) |
599 | d_rehash(newdent); | 599 | d_rehash(newdent); |
600 | } | 600 | } |
601 | } else | 601 | } else |
602 | ncp_update_inode2(newdent->d_inode, entry); | 602 | ncp_update_inode2(newdent->d_inode, entry); |
603 | 603 | ||
604 | if (newdent->d_inode) { | 604 | if (newdent->d_inode) { |
605 | ino = newdent->d_inode->i_ino; | 605 | ino = newdent->d_inode->i_ino; |
606 | newdent->d_fsdata = (void *) ctl.fpos; | 606 | newdent->d_fsdata = (void *) ctl.fpos; |
607 | ncp_new_dentry(newdent); | 607 | ncp_new_dentry(newdent); |
608 | } | 608 | } |
609 | 609 | ||
610 | if (ctl.idx >= NCP_DIRCACHE_SIZE) { | 610 | if (ctl.idx >= NCP_DIRCACHE_SIZE) { |
611 | if (ctl.page) { | 611 | if (ctl.page) { |
612 | kunmap(ctl.page); | 612 | kunmap(ctl.page); |
613 | SetPageUptodate(ctl.page); | 613 | SetPageUptodate(ctl.page); |
614 | unlock_page(ctl.page); | 614 | unlock_page(ctl.page); |
615 | page_cache_release(ctl.page); | 615 | page_cache_release(ctl.page); |
616 | } | 616 | } |
617 | ctl.cache = NULL; | 617 | ctl.cache = NULL; |
618 | ctl.idx -= NCP_DIRCACHE_SIZE; | 618 | ctl.idx -= NCP_DIRCACHE_SIZE; |
619 | ctl.ofs += 1; | 619 | ctl.ofs += 1; |
620 | ctl.page = grab_cache_page(&inode->i_data, ctl.ofs); | 620 | ctl.page = grab_cache_page(&inode->i_data, ctl.ofs); |
621 | if (ctl.page) | 621 | if (ctl.page) |
622 | ctl.cache = kmap(ctl.page); | 622 | ctl.cache = kmap(ctl.page); |
623 | } | 623 | } |
624 | if (ctl.cache) { | 624 | if (ctl.cache) { |
625 | ctl.cache->dentry[ctl.idx] = newdent; | 625 | ctl.cache->dentry[ctl.idx] = newdent; |
626 | valid = 1; | 626 | valid = 1; |
627 | } | 627 | } |
628 | dput(newdent); | 628 | dput(newdent); |
629 | end_advance: | 629 | end_advance: |
630 | if (!valid) | 630 | if (!valid) |
631 | ctl.valid = 0; | 631 | ctl.valid = 0; |
632 | if (!ctl.filled && (ctl.fpos == filp->f_pos)) { | 632 | if (!ctl.filled && (ctl.fpos == filp->f_pos)) { |
633 | if (!ino) | 633 | if (!ino) |
634 | ino = find_inode_number(dentry, &qname); | 634 | ino = find_inode_number(dentry, &qname); |
635 | if (!ino) | 635 | if (!ino) |
636 | ino = iunique(inode->i_sb, 2); | 636 | ino = iunique(inode->i_sb, 2); |
637 | ctl.filled = filldir(dirent, qname.name, qname.len, | 637 | ctl.filled = filldir(dirent, qname.name, qname.len, |
638 | filp->f_pos, ino, DT_UNKNOWN); | 638 | filp->f_pos, ino, DT_UNKNOWN); |
639 | if (!ctl.filled) | 639 | if (!ctl.filled) |
640 | filp->f_pos += 1; | 640 | filp->f_pos += 1; |
641 | } | 641 | } |
642 | ctl.fpos += 1; | 642 | ctl.fpos += 1; |
643 | ctl.idx += 1; | 643 | ctl.idx += 1; |
644 | *ctrl = ctl; | 644 | *ctrl = ctl; |
645 | return (ctl.valid || !ctl.filled); | 645 | return (ctl.valid || !ctl.filled); |
646 | } | 646 | } |
647 | 647 | ||
648 | static void | 648 | static void |
649 | ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir, | 649 | ncp_read_volume_list(struct file *filp, void *dirent, filldir_t filldir, |
650 | struct ncp_cache_control *ctl) | 650 | struct ncp_cache_control *ctl) |
651 | { | 651 | { |
652 | struct dentry *dentry = filp->f_dentry; | 652 | struct dentry *dentry = filp->f_path.dentry; |
653 | struct inode *inode = dentry->d_inode; | 653 | struct inode *inode = dentry->d_inode; |
654 | struct ncp_server *server = NCP_SERVER(inode); | 654 | struct ncp_server *server = NCP_SERVER(inode); |
655 | struct ncp_volume_info info; | 655 | struct ncp_volume_info info; |
656 | struct ncp_entry_info entry; | 656 | struct ncp_entry_info entry; |
657 | int i; | 657 | int i; |
658 | 658 | ||
659 | DPRINTK("ncp_read_volume_list: pos=%ld\n", | 659 | DPRINTK("ncp_read_volume_list: pos=%ld\n", |
660 | (unsigned long) filp->f_pos); | 660 | (unsigned long) filp->f_pos); |
661 | 661 | ||
662 | for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) { | 662 | for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) { |
663 | 663 | ||
664 | if (ncp_get_volume_info_with_number(server, i, &info) != 0) | 664 | if (ncp_get_volume_info_with_number(server, i, &info) != 0) |
665 | return; | 665 | return; |
666 | if (!strlen(info.volume_name)) | 666 | if (!strlen(info.volume_name)) |
667 | continue; | 667 | continue; |
668 | 668 | ||
669 | DPRINTK("ncp_read_volume_list: found vol: %s\n", | 669 | DPRINTK("ncp_read_volume_list: found vol: %s\n", |
670 | info.volume_name); | 670 | info.volume_name); |
671 | 671 | ||
672 | if (ncp_lookup_volume(server, info.volume_name, | 672 | if (ncp_lookup_volume(server, info.volume_name, |
673 | &entry.i)) { | 673 | &entry.i)) { |
674 | DPRINTK("ncpfs: could not lookup vol %s\n", | 674 | DPRINTK("ncpfs: could not lookup vol %s\n", |
675 | info.volume_name); | 675 | info.volume_name); |
676 | continue; | 676 | continue; |
677 | } | 677 | } |
678 | entry.volume = entry.i.volNumber; | 678 | entry.volume = entry.i.volNumber; |
679 | if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) | 679 | if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) |
680 | return; | 680 | return; |
681 | } | 681 | } |
682 | } | 682 | } |
683 | 683 | ||
684 | static void | 684 | static void |
685 | ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, | 685 | ncp_do_readdir(struct file *filp, void *dirent, filldir_t filldir, |
686 | struct ncp_cache_control *ctl) | 686 | struct ncp_cache_control *ctl) |
687 | { | 687 | { |
688 | struct dentry *dentry = filp->f_dentry; | 688 | struct dentry *dentry = filp->f_path.dentry; |
689 | struct inode *dir = dentry->d_inode; | 689 | struct inode *dir = dentry->d_inode; |
690 | struct ncp_server *server = NCP_SERVER(dir); | 690 | struct ncp_server *server = NCP_SERVER(dir); |
691 | struct nw_search_sequence seq; | 691 | struct nw_search_sequence seq; |
692 | struct ncp_entry_info entry; | 692 | struct ncp_entry_info entry; |
693 | int err; | 693 | int err; |
694 | void* buf; | 694 | void* buf; |
695 | int more; | 695 | int more; |
696 | size_t bufsize; | 696 | size_t bufsize; |
697 | 697 | ||
698 | DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n", | 698 | DPRINTK("ncp_do_readdir: %s/%s, fpos=%ld\n", |
699 | dentry->d_parent->d_name.name, dentry->d_name.name, | 699 | dentry->d_parent->d_name.name, dentry->d_name.name, |
700 | (unsigned long) filp->f_pos); | 700 | (unsigned long) filp->f_pos); |
701 | PPRINTK("ncp_do_readdir: init %s, volnum=%d, dirent=%u\n", | 701 | PPRINTK("ncp_do_readdir: init %s, volnum=%d, dirent=%u\n", |
702 | dentry->d_name.name, NCP_FINFO(dir)->volNumber, | 702 | dentry->d_name.name, NCP_FINFO(dir)->volNumber, |
703 | NCP_FINFO(dir)->dirEntNum); | 703 | NCP_FINFO(dir)->dirEntNum); |
704 | 704 | ||
705 | err = ncp_initialize_search(server, dir, &seq); | 705 | err = ncp_initialize_search(server, dir, &seq); |
706 | if (err) { | 706 | if (err) { |
707 | DPRINTK("ncp_do_readdir: init failed, err=%d\n", err); | 707 | DPRINTK("ncp_do_readdir: init failed, err=%d\n", err); |
708 | return; | 708 | return; |
709 | } | 709 | } |
710 | /* We MUST NOT use server->buffer_size handshaked with server if we are | 710 | /* We MUST NOT use server->buffer_size handshaked with server if we are |
711 | using UDP, as for UDP server uses max. buffer size determined by | 711 | using UDP, as for UDP server uses max. buffer size determined by |
712 | MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes). | 712 | MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes). |
713 | So we use 128KB, just to be sure, as there is no way how to know | 713 | So we use 128KB, just to be sure, as there is no way how to know |
714 | this value in advance. */ | 714 | this value in advance. */ |
715 | bufsize = 131072; | 715 | bufsize = 131072; |
716 | buf = vmalloc(bufsize); | 716 | buf = vmalloc(bufsize); |
717 | if (!buf) | 717 | if (!buf) |
718 | return; | 718 | return; |
719 | do { | 719 | do { |
720 | int cnt; | 720 | int cnt; |
721 | char* rpl; | 721 | char* rpl; |
722 | size_t rpls; | 722 | size_t rpls; |
723 | 723 | ||
724 | err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls); | 724 | err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls); |
725 | if (err) /* Error */ | 725 | if (err) /* Error */ |
726 | break; | 726 | break; |
727 | if (!cnt) /* prevent endless loop */ | 727 | if (!cnt) /* prevent endless loop */ |
728 | break; | 728 | break; |
729 | while (cnt--) { | 729 | while (cnt--) { |
730 | size_t onerpl; | 730 | size_t onerpl; |
731 | 731 | ||
732 | if (rpls < offsetof(struct nw_info_struct, entryName)) | 732 | if (rpls < offsetof(struct nw_info_struct, entryName)) |
733 | break; /* short packet */ | 733 | break; /* short packet */ |
734 | ncp_extract_file_info(rpl, &entry.i); | 734 | ncp_extract_file_info(rpl, &entry.i); |
735 | onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen; | 735 | onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen; |
736 | if (rpls < onerpl) | 736 | if (rpls < onerpl) |
737 | break; /* short packet */ | 737 | break; /* short packet */ |
738 | (void)ncp_obtain_nfs_info(server, &entry.i); | 738 | (void)ncp_obtain_nfs_info(server, &entry.i); |
739 | rpl += onerpl; | 739 | rpl += onerpl; |
740 | rpls -= onerpl; | 740 | rpls -= onerpl; |
741 | entry.volume = entry.i.volNumber; | 741 | entry.volume = entry.i.volNumber; |
742 | if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) | 742 | if (!ncp_fill_cache(filp, dirent, filldir, ctl, &entry)) |
743 | break; | 743 | break; |
744 | } | 744 | } |
745 | } while (more); | 745 | } while (more); |
746 | vfree(buf); | 746 | vfree(buf); |
747 | return; | 747 | return; |
748 | } | 748 | } |
749 | 749 | ||
750 | int ncp_conn_logged_in(struct super_block *sb) | 750 | int ncp_conn_logged_in(struct super_block *sb) |
751 | { | 751 | { |
752 | struct ncp_server* server = NCP_SBP(sb); | 752 | struct ncp_server* server = NCP_SBP(sb); |
753 | int result; | 753 | int result; |
754 | 754 | ||
755 | if (ncp_single_volume(server)) { | 755 | if (ncp_single_volume(server)) { |
756 | int len; | 756 | int len; |
757 | struct dentry* dent; | 757 | struct dentry* dent; |
758 | __u32 volNumber; | 758 | __u32 volNumber; |
759 | __le32 dirEntNum; | 759 | __le32 dirEntNum; |
760 | __le32 DosDirNum; | 760 | __le32 DosDirNum; |
761 | __u8 __name[NCP_MAXPATHLEN + 1]; | 761 | __u8 __name[NCP_MAXPATHLEN + 1]; |
762 | 762 | ||
763 | len = sizeof(__name); | 763 | len = sizeof(__name); |
764 | result = ncp_io2vol(server, __name, &len, server->m.mounted_vol, | 764 | result = ncp_io2vol(server, __name, &len, server->m.mounted_vol, |
765 | strlen(server->m.mounted_vol), 1); | 765 | strlen(server->m.mounted_vol), 1); |
766 | if (result) | 766 | if (result) |
767 | goto out; | 767 | goto out; |
768 | result = -ENOENT; | 768 | result = -ENOENT; |
769 | if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) { | 769 | if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) { |
770 | PPRINTK("ncp_conn_logged_in: %s not found\n", | 770 | PPRINTK("ncp_conn_logged_in: %s not found\n", |
771 | server->m.mounted_vol); | 771 | server->m.mounted_vol); |
772 | goto out; | 772 | goto out; |
773 | } | 773 | } |
774 | dent = sb->s_root; | 774 | dent = sb->s_root; |
775 | if (dent) { | 775 | if (dent) { |
776 | struct inode* ino = dent->d_inode; | 776 | struct inode* ino = dent->d_inode; |
777 | if (ino) { | 777 | if (ino) { |
778 | NCP_FINFO(ino)->volNumber = volNumber; | 778 | NCP_FINFO(ino)->volNumber = volNumber; |
779 | NCP_FINFO(ino)->dirEntNum = dirEntNum; | 779 | NCP_FINFO(ino)->dirEntNum = dirEntNum; |
780 | NCP_FINFO(ino)->DosDirNum = DosDirNum; | 780 | NCP_FINFO(ino)->DosDirNum = DosDirNum; |
781 | } else { | 781 | } else { |
782 | DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n"); | 782 | DPRINTK("ncpfs: sb->s_root->d_inode == NULL!\n"); |
783 | } | 783 | } |
784 | } else { | 784 | } else { |
785 | DPRINTK("ncpfs: sb->s_root == NULL!\n"); | 785 | DPRINTK("ncpfs: sb->s_root == NULL!\n"); |
786 | } | 786 | } |
787 | } | 787 | } |
788 | result = 0; | 788 | result = 0; |
789 | 789 | ||
790 | out: | 790 | out: |
791 | return result; | 791 | return result; |
792 | } | 792 | } |
793 | 793 | ||
794 | static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) | 794 | static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, struct nameidata *nd) |
795 | { | 795 | { |
796 | struct ncp_server *server = NCP_SERVER(dir); | 796 | struct ncp_server *server = NCP_SERVER(dir); |
797 | struct inode *inode = NULL; | 797 | struct inode *inode = NULL; |
798 | struct ncp_entry_info finfo; | 798 | struct ncp_entry_info finfo; |
799 | int error, res, len; | 799 | int error, res, len; |
800 | __u8 __name[NCP_MAXPATHLEN + 1]; | 800 | __u8 __name[NCP_MAXPATHLEN + 1]; |
801 | 801 | ||
802 | lock_kernel(); | 802 | lock_kernel(); |
803 | error = -EIO; | 803 | error = -EIO; |
804 | if (!ncp_conn_valid(server)) | 804 | if (!ncp_conn_valid(server)) |
805 | goto finished; | 805 | goto finished; |
806 | 806 | ||
807 | PPRINTK("ncp_lookup: server lookup for %s/%s\n", | 807 | PPRINTK("ncp_lookup: server lookup for %s/%s\n", |
808 | dentry->d_parent->d_name.name, dentry->d_name.name); | 808 | dentry->d_parent->d_name.name, dentry->d_name.name); |
809 | 809 | ||
810 | len = sizeof(__name); | 810 | len = sizeof(__name); |
811 | if (ncp_is_server_root(dir)) { | 811 | if (ncp_is_server_root(dir)) { |
812 | res = ncp_io2vol(server, __name, &len, dentry->d_name.name, | 812 | res = ncp_io2vol(server, __name, &len, dentry->d_name.name, |
813 | dentry->d_name.len, 1); | 813 | dentry->d_name.len, 1); |
814 | if (!res) | 814 | if (!res) |
815 | res = ncp_lookup_volume(server, __name, &(finfo.i)); | 815 | res = ncp_lookup_volume(server, __name, &(finfo.i)); |
816 | } else { | 816 | } else { |
817 | res = ncp_io2vol(server, __name, &len, dentry->d_name.name, | 817 | res = ncp_io2vol(server, __name, &len, dentry->d_name.name, |
818 | dentry->d_name.len, !ncp_preserve_case(dir)); | 818 | dentry->d_name.len, !ncp_preserve_case(dir)); |
819 | if (!res) | 819 | if (!res) |
820 | res = ncp_obtain_info(server, dir, __name, &(finfo.i)); | 820 | res = ncp_obtain_info(server, dir, __name, &(finfo.i)); |
821 | } | 821 | } |
822 | PPRINTK("ncp_lookup: looked for %s/%s, res=%d\n", | 822 | PPRINTK("ncp_lookup: looked for %s/%s, res=%d\n", |
823 | dentry->d_parent->d_name.name, __name, res); | 823 | dentry->d_parent->d_name.name, __name, res); |
824 | /* | 824 | /* |
825 | * If we didn't find an entry, make a negative dentry. | 825 | * If we didn't find an entry, make a negative dentry. |
826 | */ | 826 | */ |
827 | if (res) | 827 | if (res) |
828 | goto add_entry; | 828 | goto add_entry; |
829 | 829 | ||
830 | /* | 830 | /* |
831 | * Create an inode for the entry. | 831 | * Create an inode for the entry. |
832 | */ | 832 | */ |
833 | finfo.opened = 0; | 833 | finfo.opened = 0; |
834 | finfo.ino = iunique(dir->i_sb, 2); | 834 | finfo.ino = iunique(dir->i_sb, 2); |
835 | finfo.volume = finfo.i.volNumber; | 835 | finfo.volume = finfo.i.volNumber; |
836 | error = -EACCES; | 836 | error = -EACCES; |
837 | inode = ncp_iget(dir->i_sb, &finfo); | 837 | inode = ncp_iget(dir->i_sb, &finfo); |
838 | 838 | ||
839 | if (inode) { | 839 | if (inode) { |
840 | ncp_new_dentry(dentry); | 840 | ncp_new_dentry(dentry); |
841 | add_entry: | 841 | add_entry: |
842 | dentry->d_op = &ncp_dentry_operations; | 842 | dentry->d_op = &ncp_dentry_operations; |
843 | d_add(dentry, inode); | 843 | d_add(dentry, inode); |
844 | error = 0; | 844 | error = 0; |
845 | } | 845 | } |
846 | 846 | ||
847 | finished: | 847 | finished: |
848 | PPRINTK("ncp_lookup: result=%d\n", error); | 848 | PPRINTK("ncp_lookup: result=%d\n", error); |
849 | unlock_kernel(); | 849 | unlock_kernel(); |
850 | return ERR_PTR(error); | 850 | return ERR_PTR(error); |
851 | } | 851 | } |
852 | 852 | ||
853 | /* | 853 | /* |
854 | * This code is common to create, mkdir, and mknod. | 854 | * This code is common to create, mkdir, and mknod. |
855 | */ | 855 | */ |
856 | static int ncp_instantiate(struct inode *dir, struct dentry *dentry, | 856 | static int ncp_instantiate(struct inode *dir, struct dentry *dentry, |
857 | struct ncp_entry_info *finfo) | 857 | struct ncp_entry_info *finfo) |
858 | { | 858 | { |
859 | struct inode *inode; | 859 | struct inode *inode; |
860 | int error = -EINVAL; | 860 | int error = -EINVAL; |
861 | 861 | ||
862 | finfo->ino = iunique(dir->i_sb, 2); | 862 | finfo->ino = iunique(dir->i_sb, 2); |
863 | inode = ncp_iget(dir->i_sb, finfo); | 863 | inode = ncp_iget(dir->i_sb, finfo); |
864 | if (!inode) | 864 | if (!inode) |
865 | goto out_close; | 865 | goto out_close; |
866 | d_instantiate(dentry,inode); | 866 | d_instantiate(dentry,inode); |
867 | error = 0; | 867 | error = 0; |
868 | out: | 868 | out: |
869 | return error; | 869 | return error; |
870 | 870 | ||
871 | out_close: | 871 | out_close: |
872 | PPRINTK("ncp_instantiate: %s/%s failed, closing file\n", | 872 | PPRINTK("ncp_instantiate: %s/%s failed, closing file\n", |
873 | dentry->d_parent->d_name.name, dentry->d_name.name); | 873 | dentry->d_parent->d_name.name, dentry->d_name.name); |
874 | ncp_close_file(NCP_SERVER(dir), finfo->file_handle); | 874 | ncp_close_file(NCP_SERVER(dir), finfo->file_handle); |
875 | goto out; | 875 | goto out; |
876 | } | 876 | } |
877 | 877 | ||
878 | int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, | 878 | int ncp_create_new(struct inode *dir, struct dentry *dentry, int mode, |
879 | dev_t rdev, __le32 attributes) | 879 | dev_t rdev, __le32 attributes) |
880 | { | 880 | { |
881 | struct ncp_server *server = NCP_SERVER(dir); | 881 | struct ncp_server *server = NCP_SERVER(dir); |
882 | struct ncp_entry_info finfo; | 882 | struct ncp_entry_info finfo; |
883 | int error, result, len; | 883 | int error, result, len; |
884 | int opmode; | 884 | int opmode; |
885 | __u8 __name[NCP_MAXPATHLEN + 1]; | 885 | __u8 __name[NCP_MAXPATHLEN + 1]; |
886 | 886 | ||
887 | PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n", | 887 | PPRINTK("ncp_create_new: creating %s/%s, mode=%x\n", |
888 | dentry->d_parent->d_name.name, dentry->d_name.name, mode); | 888 | dentry->d_parent->d_name.name, dentry->d_name.name, mode); |
889 | 889 | ||
890 | error = -EIO; | 890 | error = -EIO; |
891 | lock_kernel(); | 891 | lock_kernel(); |
892 | if (!ncp_conn_valid(server)) | 892 | if (!ncp_conn_valid(server)) |
893 | goto out; | 893 | goto out; |
894 | 894 | ||
895 | ncp_age_dentry(server, dentry); | 895 | ncp_age_dentry(server, dentry); |
896 | len = sizeof(__name); | 896 | len = sizeof(__name); |
897 | error = ncp_io2vol(server, __name, &len, dentry->d_name.name, | 897 | error = ncp_io2vol(server, __name, &len, dentry->d_name.name, |
898 | dentry->d_name.len, !ncp_preserve_case(dir)); | 898 | dentry->d_name.len, !ncp_preserve_case(dir)); |
899 | if (error) | 899 | if (error) |
900 | goto out; | 900 | goto out; |
901 | 901 | ||
902 | error = -EACCES; | 902 | error = -EACCES; |
903 | 903 | ||
904 | if (S_ISREG(mode) && | 904 | if (S_ISREG(mode) && |
905 | (server->m.flags & NCP_MOUNT_EXTRAS) && | 905 | (server->m.flags & NCP_MOUNT_EXTRAS) && |
906 | (mode & S_IXUGO)) | 906 | (mode & S_IXUGO)) |
907 | attributes |= aSYSTEM | aSHARED; | 907 | attributes |= aSYSTEM | aSHARED; |
908 | 908 | ||
909 | result = ncp_open_create_file_or_subdir(server, dir, __name, | 909 | result = ncp_open_create_file_or_subdir(server, dir, __name, |
910 | OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE, | 910 | OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE, |
911 | attributes, AR_READ | AR_WRITE, &finfo); | 911 | attributes, AR_READ | AR_WRITE, &finfo); |
912 | opmode = O_RDWR; | 912 | opmode = O_RDWR; |
913 | if (result) { | 913 | if (result) { |
914 | result = ncp_open_create_file_or_subdir(server, dir, __name, | 914 | result = ncp_open_create_file_or_subdir(server, dir, __name, |
915 | OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE, | 915 | OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE, |
916 | attributes, AR_WRITE, &finfo); | 916 | attributes, AR_WRITE, &finfo); |
917 | if (result) { | 917 | if (result) { |
918 | if (result == 0x87) | 918 | if (result == 0x87) |
919 | error = -ENAMETOOLONG; | 919 | error = -ENAMETOOLONG; |
920 | DPRINTK("ncp_create: %s/%s failed\n", | 920 | DPRINTK("ncp_create: %s/%s failed\n", |
921 | dentry->d_parent->d_name.name, dentry->d_name.name); | 921 | dentry->d_parent->d_name.name, dentry->d_name.name); |
922 | goto out; | 922 | goto out; |
923 | } | 923 | } |
924 | opmode = O_WRONLY; | 924 | opmode = O_WRONLY; |
925 | } | 925 | } |
926 | finfo.access = opmode; | 926 | finfo.access = opmode; |
927 | if (ncp_is_nfs_extras(server, finfo.volume)) { | 927 | if (ncp_is_nfs_extras(server, finfo.volume)) { |
928 | finfo.i.nfs.mode = mode; | 928 | finfo.i.nfs.mode = mode; |
929 | finfo.i.nfs.rdev = new_encode_dev(rdev); | 929 | finfo.i.nfs.rdev = new_encode_dev(rdev); |
930 | if (ncp_modify_nfs_info(server, finfo.volume, | 930 | if (ncp_modify_nfs_info(server, finfo.volume, |
931 | finfo.i.dirEntNum, | 931 | finfo.i.dirEntNum, |
932 | mode, new_encode_dev(rdev)) != 0) | 932 | mode, new_encode_dev(rdev)) != 0) |
933 | goto out; | 933 | goto out; |
934 | } | 934 | } |
935 | 935 | ||
936 | error = ncp_instantiate(dir, dentry, &finfo); | 936 | error = ncp_instantiate(dir, dentry, &finfo); |
937 | out: | 937 | out: |
938 | unlock_kernel(); | 938 | unlock_kernel(); |
939 | return error; | 939 | return error; |
940 | } | 940 | } |
941 | 941 | ||
942 | static int ncp_create(struct inode *dir, struct dentry *dentry, int mode, | 942 | static int ncp_create(struct inode *dir, struct dentry *dentry, int mode, |
943 | struct nameidata *nd) | 943 | struct nameidata *nd) |
944 | { | 944 | { |
945 | return ncp_create_new(dir, dentry, mode, 0, 0); | 945 | return ncp_create_new(dir, dentry, mode, 0, 0); |
946 | } | 946 | } |
947 | 947 | ||
948 | static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode) | 948 | static int ncp_mkdir(struct inode *dir, struct dentry *dentry, int mode) |
949 | { | 949 | { |
950 | struct ncp_entry_info finfo; | 950 | struct ncp_entry_info finfo; |
951 | struct ncp_server *server = NCP_SERVER(dir); | 951 | struct ncp_server *server = NCP_SERVER(dir); |
952 | int error, len; | 952 | int error, len; |
953 | __u8 __name[NCP_MAXPATHLEN + 1]; | 953 | __u8 __name[NCP_MAXPATHLEN + 1]; |
954 | 954 | ||
955 | DPRINTK("ncp_mkdir: making %s/%s\n", | 955 | DPRINTK("ncp_mkdir: making %s/%s\n", |
956 | dentry->d_parent->d_name.name, dentry->d_name.name); | 956 | dentry->d_parent->d_name.name, dentry->d_name.name); |
957 | 957 | ||
958 | error = -EIO; | 958 | error = -EIO; |
959 | lock_kernel(); | 959 | lock_kernel(); |
960 | if (!ncp_conn_valid(server)) | 960 | if (!ncp_conn_valid(server)) |
961 | goto out; | 961 | goto out; |
962 | 962 | ||
963 | ncp_age_dentry(server, dentry); | 963 | ncp_age_dentry(server, dentry); |
964 | len = sizeof(__name); | 964 | len = sizeof(__name); |
965 | error = ncp_io2vol(server, __name, &len, dentry->d_name.name, | 965 | error = ncp_io2vol(server, __name, &len, dentry->d_name.name, |
966 | dentry->d_name.len, !ncp_preserve_case(dir)); | 966 | dentry->d_name.len, !ncp_preserve_case(dir)); |
967 | if (error) | 967 | if (error) |
968 | goto out; | 968 | goto out; |
969 | 969 | ||
970 | error = -EACCES; | 970 | error = -EACCES; |
971 | if (ncp_open_create_file_or_subdir(server, dir, __name, | 971 | if (ncp_open_create_file_or_subdir(server, dir, __name, |
972 | OC_MODE_CREATE, aDIR, | 972 | OC_MODE_CREATE, aDIR, |
973 | cpu_to_le16(0xffff), | 973 | cpu_to_le16(0xffff), |
974 | &finfo) == 0) | 974 | &finfo) == 0) |
975 | { | 975 | { |
976 | if (ncp_is_nfs_extras(server, finfo.volume)) { | 976 | if (ncp_is_nfs_extras(server, finfo.volume)) { |
977 | mode |= S_IFDIR; | 977 | mode |= S_IFDIR; |
978 | finfo.i.nfs.mode = mode; | 978 | finfo.i.nfs.mode = mode; |
979 | if (ncp_modify_nfs_info(server, | 979 | if (ncp_modify_nfs_info(server, |
980 | finfo.volume, | 980 | finfo.volume, |
981 | finfo.i.dirEntNum, | 981 | finfo.i.dirEntNum, |
982 | mode, 0) != 0) | 982 | mode, 0) != 0) |
983 | goto out; | 983 | goto out; |
984 | } | 984 | } |
985 | error = ncp_instantiate(dir, dentry, &finfo); | 985 | error = ncp_instantiate(dir, dentry, &finfo); |
986 | } | 986 | } |
987 | out: | 987 | out: |
988 | unlock_kernel(); | 988 | unlock_kernel(); |
989 | return error; | 989 | return error; |
990 | } | 990 | } |
991 | 991 | ||
992 | static int ncp_rmdir(struct inode *dir, struct dentry *dentry) | 992 | static int ncp_rmdir(struct inode *dir, struct dentry *dentry) |
993 | { | 993 | { |
994 | struct ncp_server *server = NCP_SERVER(dir); | 994 | struct ncp_server *server = NCP_SERVER(dir); |
995 | int error, result, len; | 995 | int error, result, len; |
996 | __u8 __name[NCP_MAXPATHLEN + 1]; | 996 | __u8 __name[NCP_MAXPATHLEN + 1]; |
997 | 997 | ||
998 | DPRINTK("ncp_rmdir: removing %s/%s\n", | 998 | DPRINTK("ncp_rmdir: removing %s/%s\n", |
999 | dentry->d_parent->d_name.name, dentry->d_name.name); | 999 | dentry->d_parent->d_name.name, dentry->d_name.name); |
1000 | 1000 | ||
1001 | error = -EIO; | 1001 | error = -EIO; |
1002 | lock_kernel(); | 1002 | lock_kernel(); |
1003 | if (!ncp_conn_valid(server)) | 1003 | if (!ncp_conn_valid(server)) |
1004 | goto out; | 1004 | goto out; |
1005 | 1005 | ||
1006 | error = -EBUSY; | 1006 | error = -EBUSY; |
1007 | if (!d_unhashed(dentry)) | 1007 | if (!d_unhashed(dentry)) |
1008 | goto out; | 1008 | goto out; |
1009 | 1009 | ||
1010 | len = sizeof(__name); | 1010 | len = sizeof(__name); |
1011 | error = ncp_io2vol(server, __name, &len, dentry->d_name.name, | 1011 | error = ncp_io2vol(server, __name, &len, dentry->d_name.name, |
1012 | dentry->d_name.len, !ncp_preserve_case(dir)); | 1012 | dentry->d_name.len, !ncp_preserve_case(dir)); |
1013 | if (error) | 1013 | if (error) |
1014 | goto out; | 1014 | goto out; |
1015 | 1015 | ||
1016 | result = ncp_del_file_or_subdir(server, dir, __name); | 1016 | result = ncp_del_file_or_subdir(server, dir, __name); |
1017 | switch (result) { | 1017 | switch (result) { |
1018 | case 0x00: | 1018 | case 0x00: |
1019 | error = 0; | 1019 | error = 0; |
1020 | break; | 1020 | break; |
1021 | case 0x85: /* unauthorized to delete file */ | 1021 | case 0x85: /* unauthorized to delete file */ |
1022 | case 0x8A: /* unauthorized to delete file */ | 1022 | case 0x8A: /* unauthorized to delete file */ |
1023 | error = -EACCES; | 1023 | error = -EACCES; |
1024 | break; | 1024 | break; |
1025 | case 0x8F: | 1025 | case 0x8F: |
1026 | case 0x90: /* read only */ | 1026 | case 0x90: /* read only */ |
1027 | error = -EPERM; | 1027 | error = -EPERM; |
1028 | break; | 1028 | break; |
1029 | case 0x9F: /* in use by another client */ | 1029 | case 0x9F: /* in use by another client */ |
1030 | error = -EBUSY; | 1030 | error = -EBUSY; |
1031 | break; | 1031 | break; |
1032 | case 0xA0: /* directory not empty */ | 1032 | case 0xA0: /* directory not empty */ |
1033 | error = -ENOTEMPTY; | 1033 | error = -ENOTEMPTY; |
1034 | break; | 1034 | break; |
1035 | case 0xFF: /* someone deleted file */ | 1035 | case 0xFF: /* someone deleted file */ |
1036 | error = -ENOENT; | 1036 | error = -ENOENT; |
1037 | break; | 1037 | break; |
1038 | default: | 1038 | default: |
1039 | error = -EACCES; | 1039 | error = -EACCES; |
1040 | break; | 1040 | break; |
1041 | } | 1041 | } |
1042 | out: | 1042 | out: |
1043 | unlock_kernel(); | 1043 | unlock_kernel(); |
1044 | return error; | 1044 | return error; |
1045 | } | 1045 | } |
1046 | 1046 | ||
1047 | static int ncp_unlink(struct inode *dir, struct dentry *dentry) | 1047 | static int ncp_unlink(struct inode *dir, struct dentry *dentry) |
1048 | { | 1048 | { |
1049 | struct inode *inode = dentry->d_inode; | 1049 | struct inode *inode = dentry->d_inode; |
1050 | struct ncp_server *server; | 1050 | struct ncp_server *server; |
1051 | int error; | 1051 | int error; |
1052 | 1052 | ||
1053 | lock_kernel(); | 1053 | lock_kernel(); |
1054 | server = NCP_SERVER(dir); | 1054 | server = NCP_SERVER(dir); |
1055 | DPRINTK("ncp_unlink: unlinking %s/%s\n", | 1055 | DPRINTK("ncp_unlink: unlinking %s/%s\n", |
1056 | dentry->d_parent->d_name.name, dentry->d_name.name); | 1056 | dentry->d_parent->d_name.name, dentry->d_name.name); |
1057 | 1057 | ||
1058 | error = -EIO; | 1058 | error = -EIO; |
1059 | if (!ncp_conn_valid(server)) | 1059 | if (!ncp_conn_valid(server)) |
1060 | goto out; | 1060 | goto out; |
1061 | 1061 | ||
1062 | /* | 1062 | /* |
1063 | * Check whether to close the file ... | 1063 | * Check whether to close the file ... |
1064 | */ | 1064 | */ |
1065 | if (inode) { | 1065 | if (inode) { |
1066 | PPRINTK("ncp_unlink: closing file\n"); | 1066 | PPRINTK("ncp_unlink: closing file\n"); |
1067 | ncp_make_closed(inode); | 1067 | ncp_make_closed(inode); |
1068 | } | 1068 | } |
1069 | 1069 | ||
1070 | error = ncp_del_file_or_subdir2(server, dentry); | 1070 | error = ncp_del_file_or_subdir2(server, dentry); |
1071 | #ifdef CONFIG_NCPFS_STRONG | 1071 | #ifdef CONFIG_NCPFS_STRONG |
1072 | /* 9C is Invalid path.. It should be 8F, 90 - read only, but | 1072 | /* 9C is Invalid path.. It should be 8F, 90 - read only, but |
1073 | it is not :-( */ | 1073 | it is not :-( */ |
1074 | if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */ | 1074 | if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */ |
1075 | error = ncp_force_unlink(dir, dentry); | 1075 | error = ncp_force_unlink(dir, dentry); |
1076 | } | 1076 | } |
1077 | #endif | 1077 | #endif |
1078 | switch (error) { | 1078 | switch (error) { |
1079 | case 0x00: | 1079 | case 0x00: |
1080 | DPRINTK("ncp: removed %s/%s\n", | 1080 | DPRINTK("ncp: removed %s/%s\n", |
1081 | dentry->d_parent->d_name.name, dentry->d_name.name); | 1081 | dentry->d_parent->d_name.name, dentry->d_name.name); |
1082 | break; | 1082 | break; |
1083 | case 0x85: | 1083 | case 0x85: |
1084 | case 0x8A: | 1084 | case 0x8A: |
1085 | error = -EACCES; | 1085 | error = -EACCES; |
1086 | break; | 1086 | break; |
1087 | case 0x8D: /* some files in use */ | 1087 | case 0x8D: /* some files in use */ |
1088 | case 0x8E: /* all files in use */ | 1088 | case 0x8E: /* all files in use */ |
1089 | error = -EBUSY; | 1089 | error = -EBUSY; |
1090 | break; | 1090 | break; |
1091 | case 0x8F: /* some read only */ | 1091 | case 0x8F: /* some read only */ |
1092 | case 0x90: /* all read only */ | 1092 | case 0x90: /* all read only */ |
1093 | case 0x9C: /* !!! returned when in-use or read-only by NW4 */ | 1093 | case 0x9C: /* !!! returned when in-use or read-only by NW4 */ |
1094 | error = -EPERM; | 1094 | error = -EPERM; |
1095 | break; | 1095 | break; |
1096 | case 0xFF: | 1096 | case 0xFF: |
1097 | error = -ENOENT; | 1097 | error = -ENOENT; |
1098 | break; | 1098 | break; |
1099 | default: | 1099 | default: |
1100 | error = -EACCES; | 1100 | error = -EACCES; |
1101 | break; | 1101 | break; |
1102 | } | 1102 | } |
1103 | 1103 | ||
1104 | out: | 1104 | out: |
1105 | unlock_kernel(); | 1105 | unlock_kernel(); |
1106 | return error; | 1106 | return error; |
1107 | } | 1107 | } |
1108 | 1108 | ||
1109 | static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, | 1109 | static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry, |
1110 | struct inode *new_dir, struct dentry *new_dentry) | 1110 | struct inode *new_dir, struct dentry *new_dentry) |
1111 | { | 1111 | { |
1112 | struct ncp_server *server = NCP_SERVER(old_dir); | 1112 | struct ncp_server *server = NCP_SERVER(old_dir); |
1113 | int error; | 1113 | int error; |
1114 | int old_len, new_len; | 1114 | int old_len, new_len; |
1115 | __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1]; | 1115 | __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1]; |
1116 | 1116 | ||
1117 | DPRINTK("ncp_rename: %s/%s to %s/%s\n", | 1117 | DPRINTK("ncp_rename: %s/%s to %s/%s\n", |
1118 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, | 1118 | old_dentry->d_parent->d_name.name, old_dentry->d_name.name, |
1119 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name); | 1119 | new_dentry->d_parent->d_name.name, new_dentry->d_name.name); |
1120 | 1120 | ||
1121 | error = -EIO; | 1121 | error = -EIO; |
1122 | lock_kernel(); | 1122 | lock_kernel(); |
1123 | if (!ncp_conn_valid(server)) | 1123 | if (!ncp_conn_valid(server)) |
1124 | goto out; | 1124 | goto out; |
1125 | 1125 | ||
1126 | ncp_age_dentry(server, old_dentry); | 1126 | ncp_age_dentry(server, old_dentry); |
1127 | ncp_age_dentry(server, new_dentry); | 1127 | ncp_age_dentry(server, new_dentry); |
1128 | 1128 | ||
1129 | old_len = sizeof(__old_name); | 1129 | old_len = sizeof(__old_name); |
1130 | error = ncp_io2vol(server, __old_name, &old_len, | 1130 | error = ncp_io2vol(server, __old_name, &old_len, |
1131 | old_dentry->d_name.name, old_dentry->d_name.len, | 1131 | old_dentry->d_name.name, old_dentry->d_name.len, |
1132 | !ncp_preserve_case(old_dir)); | 1132 | !ncp_preserve_case(old_dir)); |
1133 | if (error) | 1133 | if (error) |
1134 | goto out; | 1134 | goto out; |
1135 | 1135 | ||
1136 | new_len = sizeof(__new_name); | 1136 | new_len = sizeof(__new_name); |
1137 | error = ncp_io2vol(server, __new_name, &new_len, | 1137 | error = ncp_io2vol(server, __new_name, &new_len, |
1138 | new_dentry->d_name.name, new_dentry->d_name.len, | 1138 | new_dentry->d_name.name, new_dentry->d_name.len, |
1139 | !ncp_preserve_case(new_dir)); | 1139 | !ncp_preserve_case(new_dir)); |
1140 | if (error) | 1140 | if (error) |
1141 | goto out; | 1141 | goto out; |
1142 | 1142 | ||
1143 | error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name, | 1143 | error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name, |
1144 | new_dir, __new_name); | 1144 | new_dir, __new_name); |
1145 | #ifdef CONFIG_NCPFS_STRONG | 1145 | #ifdef CONFIG_NCPFS_STRONG |
1146 | if ((error == 0x90 || error == 0x8B || error == -EACCES) && | 1146 | if ((error == 0x90 || error == 0x8B || error == -EACCES) && |
1147 | server->m.flags & NCP_MOUNT_STRONG) { /* RO */ | 1147 | server->m.flags & NCP_MOUNT_STRONG) { /* RO */ |
1148 | error = ncp_force_rename(old_dir, old_dentry, __old_name, | 1148 | error = ncp_force_rename(old_dir, old_dentry, __old_name, |
1149 | new_dir, new_dentry, __new_name); | 1149 | new_dir, new_dentry, __new_name); |
1150 | } | 1150 | } |
1151 | #endif | 1151 | #endif |
1152 | switch (error) { | 1152 | switch (error) { |
1153 | case 0x00: | 1153 | case 0x00: |
1154 | DPRINTK("ncp renamed %s -> %s.\n", | 1154 | DPRINTK("ncp renamed %s -> %s.\n", |
1155 | old_dentry->d_name.name,new_dentry->d_name.name); | 1155 | old_dentry->d_name.name,new_dentry->d_name.name); |
1156 | break; | 1156 | break; |
1157 | case 0x9E: | 1157 | case 0x9E: |
1158 | error = -ENAMETOOLONG; | 1158 | error = -ENAMETOOLONG; |
1159 | break; | 1159 | break; |
1160 | case 0xFF: | 1160 | case 0xFF: |
1161 | error = -ENOENT; | 1161 | error = -ENOENT; |
1162 | break; | 1162 | break; |
1163 | default: | 1163 | default: |
1164 | error = -EACCES; | 1164 | error = -EACCES; |
1165 | break; | 1165 | break; |
1166 | } | 1166 | } |
1167 | out: | 1167 | out: |
1168 | unlock_kernel(); | 1168 | unlock_kernel(); |
1169 | return error; | 1169 | return error; |
1170 | } | 1170 | } |
1171 | 1171 | ||
1172 | static int ncp_mknod(struct inode * dir, struct dentry *dentry, | 1172 | static int ncp_mknod(struct inode * dir, struct dentry *dentry, |
1173 | int mode, dev_t rdev) | 1173 | int mode, dev_t rdev) |
1174 | { | 1174 | { |
1175 | if (!new_valid_dev(rdev)) | 1175 | if (!new_valid_dev(rdev)) |
1176 | return -EINVAL; | 1176 | return -EINVAL; |
1177 | if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) { | 1177 | if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) { |
1178 | DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%o\n", mode); | 1178 | DPRINTK(KERN_DEBUG "ncp_mknod: mode = 0%o\n", mode); |
1179 | return ncp_create_new(dir, dentry, mode, rdev, 0); | 1179 | return ncp_create_new(dir, dentry, mode, rdev, 0); |
1180 | } | 1180 | } |
1181 | return -EPERM; /* Strange, but true */ | 1181 | return -EPERM; /* Strange, but true */ |
1182 | } | 1182 | } |
1183 | 1183 | ||
1184 | /* The following routines are taken directly from msdos-fs */ | 1184 | /* The following routines are taken directly from msdos-fs */ |
1185 | 1185 | ||
1186 | /* Linear day numbers of the respective 1sts in non-leap years. */ | 1186 | /* Linear day numbers of the respective 1sts in non-leap years. */ |
1187 | 1187 | ||
1188 | static int day_n[] = | 1188 | static int day_n[] = |
1189 | {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0}; | 1189 | {0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0}; |
1190 | /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ | 1190 | /* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */ |
1191 | 1191 | ||
1192 | 1192 | ||
1193 | extern struct timezone sys_tz; | 1193 | extern struct timezone sys_tz; |
1194 | 1194 | ||
1195 | static int utc2local(int time) | 1195 | static int utc2local(int time) |
1196 | { | 1196 | { |
1197 | return time - sys_tz.tz_minuteswest * 60; | 1197 | return time - sys_tz.tz_minuteswest * 60; |
1198 | } | 1198 | } |
1199 | 1199 | ||
1200 | static int local2utc(int time) | 1200 | static int local2utc(int time) |
1201 | { | 1201 | { |
1202 | return time + sys_tz.tz_minuteswest * 60; | 1202 | return time + sys_tz.tz_minuteswest * 60; |
1203 | } | 1203 | } |
1204 | 1204 | ||
1205 | /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ | 1205 | /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */ |
1206 | int | 1206 | int |
1207 | ncp_date_dos2unix(__le16 t, __le16 d) | 1207 | ncp_date_dos2unix(__le16 t, __le16 d) |
1208 | { | 1208 | { |
1209 | unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d); | 1209 | unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d); |
1210 | int month, year, secs; | 1210 | int month, year, secs; |
1211 | 1211 | ||
1212 | /* first subtract and mask after that... Otherwise, if | 1212 | /* first subtract and mask after that... Otherwise, if |
1213 | date == 0, bad things happen */ | 1213 | date == 0, bad things happen */ |
1214 | month = ((date >> 5) - 1) & 15; | 1214 | month = ((date >> 5) - 1) & 15; |
1215 | year = date >> 9; | 1215 | year = date >> 9; |
1216 | secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + | 1216 | secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 + |
1217 | 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) + | 1217 | 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) + |
1218 | year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653); | 1218 | year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653); |
1219 | /* days since 1.1.70 plus 80's leap day */ | 1219 | /* days since 1.1.70 plus 80's leap day */ |
1220 | return local2utc(secs); | 1220 | return local2utc(secs); |
1221 | } | 1221 | } |
1222 | 1222 | ||
1223 | 1223 | ||
1224 | /* Convert linear UNIX date to a MS-DOS time/date pair. */ | 1224 | /* Convert linear UNIX date to a MS-DOS time/date pair. */ |
1225 | void | 1225 | void |
1226 | ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date) | 1226 | ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date) |
1227 | { | 1227 | { |
1228 | int day, year, nl_day, month; | 1228 | int day, year, nl_day, month; |
1229 | 1229 | ||
1230 | unix_date = utc2local(unix_date); | 1230 | unix_date = utc2local(unix_date); |
1231 | *time = cpu_to_le16( | 1231 | *time = cpu_to_le16( |
1232 | (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) + | 1232 | (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) + |
1233 | (((unix_date / 3600) % 24) << 11)); | 1233 | (((unix_date / 3600) % 24) << 11)); |
1234 | day = unix_date / 86400 - 3652; | 1234 | day = unix_date / 86400 - 3652; |
1235 | year = day / 365; | 1235 | year = day / 365; |
1236 | if ((year + 3) / 4 + 365 * year > day) | 1236 | if ((year + 3) / 4 + 365 * year > day) |
1237 | year--; | 1237 | year--; |
1238 | day -= (year + 3) / 4 + 365 * year; | 1238 | day -= (year + 3) / 4 + 365 * year; |
1239 | if (day == 59 && !(year & 3)) { | 1239 | if (day == 59 && !(year & 3)) { |
1240 | nl_day = day; | 1240 | nl_day = day; |
1241 | month = 2; | 1241 | month = 2; |
1242 | } else { | 1242 | } else { |
1243 | nl_day = (year & 3) || day <= 59 ? day : day - 1; | 1243 | nl_day = (year & 3) || day <= 59 ? day : day - 1; |
1244 | for (month = 0; month < 12; month++) | 1244 | for (month = 0; month < 12; month++) |
1245 | if (day_n[month] > nl_day) | 1245 | if (day_n[month] > nl_day) |
1246 | break; | 1246 | break; |
1247 | } | 1247 | } |
1248 | *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9)); | 1248 | *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9)); |
1249 | } | 1249 | } |
1250 | 1250 |
fs/ncpfs/file.c
1 | /* | 1 | /* |
2 | * file.c | 2 | * file.c |
3 | * | 3 | * |
4 | * Copyright (C) 1995, 1996 by Volker Lendecke | 4 | * Copyright (C) 1995, 1996 by Volker Lendecke |
5 | * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache | 5 | * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache |
6 | * | 6 | * |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <asm/uaccess.h> | 9 | #include <asm/uaccess.h> |
10 | #include <asm/system.h> | 10 | #include <asm/system.h> |
11 | 11 | ||
12 | #include <linux/time.h> | 12 | #include <linux/time.h> |
13 | #include <linux/kernel.h> | 13 | #include <linux/kernel.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/fcntl.h> | 15 | #include <linux/fcntl.h> |
16 | #include <linux/stat.h> | 16 | #include <linux/stat.h> |
17 | #include <linux/mm.h> | 17 | #include <linux/mm.h> |
18 | #include <linux/slab.h> | 18 | #include <linux/slab.h> |
19 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
20 | #include <linux/smp_lock.h> | 20 | #include <linux/smp_lock.h> |
21 | 21 | ||
22 | #include <linux/ncp_fs.h> | 22 | #include <linux/ncp_fs.h> |
23 | #include "ncplib_kernel.h" | 23 | #include "ncplib_kernel.h" |
24 | 24 | ||
25 | static int ncp_fsync(struct file *file, struct dentry *dentry, int datasync) | 25 | static int ncp_fsync(struct file *file, struct dentry *dentry, int datasync) |
26 | { | 26 | { |
27 | return 0; | 27 | return 0; |
28 | } | 28 | } |
29 | 29 | ||
30 | /* | 30 | /* |
31 | * Open a file with the specified read/write mode. | 31 | * Open a file with the specified read/write mode. |
32 | */ | 32 | */ |
33 | int ncp_make_open(struct inode *inode, int right) | 33 | int ncp_make_open(struct inode *inode, int right) |
34 | { | 34 | { |
35 | int error; | 35 | int error; |
36 | int access; | 36 | int access; |
37 | 37 | ||
38 | error = -EINVAL; | 38 | error = -EINVAL; |
39 | if (!inode) { | 39 | if (!inode) { |
40 | printk(KERN_ERR "ncp_make_open: got NULL inode\n"); | 40 | printk(KERN_ERR "ncp_make_open: got NULL inode\n"); |
41 | goto out; | 41 | goto out; |
42 | } | 42 | } |
43 | 43 | ||
44 | DPRINTK("ncp_make_open: opened=%d, volume # %u, dir entry # %u\n", | 44 | DPRINTK("ncp_make_open: opened=%d, volume # %u, dir entry # %u\n", |
45 | atomic_read(&NCP_FINFO(inode)->opened), | 45 | atomic_read(&NCP_FINFO(inode)->opened), |
46 | NCP_FINFO(inode)->volNumber, | 46 | NCP_FINFO(inode)->volNumber, |
47 | NCP_FINFO(inode)->dirEntNum); | 47 | NCP_FINFO(inode)->dirEntNum); |
48 | error = -EACCES; | 48 | error = -EACCES; |
49 | mutex_lock(&NCP_FINFO(inode)->open_mutex); | 49 | mutex_lock(&NCP_FINFO(inode)->open_mutex); |
50 | if (!atomic_read(&NCP_FINFO(inode)->opened)) { | 50 | if (!atomic_read(&NCP_FINFO(inode)->opened)) { |
51 | struct ncp_entry_info finfo; | 51 | struct ncp_entry_info finfo; |
52 | int result; | 52 | int result; |
53 | 53 | ||
54 | /* tries max. rights */ | 54 | /* tries max. rights */ |
55 | finfo.access = O_RDWR; | 55 | finfo.access = O_RDWR; |
56 | result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), | 56 | result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), |
57 | inode, NULL, OC_MODE_OPEN, | 57 | inode, NULL, OC_MODE_OPEN, |
58 | 0, AR_READ | AR_WRITE, &finfo); | 58 | 0, AR_READ | AR_WRITE, &finfo); |
59 | if (!result) | 59 | if (!result) |
60 | goto update; | 60 | goto update; |
61 | /* RDWR did not succeeded, try readonly or writeonly as requested */ | 61 | /* RDWR did not succeeded, try readonly or writeonly as requested */ |
62 | switch (right) { | 62 | switch (right) { |
63 | case O_RDONLY: | 63 | case O_RDONLY: |
64 | finfo.access = O_RDONLY; | 64 | finfo.access = O_RDONLY; |
65 | result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), | 65 | result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), |
66 | inode, NULL, OC_MODE_OPEN, | 66 | inode, NULL, OC_MODE_OPEN, |
67 | 0, AR_READ, &finfo); | 67 | 0, AR_READ, &finfo); |
68 | break; | 68 | break; |
69 | case O_WRONLY: | 69 | case O_WRONLY: |
70 | finfo.access = O_WRONLY; | 70 | finfo.access = O_WRONLY; |
71 | result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), | 71 | result = ncp_open_create_file_or_subdir(NCP_SERVER(inode), |
72 | inode, NULL, OC_MODE_OPEN, | 72 | inode, NULL, OC_MODE_OPEN, |
73 | 0, AR_WRITE, &finfo); | 73 | 0, AR_WRITE, &finfo); |
74 | break; | 74 | break; |
75 | } | 75 | } |
76 | if (result) { | 76 | if (result) { |
77 | PPRINTK("ncp_make_open: failed, result=%d\n", result); | 77 | PPRINTK("ncp_make_open: failed, result=%d\n", result); |
78 | goto out_unlock; | 78 | goto out_unlock; |
79 | } | 79 | } |
80 | /* | 80 | /* |
81 | * Update the inode information. | 81 | * Update the inode information. |
82 | */ | 82 | */ |
83 | update: | 83 | update: |
84 | ncp_update_inode(inode, &finfo); | 84 | ncp_update_inode(inode, &finfo); |
85 | atomic_set(&NCP_FINFO(inode)->opened, 1); | 85 | atomic_set(&NCP_FINFO(inode)->opened, 1); |
86 | } | 86 | } |
87 | 87 | ||
88 | access = NCP_FINFO(inode)->access; | 88 | access = NCP_FINFO(inode)->access; |
89 | PPRINTK("ncp_make_open: file open, access=%x\n", access); | 89 | PPRINTK("ncp_make_open: file open, access=%x\n", access); |
90 | if (access == right || access == O_RDWR) { | 90 | if (access == right || access == O_RDWR) { |
91 | atomic_inc(&NCP_FINFO(inode)->opened); | 91 | atomic_inc(&NCP_FINFO(inode)->opened); |
92 | error = 0; | 92 | error = 0; |
93 | } | 93 | } |
94 | 94 | ||
95 | out_unlock: | 95 | out_unlock: |
96 | mutex_unlock(&NCP_FINFO(inode)->open_mutex); | 96 | mutex_unlock(&NCP_FINFO(inode)->open_mutex); |
97 | out: | 97 | out: |
98 | return error; | 98 | return error; |
99 | } | 99 | } |
100 | 100 | ||
101 | static ssize_t | 101 | static ssize_t |
102 | ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) | 102 | ncp_file_read(struct file *file, char __user *buf, size_t count, loff_t *ppos) |
103 | { | 103 | { |
104 | struct dentry *dentry = file->f_dentry; | 104 | struct dentry *dentry = file->f_path.dentry; |
105 | struct inode *inode = dentry->d_inode; | 105 | struct inode *inode = dentry->d_inode; |
106 | size_t already_read = 0; | 106 | size_t already_read = 0; |
107 | off_t pos; | 107 | off_t pos; |
108 | size_t bufsize; | 108 | size_t bufsize; |
109 | int error; | 109 | int error; |
110 | void* freepage; | 110 | void* freepage; |
111 | size_t freelen; | 111 | size_t freelen; |
112 | 112 | ||
113 | DPRINTK("ncp_file_read: enter %s/%s\n", | 113 | DPRINTK("ncp_file_read: enter %s/%s\n", |
114 | dentry->d_parent->d_name.name, dentry->d_name.name); | 114 | dentry->d_parent->d_name.name, dentry->d_name.name); |
115 | 115 | ||
116 | if (!ncp_conn_valid(NCP_SERVER(inode))) | 116 | if (!ncp_conn_valid(NCP_SERVER(inode))) |
117 | return -EIO; | 117 | return -EIO; |
118 | 118 | ||
119 | pos = *ppos; | 119 | pos = *ppos; |
120 | 120 | ||
121 | if ((ssize_t) count < 0) { | 121 | if ((ssize_t) count < 0) { |
122 | return -EINVAL; | 122 | return -EINVAL; |
123 | } | 123 | } |
124 | if (!count) | 124 | if (!count) |
125 | return 0; | 125 | return 0; |
126 | if (pos > inode->i_sb->s_maxbytes) | 126 | if (pos > inode->i_sb->s_maxbytes) |
127 | return 0; | 127 | return 0; |
128 | if (pos + count > inode->i_sb->s_maxbytes) { | 128 | if (pos + count > inode->i_sb->s_maxbytes) { |
129 | count = inode->i_sb->s_maxbytes - pos; | 129 | count = inode->i_sb->s_maxbytes - pos; |
130 | } | 130 | } |
131 | 131 | ||
132 | error = ncp_make_open(inode, O_RDONLY); | 132 | error = ncp_make_open(inode, O_RDONLY); |
133 | if (error) { | 133 | if (error) { |
134 | DPRINTK(KERN_ERR "ncp_file_read: open failed, error=%d\n", error); | 134 | DPRINTK(KERN_ERR "ncp_file_read: open failed, error=%d\n", error); |
135 | return error; | 135 | return error; |
136 | } | 136 | } |
137 | 137 | ||
138 | bufsize = NCP_SERVER(inode)->buffer_size; | 138 | bufsize = NCP_SERVER(inode)->buffer_size; |
139 | 139 | ||
140 | error = -EIO; | 140 | error = -EIO; |
141 | freelen = ncp_read_bounce_size(bufsize); | 141 | freelen = ncp_read_bounce_size(bufsize); |
142 | freepage = vmalloc(freelen); | 142 | freepage = vmalloc(freelen); |
143 | if (!freepage) | 143 | if (!freepage) |
144 | goto outrel; | 144 | goto outrel; |
145 | error = 0; | 145 | error = 0; |
146 | /* First read in as much as possible for each bufsize. */ | 146 | /* First read in as much as possible for each bufsize. */ |
147 | while (already_read < count) { | 147 | while (already_read < count) { |
148 | int read_this_time; | 148 | int read_this_time; |
149 | size_t to_read = min_t(unsigned int, | 149 | size_t to_read = min_t(unsigned int, |
150 | bufsize - (pos % bufsize), | 150 | bufsize - (pos % bufsize), |
151 | count - already_read); | 151 | count - already_read); |
152 | 152 | ||
153 | error = ncp_read_bounce(NCP_SERVER(inode), | 153 | error = ncp_read_bounce(NCP_SERVER(inode), |
154 | NCP_FINFO(inode)->file_handle, | 154 | NCP_FINFO(inode)->file_handle, |
155 | pos, to_read, buf, &read_this_time, | 155 | pos, to_read, buf, &read_this_time, |
156 | freepage, freelen); | 156 | freepage, freelen); |
157 | if (error) { | 157 | if (error) { |
158 | error = -EIO; /* NW errno -> Linux errno */ | 158 | error = -EIO; /* NW errno -> Linux errno */ |
159 | break; | 159 | break; |
160 | } | 160 | } |
161 | pos += read_this_time; | 161 | pos += read_this_time; |
162 | buf += read_this_time; | 162 | buf += read_this_time; |
163 | already_read += read_this_time; | 163 | already_read += read_this_time; |
164 | 164 | ||
165 | if (read_this_time != to_read) { | 165 | if (read_this_time != to_read) { |
166 | break; | 166 | break; |
167 | } | 167 | } |
168 | } | 168 | } |
169 | vfree(freepage); | 169 | vfree(freepage); |
170 | 170 | ||
171 | *ppos = pos; | 171 | *ppos = pos; |
172 | 172 | ||
173 | file_accessed(file); | 173 | file_accessed(file); |
174 | 174 | ||
175 | DPRINTK("ncp_file_read: exit %s/%s\n", | 175 | DPRINTK("ncp_file_read: exit %s/%s\n", |
176 | dentry->d_parent->d_name.name, dentry->d_name.name); | 176 | dentry->d_parent->d_name.name, dentry->d_name.name); |
177 | outrel: | 177 | outrel: |
178 | ncp_inode_close(inode); | 178 | ncp_inode_close(inode); |
179 | return already_read ? already_read : error; | 179 | return already_read ? already_read : error; |
180 | } | 180 | } |
181 | 181 | ||
182 | static ssize_t | 182 | static ssize_t |
183 | ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) | 183 | ncp_file_write(struct file *file, const char __user *buf, size_t count, loff_t *ppos) |
184 | { | 184 | { |
185 | struct dentry *dentry = file->f_dentry; | 185 | struct dentry *dentry = file->f_path.dentry; |
186 | struct inode *inode = dentry->d_inode; | 186 | struct inode *inode = dentry->d_inode; |
187 | size_t already_written = 0; | 187 | size_t already_written = 0; |
188 | off_t pos; | 188 | off_t pos; |
189 | size_t bufsize; | 189 | size_t bufsize; |
190 | int errno; | 190 | int errno; |
191 | void* bouncebuffer; | 191 | void* bouncebuffer; |
192 | 192 | ||
193 | DPRINTK("ncp_file_write: enter %s/%s\n", | 193 | DPRINTK("ncp_file_write: enter %s/%s\n", |
194 | dentry->d_parent->d_name.name, dentry->d_name.name); | 194 | dentry->d_parent->d_name.name, dentry->d_name.name); |
195 | if (!ncp_conn_valid(NCP_SERVER(inode))) | 195 | if (!ncp_conn_valid(NCP_SERVER(inode))) |
196 | return -EIO; | 196 | return -EIO; |
197 | if ((ssize_t) count < 0) | 197 | if ((ssize_t) count < 0) |
198 | return -EINVAL; | 198 | return -EINVAL; |
199 | pos = *ppos; | 199 | pos = *ppos; |
200 | if (file->f_flags & O_APPEND) { | 200 | if (file->f_flags & O_APPEND) { |
201 | pos = inode->i_size; | 201 | pos = inode->i_size; |
202 | } | 202 | } |
203 | 203 | ||
204 | if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) { | 204 | if (pos + count > MAX_NON_LFS && !(file->f_flags&O_LARGEFILE)) { |
205 | if (pos >= MAX_NON_LFS) { | 205 | if (pos >= MAX_NON_LFS) { |
206 | send_sig(SIGXFSZ, current, 0); | 206 | send_sig(SIGXFSZ, current, 0); |
207 | return -EFBIG; | 207 | return -EFBIG; |
208 | } | 208 | } |
209 | if (count > MAX_NON_LFS - (u32)pos) { | 209 | if (count > MAX_NON_LFS - (u32)pos) { |
210 | count = MAX_NON_LFS - (u32)pos; | 210 | count = MAX_NON_LFS - (u32)pos; |
211 | } | 211 | } |
212 | } | 212 | } |
213 | if (pos >= inode->i_sb->s_maxbytes) { | 213 | if (pos >= inode->i_sb->s_maxbytes) { |
214 | if (count || pos > inode->i_sb->s_maxbytes) { | 214 | if (count || pos > inode->i_sb->s_maxbytes) { |
215 | send_sig(SIGXFSZ, current, 0); | 215 | send_sig(SIGXFSZ, current, 0); |
216 | return -EFBIG; | 216 | return -EFBIG; |
217 | } | 217 | } |
218 | } | 218 | } |
219 | if (pos + count > inode->i_sb->s_maxbytes) { | 219 | if (pos + count > inode->i_sb->s_maxbytes) { |
220 | count = inode->i_sb->s_maxbytes - pos; | 220 | count = inode->i_sb->s_maxbytes - pos; |
221 | } | 221 | } |
222 | 222 | ||
223 | if (!count) | 223 | if (!count) |
224 | return 0; | 224 | return 0; |
225 | errno = ncp_make_open(inode, O_WRONLY); | 225 | errno = ncp_make_open(inode, O_WRONLY); |
226 | if (errno) { | 226 | if (errno) { |
227 | DPRINTK(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno); | 227 | DPRINTK(KERN_ERR "ncp_file_write: open failed, error=%d\n", errno); |
228 | return errno; | 228 | return errno; |
229 | } | 229 | } |
230 | bufsize = NCP_SERVER(inode)->buffer_size; | 230 | bufsize = NCP_SERVER(inode)->buffer_size; |
231 | 231 | ||
232 | already_written = 0; | 232 | already_written = 0; |
233 | 233 | ||
234 | bouncebuffer = vmalloc(bufsize); | 234 | bouncebuffer = vmalloc(bufsize); |
235 | if (!bouncebuffer) { | 235 | if (!bouncebuffer) { |
236 | errno = -EIO; /* -ENOMEM */ | 236 | errno = -EIO; /* -ENOMEM */ |
237 | goto outrel; | 237 | goto outrel; |
238 | } | 238 | } |
239 | while (already_written < count) { | 239 | while (already_written < count) { |
240 | int written_this_time; | 240 | int written_this_time; |
241 | size_t to_write = min_t(unsigned int, | 241 | size_t to_write = min_t(unsigned int, |
242 | bufsize - (pos % bufsize), | 242 | bufsize - (pos % bufsize), |
243 | count - already_written); | 243 | count - already_written); |
244 | 244 | ||
245 | if (copy_from_user(bouncebuffer, buf, to_write)) { | 245 | if (copy_from_user(bouncebuffer, buf, to_write)) { |
246 | errno = -EFAULT; | 246 | errno = -EFAULT; |
247 | break; | 247 | break; |
248 | } | 248 | } |
249 | if (ncp_write_kernel(NCP_SERVER(inode), | 249 | if (ncp_write_kernel(NCP_SERVER(inode), |
250 | NCP_FINFO(inode)->file_handle, | 250 | NCP_FINFO(inode)->file_handle, |
251 | pos, to_write, bouncebuffer, &written_this_time) != 0) { | 251 | pos, to_write, bouncebuffer, &written_this_time) != 0) { |
252 | errno = -EIO; | 252 | errno = -EIO; |
253 | break; | 253 | break; |
254 | } | 254 | } |
255 | pos += written_this_time; | 255 | pos += written_this_time; |
256 | buf += written_this_time; | 256 | buf += written_this_time; |
257 | already_written += written_this_time; | 257 | already_written += written_this_time; |
258 | 258 | ||
259 | if (written_this_time != to_write) { | 259 | if (written_this_time != to_write) { |
260 | break; | 260 | break; |
261 | } | 261 | } |
262 | } | 262 | } |
263 | vfree(bouncebuffer); | 263 | vfree(bouncebuffer); |
264 | 264 | ||
265 | file_update_time(file); | 265 | file_update_time(file); |
266 | 266 | ||
267 | *ppos = pos; | 267 | *ppos = pos; |
268 | 268 | ||
269 | if (pos > inode->i_size) { | 269 | if (pos > inode->i_size) { |
270 | inode->i_size = pos; | 270 | inode->i_size = pos; |
271 | } | 271 | } |
272 | DPRINTK("ncp_file_write: exit %s/%s\n", | 272 | DPRINTK("ncp_file_write: exit %s/%s\n", |
273 | dentry->d_parent->d_name.name, dentry->d_name.name); | 273 | dentry->d_parent->d_name.name, dentry->d_name.name); |
274 | outrel: | 274 | outrel: |
275 | ncp_inode_close(inode); | 275 | ncp_inode_close(inode); |
276 | return already_written ? already_written : errno; | 276 | return already_written ? already_written : errno; |
277 | } | 277 | } |
278 | 278 | ||
279 | static int ncp_release(struct inode *inode, struct file *file) { | 279 | static int ncp_release(struct inode *inode, struct file *file) { |
280 | if (ncp_make_closed(inode)) { | 280 | if (ncp_make_closed(inode)) { |
281 | DPRINTK("ncp_release: failed to close\n"); | 281 | DPRINTK("ncp_release: failed to close\n"); |
282 | } | 282 | } |
283 | return 0; | 283 | return 0; |
284 | } | 284 | } |
285 | 285 | ||
286 | const struct file_operations ncp_file_operations = | 286 | const struct file_operations ncp_file_operations = |
287 | { | 287 | { |
288 | .llseek = remote_llseek, | 288 | .llseek = remote_llseek, |
289 | .read = ncp_file_read, | 289 | .read = ncp_file_read, |
290 | .write = ncp_file_write, | 290 | .write = ncp_file_write, |
291 | .ioctl = ncp_ioctl, | 291 | .ioctl = ncp_ioctl, |
292 | #ifdef CONFIG_COMPAT | 292 | #ifdef CONFIG_COMPAT |
293 | .compat_ioctl = ncp_compat_ioctl, | 293 | .compat_ioctl = ncp_compat_ioctl, |
294 | #endif | 294 | #endif |
295 | .mmap = ncp_mmap, | 295 | .mmap = ncp_mmap, |
296 | .release = ncp_release, | 296 | .release = ncp_release, |
297 | .fsync = ncp_fsync, | 297 | .fsync = ncp_fsync, |
298 | }; | 298 | }; |
299 | 299 | ||
300 | struct inode_operations ncp_file_inode_operations = | 300 | struct inode_operations ncp_file_inode_operations = |
301 | { | 301 | { |
302 | .setattr = ncp_notify_change, | 302 | .setattr = ncp_notify_change, |
303 | }; | 303 | }; |
304 | 304 |
fs/ncpfs/inode.c
1 | /* | 1 | /* |
2 | * inode.c | 2 | * inode.c |
3 | * | 3 | * |
4 | * Copyright (C) 1995, 1996 by Volker Lendecke | 4 | * Copyright (C) 1995, 1996 by Volker Lendecke |
5 | * Modified for big endian by J.F. Chadima and David S. Miller | 5 | * Modified for big endian by J.F. Chadima and David S. Miller |
6 | * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache | 6 | * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache |
7 | * Modified 1998 Wolfram Pienkoss for NLS | 7 | * Modified 1998 Wolfram Pienkoss for NLS |
8 | * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info | 8 | * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info |
9 | * | 9 | * |
10 | */ | 10 | */ |
11 | 11 | ||
12 | #include <linux/module.h> | 12 | #include <linux/module.h> |
13 | 13 | ||
14 | #include <asm/system.h> | 14 | #include <asm/system.h> |
15 | #include <asm/uaccess.h> | 15 | #include <asm/uaccess.h> |
16 | #include <asm/byteorder.h> | 16 | #include <asm/byteorder.h> |
17 | 17 | ||
18 | #include <linux/time.h> | 18 | #include <linux/time.h> |
19 | #include <linux/kernel.h> | 19 | #include <linux/kernel.h> |
20 | #include <linux/mm.h> | 20 | #include <linux/mm.h> |
21 | #include <linux/string.h> | 21 | #include <linux/string.h> |
22 | #include <linux/stat.h> | 22 | #include <linux/stat.h> |
23 | #include <linux/errno.h> | 23 | #include <linux/errno.h> |
24 | #include <linux/file.h> | 24 | #include <linux/file.h> |
25 | #include <linux/fcntl.h> | 25 | #include <linux/fcntl.h> |
26 | #include <linux/slab.h> | 26 | #include <linux/slab.h> |
27 | #include <linux/vmalloc.h> | 27 | #include <linux/vmalloc.h> |
28 | #include <linux/init.h> | 28 | #include <linux/init.h> |
29 | #include <linux/smp_lock.h> | 29 | #include <linux/smp_lock.h> |
30 | #include <linux/vfs.h> | 30 | #include <linux/vfs.h> |
31 | 31 | ||
32 | #include <linux/ncp_fs.h> | 32 | #include <linux/ncp_fs.h> |
33 | 33 | ||
34 | #include <net/sock.h> | 34 | #include <net/sock.h> |
35 | 35 | ||
36 | #include "ncplib_kernel.h" | 36 | #include "ncplib_kernel.h" |
37 | #include "getopt.h" | 37 | #include "getopt.h" |
38 | 38 | ||
39 | static void ncp_delete_inode(struct inode *); | 39 | static void ncp_delete_inode(struct inode *); |
40 | static void ncp_put_super(struct super_block *); | 40 | static void ncp_put_super(struct super_block *); |
41 | static int ncp_statfs(struct dentry *, struct kstatfs *); | 41 | static int ncp_statfs(struct dentry *, struct kstatfs *); |
42 | 42 | ||
43 | static struct kmem_cache * ncp_inode_cachep; | 43 | static struct kmem_cache * ncp_inode_cachep; |
44 | 44 | ||
45 | static struct inode *ncp_alloc_inode(struct super_block *sb) | 45 | static struct inode *ncp_alloc_inode(struct super_block *sb) |
46 | { | 46 | { |
47 | struct ncp_inode_info *ei; | 47 | struct ncp_inode_info *ei; |
48 | ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL); | 48 | ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL); |
49 | if (!ei) | 49 | if (!ei) |
50 | return NULL; | 50 | return NULL; |
51 | return &ei->vfs_inode; | 51 | return &ei->vfs_inode; |
52 | } | 52 | } |
53 | 53 | ||
54 | static void ncp_destroy_inode(struct inode *inode) | 54 | static void ncp_destroy_inode(struct inode *inode) |
55 | { | 55 | { |
56 | kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode)); | 56 | kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode)); |
57 | } | 57 | } |
58 | 58 | ||
59 | static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) | 59 | static void init_once(void * foo, struct kmem_cache * cachep, unsigned long flags) |
60 | { | 60 | { |
61 | struct ncp_inode_info *ei = (struct ncp_inode_info *) foo; | 61 | struct ncp_inode_info *ei = (struct ncp_inode_info *) foo; |
62 | 62 | ||
63 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == | 63 | if ((flags & (SLAB_CTOR_VERIFY|SLAB_CTOR_CONSTRUCTOR)) == |
64 | SLAB_CTOR_CONSTRUCTOR) { | 64 | SLAB_CTOR_CONSTRUCTOR) { |
65 | mutex_init(&ei->open_mutex); | 65 | mutex_init(&ei->open_mutex); |
66 | inode_init_once(&ei->vfs_inode); | 66 | inode_init_once(&ei->vfs_inode); |
67 | } | 67 | } |
68 | } | 68 | } |
69 | 69 | ||
70 | static int init_inodecache(void) | 70 | static int init_inodecache(void) |
71 | { | 71 | { |
72 | ncp_inode_cachep = kmem_cache_create("ncp_inode_cache", | 72 | ncp_inode_cachep = kmem_cache_create("ncp_inode_cache", |
73 | sizeof(struct ncp_inode_info), | 73 | sizeof(struct ncp_inode_info), |
74 | 0, (SLAB_RECLAIM_ACCOUNT| | 74 | 0, (SLAB_RECLAIM_ACCOUNT| |
75 | SLAB_MEM_SPREAD), | 75 | SLAB_MEM_SPREAD), |
76 | init_once, NULL); | 76 | init_once, NULL); |
77 | if (ncp_inode_cachep == NULL) | 77 | if (ncp_inode_cachep == NULL) |
78 | return -ENOMEM; | 78 | return -ENOMEM; |
79 | return 0; | 79 | return 0; |
80 | } | 80 | } |
81 | 81 | ||
82 | static void destroy_inodecache(void) | 82 | static void destroy_inodecache(void) |
83 | { | 83 | { |
84 | kmem_cache_destroy(ncp_inode_cachep); | 84 | kmem_cache_destroy(ncp_inode_cachep); |
85 | } | 85 | } |
86 | 86 | ||
87 | static int ncp_remount(struct super_block *sb, int *flags, char* data) | 87 | static int ncp_remount(struct super_block *sb, int *flags, char* data) |
88 | { | 88 | { |
89 | *flags |= MS_NODIRATIME; | 89 | *flags |= MS_NODIRATIME; |
90 | return 0; | 90 | return 0; |
91 | } | 91 | } |
92 | 92 | ||
93 | static struct super_operations ncp_sops = | 93 | static struct super_operations ncp_sops = |
94 | { | 94 | { |
95 | .alloc_inode = ncp_alloc_inode, | 95 | .alloc_inode = ncp_alloc_inode, |
96 | .destroy_inode = ncp_destroy_inode, | 96 | .destroy_inode = ncp_destroy_inode, |
97 | .drop_inode = generic_delete_inode, | 97 | .drop_inode = generic_delete_inode, |
98 | .delete_inode = ncp_delete_inode, | 98 | .delete_inode = ncp_delete_inode, |
99 | .put_super = ncp_put_super, | 99 | .put_super = ncp_put_super, |
100 | .statfs = ncp_statfs, | 100 | .statfs = ncp_statfs, |
101 | .remount_fs = ncp_remount, | 101 | .remount_fs = ncp_remount, |
102 | }; | 102 | }; |
103 | 103 | ||
104 | extern struct dentry_operations ncp_root_dentry_operations; | 104 | extern struct dentry_operations ncp_root_dentry_operations; |
105 | #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) | 105 | #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) |
106 | extern const struct address_space_operations ncp_symlink_aops; | 106 | extern const struct address_space_operations ncp_symlink_aops; |
107 | extern int ncp_symlink(struct inode*, struct dentry*, const char*); | 107 | extern int ncp_symlink(struct inode*, struct dentry*, const char*); |
108 | #endif | 108 | #endif |
109 | 109 | ||
110 | /* | 110 | /* |
111 | * Fill in the ncpfs-specific information in the inode. | 111 | * Fill in the ncpfs-specific information in the inode. |
112 | */ | 112 | */ |
113 | static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo) | 113 | static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo) |
114 | { | 114 | { |
115 | NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum; | 115 | NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum; |
116 | NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum; | 116 | NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum; |
117 | NCP_FINFO(inode)->volNumber = nwinfo->volume; | 117 | NCP_FINFO(inode)->volNumber = nwinfo->volume; |
118 | } | 118 | } |
119 | 119 | ||
120 | void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo) | 120 | void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo) |
121 | { | 121 | { |
122 | ncp_update_dirent(inode, nwinfo); | 122 | ncp_update_dirent(inode, nwinfo); |
123 | NCP_FINFO(inode)->nwattr = nwinfo->i.attributes; | 123 | NCP_FINFO(inode)->nwattr = nwinfo->i.attributes; |
124 | NCP_FINFO(inode)->access = nwinfo->access; | 124 | NCP_FINFO(inode)->access = nwinfo->access; |
125 | memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle, | 125 | memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle, |
126 | sizeof(nwinfo->file_handle)); | 126 | sizeof(nwinfo->file_handle)); |
127 | DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n", | 127 | DPRINTK("ncp_update_inode: updated %s, volnum=%d, dirent=%u\n", |
128 | nwinfo->i.entryName, NCP_FINFO(inode)->volNumber, | 128 | nwinfo->i.entryName, NCP_FINFO(inode)->volNumber, |
129 | NCP_FINFO(inode)->dirEntNum); | 129 | NCP_FINFO(inode)->dirEntNum); |
130 | } | 130 | } |
131 | 131 | ||
132 | static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi) | 132 | static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi) |
133 | { | 133 | { |
134 | /* NFS namespace mode overrides others if it's set. */ | 134 | /* NFS namespace mode overrides others if it's set. */ |
135 | DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n", | 135 | DPRINTK(KERN_DEBUG "ncp_update_dates_and_mode: (%s) nfs.mode=0%o\n", |
136 | nwi->entryName, nwi->nfs.mode); | 136 | nwi->entryName, nwi->nfs.mode); |
137 | if (nwi->nfs.mode) { | 137 | if (nwi->nfs.mode) { |
138 | /* XXX Security? */ | 138 | /* XXX Security? */ |
139 | inode->i_mode = nwi->nfs.mode; | 139 | inode->i_mode = nwi->nfs.mode; |
140 | } | 140 | } |
141 | 141 | ||
142 | inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT; | 142 | inode->i_blocks = (inode->i_size + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT; |
143 | 143 | ||
144 | inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate); | 144 | inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate); |
145 | inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate); | 145 | inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate); |
146 | inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate); | 146 | inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate); |
147 | inode->i_atime.tv_nsec = 0; | 147 | inode->i_atime.tv_nsec = 0; |
148 | inode->i_mtime.tv_nsec = 0; | 148 | inode->i_mtime.tv_nsec = 0; |
149 | inode->i_ctime.tv_nsec = 0; | 149 | inode->i_ctime.tv_nsec = 0; |
150 | } | 150 | } |
151 | 151 | ||
152 | static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo) | 152 | static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo) |
153 | { | 153 | { |
154 | struct nw_info_struct *nwi = &nwinfo->i; | 154 | struct nw_info_struct *nwi = &nwinfo->i; |
155 | struct ncp_server *server = NCP_SERVER(inode); | 155 | struct ncp_server *server = NCP_SERVER(inode); |
156 | 156 | ||
157 | if (nwi->attributes & aDIR) { | 157 | if (nwi->attributes & aDIR) { |
158 | inode->i_mode = server->m.dir_mode; | 158 | inode->i_mode = server->m.dir_mode; |
159 | /* for directories dataStreamSize seems to be some | 159 | /* for directories dataStreamSize seems to be some |
160 | Object ID ??? */ | 160 | Object ID ??? */ |
161 | inode->i_size = NCP_BLOCK_SIZE; | 161 | inode->i_size = NCP_BLOCK_SIZE; |
162 | } else { | 162 | } else { |
163 | inode->i_mode = server->m.file_mode; | 163 | inode->i_mode = server->m.file_mode; |
164 | inode->i_size = le32_to_cpu(nwi->dataStreamSize); | 164 | inode->i_size = le32_to_cpu(nwi->dataStreamSize); |
165 | #ifdef CONFIG_NCPFS_EXTRAS | 165 | #ifdef CONFIG_NCPFS_EXTRAS |
166 | if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) | 166 | if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) |
167 | && (nwi->attributes & aSHARED)) { | 167 | && (nwi->attributes & aSHARED)) { |
168 | switch (nwi->attributes & (aHIDDEN|aSYSTEM)) { | 168 | switch (nwi->attributes & (aHIDDEN|aSYSTEM)) { |
169 | case aHIDDEN: | 169 | case aHIDDEN: |
170 | if (server->m.flags & NCP_MOUNT_SYMLINKS) { | 170 | if (server->m.flags & NCP_MOUNT_SYMLINKS) { |
171 | if (/* (inode->i_size >= NCP_MIN_SYMLINK_SIZE) | 171 | if (/* (inode->i_size >= NCP_MIN_SYMLINK_SIZE) |
172 | && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) { | 172 | && */ (inode->i_size <= NCP_MAX_SYMLINK_SIZE)) { |
173 | inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK; | 173 | inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK; |
174 | NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK; | 174 | NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK; |
175 | break; | 175 | break; |
176 | } | 176 | } |
177 | } | 177 | } |
178 | /* FALLTHROUGH */ | 178 | /* FALLTHROUGH */ |
179 | case 0: | 179 | case 0: |
180 | if (server->m.flags & NCP_MOUNT_EXTRAS) | 180 | if (server->m.flags & NCP_MOUNT_EXTRAS) |
181 | inode->i_mode |= S_IRUGO; | 181 | inode->i_mode |= S_IRUGO; |
182 | break; | 182 | break; |
183 | case aSYSTEM: | 183 | case aSYSTEM: |
184 | if (server->m.flags & NCP_MOUNT_EXTRAS) | 184 | if (server->m.flags & NCP_MOUNT_EXTRAS) |
185 | inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO; | 185 | inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO; |
186 | break; | 186 | break; |
187 | /* case aSYSTEM|aHIDDEN: */ | 187 | /* case aSYSTEM|aHIDDEN: */ |
188 | default: | 188 | default: |
189 | /* reserved combination */ | 189 | /* reserved combination */ |
190 | break; | 190 | break; |
191 | } | 191 | } |
192 | } | 192 | } |
193 | #endif | 193 | #endif |
194 | } | 194 | } |
195 | if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO; | 195 | if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO; |
196 | } | 196 | } |
197 | 197 | ||
198 | void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo) | 198 | void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo) |
199 | { | 199 | { |
200 | NCP_FINFO(inode)->flags = 0; | 200 | NCP_FINFO(inode)->flags = 0; |
201 | if (!atomic_read(&NCP_FINFO(inode)->opened)) { | 201 | if (!atomic_read(&NCP_FINFO(inode)->opened)) { |
202 | NCP_FINFO(inode)->nwattr = nwinfo->i.attributes; | 202 | NCP_FINFO(inode)->nwattr = nwinfo->i.attributes; |
203 | ncp_update_attrs(inode, nwinfo); | 203 | ncp_update_attrs(inode, nwinfo); |
204 | } | 204 | } |
205 | 205 | ||
206 | ncp_update_dates(inode, &nwinfo->i); | 206 | ncp_update_dates(inode, &nwinfo->i); |
207 | ncp_update_dirent(inode, nwinfo); | 207 | ncp_update_dirent(inode, nwinfo); |
208 | } | 208 | } |
209 | 209 | ||
210 | /* | 210 | /* |
211 | * Fill in the inode based on the ncp_entry_info structure. | 211 | * Fill in the inode based on the ncp_entry_info structure. |
212 | */ | 212 | */ |
213 | static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo) | 213 | static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo) |
214 | { | 214 | { |
215 | struct ncp_server *server = NCP_SERVER(inode); | 215 | struct ncp_server *server = NCP_SERVER(inode); |
216 | 216 | ||
217 | NCP_FINFO(inode)->flags = 0; | 217 | NCP_FINFO(inode)->flags = 0; |
218 | 218 | ||
219 | ncp_update_attrs(inode, nwinfo); | 219 | ncp_update_attrs(inode, nwinfo); |
220 | 220 | ||
221 | DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode); | 221 | DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode); |
222 | 222 | ||
223 | inode->i_nlink = 1; | 223 | inode->i_nlink = 1; |
224 | inode->i_uid = server->m.uid; | 224 | inode->i_uid = server->m.uid; |
225 | inode->i_gid = server->m.gid; | 225 | inode->i_gid = server->m.gid; |
226 | 226 | ||
227 | ncp_update_dates(inode, &nwinfo->i); | 227 | ncp_update_dates(inode, &nwinfo->i); |
228 | ncp_update_inode(inode, nwinfo); | 228 | ncp_update_inode(inode, nwinfo); |
229 | } | 229 | } |
230 | 230 | ||
231 | #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) | 231 | #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) |
232 | static struct inode_operations ncp_symlink_inode_operations = { | 232 | static struct inode_operations ncp_symlink_inode_operations = { |
233 | .readlink = generic_readlink, | 233 | .readlink = generic_readlink, |
234 | .follow_link = page_follow_link_light, | 234 | .follow_link = page_follow_link_light, |
235 | .put_link = page_put_link, | 235 | .put_link = page_put_link, |
236 | .setattr = ncp_notify_change, | 236 | .setattr = ncp_notify_change, |
237 | }; | 237 | }; |
238 | #endif | 238 | #endif |
239 | 239 | ||
240 | /* | 240 | /* |
241 | * Get a new inode. | 241 | * Get a new inode. |
242 | */ | 242 | */ |
243 | struct inode * | 243 | struct inode * |
244 | ncp_iget(struct super_block *sb, struct ncp_entry_info *info) | 244 | ncp_iget(struct super_block *sb, struct ncp_entry_info *info) |
245 | { | 245 | { |
246 | struct inode *inode; | 246 | struct inode *inode; |
247 | 247 | ||
248 | if (info == NULL) { | 248 | if (info == NULL) { |
249 | printk(KERN_ERR "ncp_iget: info is NULL\n"); | 249 | printk(KERN_ERR "ncp_iget: info is NULL\n"); |
250 | return NULL; | 250 | return NULL; |
251 | } | 251 | } |
252 | 252 | ||
253 | inode = new_inode(sb); | 253 | inode = new_inode(sb); |
254 | if (inode) { | 254 | if (inode) { |
255 | atomic_set(&NCP_FINFO(inode)->opened, info->opened); | 255 | atomic_set(&NCP_FINFO(inode)->opened, info->opened); |
256 | 256 | ||
257 | inode->i_ino = info->ino; | 257 | inode->i_ino = info->ino; |
258 | ncp_set_attr(inode, info); | 258 | ncp_set_attr(inode, info); |
259 | if (S_ISREG(inode->i_mode)) { | 259 | if (S_ISREG(inode->i_mode)) { |
260 | inode->i_op = &ncp_file_inode_operations; | 260 | inode->i_op = &ncp_file_inode_operations; |
261 | inode->i_fop = &ncp_file_operations; | 261 | inode->i_fop = &ncp_file_operations; |
262 | } else if (S_ISDIR(inode->i_mode)) { | 262 | } else if (S_ISDIR(inode->i_mode)) { |
263 | inode->i_op = &ncp_dir_inode_operations; | 263 | inode->i_op = &ncp_dir_inode_operations; |
264 | inode->i_fop = &ncp_dir_operations; | 264 | inode->i_fop = &ncp_dir_operations; |
265 | #ifdef CONFIG_NCPFS_NFS_NS | 265 | #ifdef CONFIG_NCPFS_NFS_NS |
266 | } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { | 266 | } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) { |
267 | init_special_inode(inode, inode->i_mode, | 267 | init_special_inode(inode, inode->i_mode, |
268 | new_decode_dev(info->i.nfs.rdev)); | 268 | new_decode_dev(info->i.nfs.rdev)); |
269 | #endif | 269 | #endif |
270 | #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) | 270 | #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS) |
271 | } else if (S_ISLNK(inode->i_mode)) { | 271 | } else if (S_ISLNK(inode->i_mode)) { |
272 | inode->i_op = &ncp_symlink_inode_operations; | 272 | inode->i_op = &ncp_symlink_inode_operations; |
273 | inode->i_data.a_ops = &ncp_symlink_aops; | 273 | inode->i_data.a_ops = &ncp_symlink_aops; |
274 | #endif | 274 | #endif |
275 | } else { | 275 | } else { |
276 | make_bad_inode(inode); | 276 | make_bad_inode(inode); |
277 | } | 277 | } |
278 | insert_inode_hash(inode); | 278 | insert_inode_hash(inode); |
279 | } else | 279 | } else |
280 | printk(KERN_ERR "ncp_iget: iget failed!\n"); | 280 | printk(KERN_ERR "ncp_iget: iget failed!\n"); |
281 | return inode; | 281 | return inode; |
282 | } | 282 | } |
283 | 283 | ||
284 | static void | 284 | static void |
285 | ncp_delete_inode(struct inode *inode) | 285 | ncp_delete_inode(struct inode *inode) |
286 | { | 286 | { |
287 | truncate_inode_pages(&inode->i_data, 0); | 287 | truncate_inode_pages(&inode->i_data, 0); |
288 | 288 | ||
289 | if (S_ISDIR(inode->i_mode)) { | 289 | if (S_ISDIR(inode->i_mode)) { |
290 | DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino); | 290 | DDPRINTK("ncp_delete_inode: put directory %ld\n", inode->i_ino); |
291 | } | 291 | } |
292 | 292 | ||
293 | if (ncp_make_closed(inode) != 0) { | 293 | if (ncp_make_closed(inode) != 0) { |
294 | /* We can't do anything but complain. */ | 294 | /* We can't do anything but complain. */ |
295 | printk(KERN_ERR "ncp_delete_inode: could not close\n"); | 295 | printk(KERN_ERR "ncp_delete_inode: could not close\n"); |
296 | } | 296 | } |
297 | clear_inode(inode); | 297 | clear_inode(inode); |
298 | } | 298 | } |
299 | 299 | ||
300 | static void ncp_stop_tasks(struct ncp_server *server) { | 300 | static void ncp_stop_tasks(struct ncp_server *server) { |
301 | struct sock* sk = server->ncp_sock->sk; | 301 | struct sock* sk = server->ncp_sock->sk; |
302 | 302 | ||
303 | sk->sk_error_report = server->error_report; | 303 | sk->sk_error_report = server->error_report; |
304 | sk->sk_data_ready = server->data_ready; | 304 | sk->sk_data_ready = server->data_ready; |
305 | sk->sk_write_space = server->write_space; | 305 | sk->sk_write_space = server->write_space; |
306 | del_timer_sync(&server->timeout_tm); | 306 | del_timer_sync(&server->timeout_tm); |
307 | flush_scheduled_work(); | 307 | flush_scheduled_work(); |
308 | } | 308 | } |
309 | 309 | ||
310 | static const struct ncp_option ncp_opts[] = { | 310 | static const struct ncp_option ncp_opts[] = { |
311 | { "uid", OPT_INT, 'u' }, | 311 | { "uid", OPT_INT, 'u' }, |
312 | { "gid", OPT_INT, 'g' }, | 312 | { "gid", OPT_INT, 'g' }, |
313 | { "owner", OPT_INT, 'o' }, | 313 | { "owner", OPT_INT, 'o' }, |
314 | { "mode", OPT_INT, 'm' }, | 314 | { "mode", OPT_INT, 'm' }, |
315 | { "dirmode", OPT_INT, 'd' }, | 315 | { "dirmode", OPT_INT, 'd' }, |
316 | { "timeout", OPT_INT, 't' }, | 316 | { "timeout", OPT_INT, 't' }, |
317 | { "retry", OPT_INT, 'r' }, | 317 | { "retry", OPT_INT, 'r' }, |
318 | { "flags", OPT_INT, 'f' }, | 318 | { "flags", OPT_INT, 'f' }, |
319 | { "wdogpid", OPT_INT, 'w' }, | 319 | { "wdogpid", OPT_INT, 'w' }, |
320 | { "ncpfd", OPT_INT, 'n' }, | 320 | { "ncpfd", OPT_INT, 'n' }, |
321 | { "infofd", OPT_INT, 'i' }, /* v5 */ | 321 | { "infofd", OPT_INT, 'i' }, /* v5 */ |
322 | { "version", OPT_INT, 'v' }, | 322 | { "version", OPT_INT, 'v' }, |
323 | { NULL, 0, 0 } }; | 323 | { NULL, 0, 0 } }; |
324 | 324 | ||
325 | static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) { | 325 | static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) { |
326 | int optval; | 326 | int optval; |
327 | char *optarg; | 327 | char *optarg; |
328 | unsigned long optint; | 328 | unsigned long optint; |
329 | int version = 0; | 329 | int version = 0; |
330 | 330 | ||
331 | data->flags = 0; | 331 | data->flags = 0; |
332 | data->int_flags = 0; | 332 | data->int_flags = 0; |
333 | data->mounted_uid = 0; | 333 | data->mounted_uid = 0; |
334 | data->wdog_pid = -1; | 334 | data->wdog_pid = -1; |
335 | data->ncp_fd = ~0; | 335 | data->ncp_fd = ~0; |
336 | data->time_out = 10; | 336 | data->time_out = 10; |
337 | data->retry_count = 20; | 337 | data->retry_count = 20; |
338 | data->uid = 0; | 338 | data->uid = 0; |
339 | data->gid = 0; | 339 | data->gid = 0; |
340 | data->file_mode = 0600; | 340 | data->file_mode = 0600; |
341 | data->dir_mode = 0700; | 341 | data->dir_mode = 0700; |
342 | data->info_fd = -1; | 342 | data->info_fd = -1; |
343 | data->mounted_vol[0] = 0; | 343 | data->mounted_vol[0] = 0; |
344 | 344 | ||
345 | while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) { | 345 | while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) { |
346 | if (optval < 0) | 346 | if (optval < 0) |
347 | return optval; | 347 | return optval; |
348 | switch (optval) { | 348 | switch (optval) { |
349 | case 'u': | 349 | case 'u': |
350 | data->uid = optint; | 350 | data->uid = optint; |
351 | break; | 351 | break; |
352 | case 'g': | 352 | case 'g': |
353 | data->gid = optint; | 353 | data->gid = optint; |
354 | break; | 354 | break; |
355 | case 'o': | 355 | case 'o': |
356 | data->mounted_uid = optint; | 356 | data->mounted_uid = optint; |
357 | break; | 357 | break; |
358 | case 'm': | 358 | case 'm': |
359 | data->file_mode = optint; | 359 | data->file_mode = optint; |
360 | break; | 360 | break; |
361 | case 'd': | 361 | case 'd': |
362 | data->dir_mode = optint; | 362 | data->dir_mode = optint; |
363 | break; | 363 | break; |
364 | case 't': | 364 | case 't': |
365 | data->time_out = optint; | 365 | data->time_out = optint; |
366 | break; | 366 | break; |
367 | case 'r': | 367 | case 'r': |
368 | data->retry_count = optint; | 368 | data->retry_count = optint; |
369 | break; | 369 | break; |
370 | case 'f': | 370 | case 'f': |
371 | data->flags = optint; | 371 | data->flags = optint; |
372 | break; | 372 | break; |
373 | case 'w': | 373 | case 'w': |
374 | data->wdog_pid = optint; | 374 | data->wdog_pid = optint; |
375 | break; | 375 | break; |
376 | case 'n': | 376 | case 'n': |
377 | data->ncp_fd = optint; | 377 | data->ncp_fd = optint; |
378 | break; | 378 | break; |
379 | case 'i': | 379 | case 'i': |
380 | data->info_fd = optint; | 380 | data->info_fd = optint; |
381 | break; | 381 | break; |
382 | case 'v': | 382 | case 'v': |
383 | if (optint < NCP_MOUNT_VERSION_V4) { | 383 | if (optint < NCP_MOUNT_VERSION_V4) { |
384 | return -ECHRNG; | 384 | return -ECHRNG; |
385 | } | 385 | } |
386 | if (optint > NCP_MOUNT_VERSION_V5) { | 386 | if (optint > NCP_MOUNT_VERSION_V5) { |
387 | return -ECHRNG; | 387 | return -ECHRNG; |
388 | } | 388 | } |
389 | version = optint; | 389 | version = optint; |
390 | break; | 390 | break; |
391 | 391 | ||
392 | } | 392 | } |
393 | } | 393 | } |
394 | return 0; | 394 | return 0; |
395 | } | 395 | } |
396 | 396 | ||
397 | static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) | 397 | static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent) |
398 | { | 398 | { |
399 | struct ncp_mount_data_kernel data; | 399 | struct ncp_mount_data_kernel data; |
400 | struct ncp_server *server; | 400 | struct ncp_server *server; |
401 | struct file *ncp_filp; | 401 | struct file *ncp_filp; |
402 | struct inode *root_inode; | 402 | struct inode *root_inode; |
403 | struct inode *sock_inode; | 403 | struct inode *sock_inode; |
404 | struct socket *sock; | 404 | struct socket *sock; |
405 | int error; | 405 | int error; |
406 | int default_bufsize; | 406 | int default_bufsize; |
407 | #ifdef CONFIG_NCPFS_PACKET_SIGNING | 407 | #ifdef CONFIG_NCPFS_PACKET_SIGNING |
408 | int options; | 408 | int options; |
409 | #endif | 409 | #endif |
410 | struct ncp_entry_info finfo; | 410 | struct ncp_entry_info finfo; |
411 | 411 | ||
412 | server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL); | 412 | server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL); |
413 | if (!server) | 413 | if (!server) |
414 | return -ENOMEM; | 414 | return -ENOMEM; |
415 | sb->s_fs_info = server; | 415 | sb->s_fs_info = server; |
416 | 416 | ||
417 | error = -EFAULT; | 417 | error = -EFAULT; |
418 | if (raw_data == NULL) | 418 | if (raw_data == NULL) |
419 | goto out; | 419 | goto out; |
420 | switch (*(int*)raw_data) { | 420 | switch (*(int*)raw_data) { |
421 | case NCP_MOUNT_VERSION: | 421 | case NCP_MOUNT_VERSION: |
422 | { | 422 | { |
423 | struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data; | 423 | struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data; |
424 | 424 | ||
425 | data.flags = md->flags; | 425 | data.flags = md->flags; |
426 | data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE; | 426 | data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE; |
427 | data.mounted_uid = md->mounted_uid; | 427 | data.mounted_uid = md->mounted_uid; |
428 | data.wdog_pid = md->wdog_pid; | 428 | data.wdog_pid = md->wdog_pid; |
429 | data.ncp_fd = md->ncp_fd; | 429 | data.ncp_fd = md->ncp_fd; |
430 | data.time_out = md->time_out; | 430 | data.time_out = md->time_out; |
431 | data.retry_count = md->retry_count; | 431 | data.retry_count = md->retry_count; |
432 | data.uid = md->uid; | 432 | data.uid = md->uid; |
433 | data.gid = md->gid; | 433 | data.gid = md->gid; |
434 | data.file_mode = md->file_mode; | 434 | data.file_mode = md->file_mode; |
435 | data.dir_mode = md->dir_mode; | 435 | data.dir_mode = md->dir_mode; |
436 | data.info_fd = -1; | 436 | data.info_fd = -1; |
437 | memcpy(data.mounted_vol, md->mounted_vol, | 437 | memcpy(data.mounted_vol, md->mounted_vol, |
438 | NCP_VOLNAME_LEN+1); | 438 | NCP_VOLNAME_LEN+1); |
439 | } | 439 | } |
440 | break; | 440 | break; |
441 | case NCP_MOUNT_VERSION_V4: | 441 | case NCP_MOUNT_VERSION_V4: |
442 | { | 442 | { |
443 | struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data; | 443 | struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data; |
444 | 444 | ||
445 | data.flags = md->flags; | 445 | data.flags = md->flags; |
446 | data.int_flags = 0; | 446 | data.int_flags = 0; |
447 | data.mounted_uid = md->mounted_uid; | 447 | data.mounted_uid = md->mounted_uid; |
448 | data.wdog_pid = md->wdog_pid; | 448 | data.wdog_pid = md->wdog_pid; |
449 | data.ncp_fd = md->ncp_fd; | 449 | data.ncp_fd = md->ncp_fd; |
450 | data.time_out = md->time_out; | 450 | data.time_out = md->time_out; |
451 | data.retry_count = md->retry_count; | 451 | data.retry_count = md->retry_count; |
452 | data.uid = md->uid; | 452 | data.uid = md->uid; |
453 | data.gid = md->gid; | 453 | data.gid = md->gid; |
454 | data.file_mode = md->file_mode; | 454 | data.file_mode = md->file_mode; |
455 | data.dir_mode = md->dir_mode; | 455 | data.dir_mode = md->dir_mode; |
456 | data.info_fd = -1; | 456 | data.info_fd = -1; |
457 | data.mounted_vol[0] = 0; | 457 | data.mounted_vol[0] = 0; |
458 | } | 458 | } |
459 | break; | 459 | break; |
460 | default: | 460 | default: |
461 | error = -ECHRNG; | 461 | error = -ECHRNG; |
462 | if (memcmp(raw_data, "vers", 4) == 0) { | 462 | if (memcmp(raw_data, "vers", 4) == 0) { |
463 | error = ncp_parse_options(&data, raw_data); | 463 | error = ncp_parse_options(&data, raw_data); |
464 | } | 464 | } |
465 | if (error) | 465 | if (error) |
466 | goto out; | 466 | goto out; |
467 | break; | 467 | break; |
468 | } | 468 | } |
469 | error = -EBADF; | 469 | error = -EBADF; |
470 | ncp_filp = fget(data.ncp_fd); | 470 | ncp_filp = fget(data.ncp_fd); |
471 | if (!ncp_filp) | 471 | if (!ncp_filp) |
472 | goto out; | 472 | goto out; |
473 | error = -ENOTSOCK; | 473 | error = -ENOTSOCK; |
474 | sock_inode = ncp_filp->f_dentry->d_inode; | 474 | sock_inode = ncp_filp->f_path.dentry->d_inode; |
475 | if (!S_ISSOCK(sock_inode->i_mode)) | 475 | if (!S_ISSOCK(sock_inode->i_mode)) |
476 | goto out_fput; | 476 | goto out_fput; |
477 | sock = SOCKET_I(sock_inode); | 477 | sock = SOCKET_I(sock_inode); |
478 | if (!sock) | 478 | if (!sock) |
479 | goto out_fput; | 479 | goto out_fput; |
480 | 480 | ||
481 | if (sock->type == SOCK_STREAM) | 481 | if (sock->type == SOCK_STREAM) |
482 | default_bufsize = 0xF000; | 482 | default_bufsize = 0xF000; |
483 | else | 483 | else |
484 | default_bufsize = 1024; | 484 | default_bufsize = 1024; |
485 | 485 | ||
486 | sb->s_flags |= MS_NODIRATIME; /* probably even noatime */ | 486 | sb->s_flags |= MS_NODIRATIME; /* probably even noatime */ |
487 | sb->s_maxbytes = 0xFFFFFFFFU; | 487 | sb->s_maxbytes = 0xFFFFFFFFU; |
488 | sb->s_blocksize = 1024; /* Eh... Is this correct? */ | 488 | sb->s_blocksize = 1024; /* Eh... Is this correct? */ |
489 | sb->s_blocksize_bits = 10; | 489 | sb->s_blocksize_bits = 10; |
490 | sb->s_magic = NCP_SUPER_MAGIC; | 490 | sb->s_magic = NCP_SUPER_MAGIC; |
491 | sb->s_op = &ncp_sops; | 491 | sb->s_op = &ncp_sops; |
492 | 492 | ||
493 | server = NCP_SBP(sb); | 493 | server = NCP_SBP(sb); |
494 | memset(server, 0, sizeof(*server)); | 494 | memset(server, 0, sizeof(*server)); |
495 | 495 | ||
496 | server->ncp_filp = ncp_filp; | 496 | server->ncp_filp = ncp_filp; |
497 | server->ncp_sock = sock; | 497 | server->ncp_sock = sock; |
498 | 498 | ||
499 | if (data.info_fd != -1) { | 499 | if (data.info_fd != -1) { |
500 | struct socket *info_sock; | 500 | struct socket *info_sock; |
501 | 501 | ||
502 | error = -EBADF; | 502 | error = -EBADF; |
503 | server->info_filp = fget(data.info_fd); | 503 | server->info_filp = fget(data.info_fd); |
504 | if (!server->info_filp) | 504 | if (!server->info_filp) |
505 | goto out_fput; | 505 | goto out_fput; |
506 | error = -ENOTSOCK; | 506 | error = -ENOTSOCK; |
507 | sock_inode = server->info_filp->f_dentry->d_inode; | 507 | sock_inode = server->info_filp->f_path.dentry->d_inode; |
508 | if (!S_ISSOCK(sock_inode->i_mode)) | 508 | if (!S_ISSOCK(sock_inode->i_mode)) |
509 | goto out_fput2; | 509 | goto out_fput2; |
510 | info_sock = SOCKET_I(sock_inode); | 510 | info_sock = SOCKET_I(sock_inode); |
511 | if (!info_sock) | 511 | if (!info_sock) |
512 | goto out_fput2; | 512 | goto out_fput2; |
513 | error = -EBADFD; | 513 | error = -EBADFD; |
514 | if (info_sock->type != SOCK_STREAM) | 514 | if (info_sock->type != SOCK_STREAM) |
515 | goto out_fput2; | 515 | goto out_fput2; |
516 | server->info_sock = info_sock; | 516 | server->info_sock = info_sock; |
517 | } | 517 | } |
518 | 518 | ||
519 | /* server->lock = 0; */ | 519 | /* server->lock = 0; */ |
520 | mutex_init(&server->mutex); | 520 | mutex_init(&server->mutex); |
521 | server->packet = NULL; | 521 | server->packet = NULL; |
522 | /* server->buffer_size = 0; */ | 522 | /* server->buffer_size = 0; */ |
523 | /* server->conn_status = 0; */ | 523 | /* server->conn_status = 0; */ |
524 | /* server->root_dentry = NULL; */ | 524 | /* server->root_dentry = NULL; */ |
525 | /* server->root_setuped = 0; */ | 525 | /* server->root_setuped = 0; */ |
526 | #ifdef CONFIG_NCPFS_PACKET_SIGNING | 526 | #ifdef CONFIG_NCPFS_PACKET_SIGNING |
527 | /* server->sign_wanted = 0; */ | 527 | /* server->sign_wanted = 0; */ |
528 | /* server->sign_active = 0; */ | 528 | /* server->sign_active = 0; */ |
529 | #endif | 529 | #endif |
530 | server->auth.auth_type = NCP_AUTH_NONE; | 530 | server->auth.auth_type = NCP_AUTH_NONE; |
531 | /* server->auth.object_name_len = 0; */ | 531 | /* server->auth.object_name_len = 0; */ |
532 | /* server->auth.object_name = NULL; */ | 532 | /* server->auth.object_name = NULL; */ |
533 | /* server->auth.object_type = 0; */ | 533 | /* server->auth.object_type = 0; */ |
534 | /* server->priv.len = 0; */ | 534 | /* server->priv.len = 0; */ |
535 | /* server->priv.data = NULL; */ | 535 | /* server->priv.data = NULL; */ |
536 | 536 | ||
537 | server->m = data; | 537 | server->m = data; |
538 | /* Althought anything producing this is buggy, it happens | 538 | /* Althought anything producing this is buggy, it happens |
539 | now because of PATH_MAX changes.. */ | 539 | now because of PATH_MAX changes.. */ |
540 | if (server->m.time_out < 1) { | 540 | if (server->m.time_out < 1) { |
541 | server->m.time_out = 10; | 541 | server->m.time_out = 10; |
542 | printk(KERN_INFO "You need to recompile your ncpfs utils..\n"); | 542 | printk(KERN_INFO "You need to recompile your ncpfs utils..\n"); |
543 | } | 543 | } |
544 | server->m.time_out = server->m.time_out * HZ / 100; | 544 | server->m.time_out = server->m.time_out * HZ / 100; |
545 | server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG; | 545 | server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG; |
546 | server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR; | 546 | server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR; |
547 | 547 | ||
548 | #ifdef CONFIG_NCPFS_NLS | 548 | #ifdef CONFIG_NCPFS_NLS |
549 | /* load the default NLS charsets */ | 549 | /* load the default NLS charsets */ |
550 | server->nls_vol = load_nls_default(); | 550 | server->nls_vol = load_nls_default(); |
551 | server->nls_io = load_nls_default(); | 551 | server->nls_io = load_nls_default(); |
552 | #endif /* CONFIG_NCPFS_NLS */ | 552 | #endif /* CONFIG_NCPFS_NLS */ |
553 | 553 | ||
554 | server->dentry_ttl = 0; /* no caching */ | 554 | server->dentry_ttl = 0; /* no caching */ |
555 | 555 | ||
556 | INIT_LIST_HEAD(&server->tx.requests); | 556 | INIT_LIST_HEAD(&server->tx.requests); |
557 | mutex_init(&server->rcv.creq_mutex); | 557 | mutex_init(&server->rcv.creq_mutex); |
558 | server->tx.creq = NULL; | 558 | server->tx.creq = NULL; |
559 | server->rcv.creq = NULL; | 559 | server->rcv.creq = NULL; |
560 | server->data_ready = sock->sk->sk_data_ready; | 560 | server->data_ready = sock->sk->sk_data_ready; |
561 | server->write_space = sock->sk->sk_write_space; | 561 | server->write_space = sock->sk->sk_write_space; |
562 | server->error_report = sock->sk->sk_error_report; | 562 | server->error_report = sock->sk->sk_error_report; |
563 | sock->sk->sk_user_data = server; | 563 | sock->sk->sk_user_data = server; |
564 | 564 | ||
565 | init_timer(&server->timeout_tm); | 565 | init_timer(&server->timeout_tm); |
566 | #undef NCP_PACKET_SIZE | 566 | #undef NCP_PACKET_SIZE |
567 | #define NCP_PACKET_SIZE 131072 | 567 | #define NCP_PACKET_SIZE 131072 |
568 | error = -ENOMEM; | 568 | error = -ENOMEM; |
569 | server->packet_size = NCP_PACKET_SIZE; | 569 | server->packet_size = NCP_PACKET_SIZE; |
570 | server->packet = vmalloc(NCP_PACKET_SIZE); | 570 | server->packet = vmalloc(NCP_PACKET_SIZE); |
571 | if (server->packet == NULL) | 571 | if (server->packet == NULL) |
572 | goto out_nls; | 572 | goto out_nls; |
573 | 573 | ||
574 | sock->sk->sk_data_ready = ncp_tcp_data_ready; | 574 | sock->sk->sk_data_ready = ncp_tcp_data_ready; |
575 | sock->sk->sk_error_report = ncp_tcp_error_report; | 575 | sock->sk->sk_error_report = ncp_tcp_error_report; |
576 | if (sock->type == SOCK_STREAM) { | 576 | if (sock->type == SOCK_STREAM) { |
577 | server->rcv.ptr = (unsigned char*)&server->rcv.buf; | 577 | server->rcv.ptr = (unsigned char*)&server->rcv.buf; |
578 | server->rcv.len = 10; | 578 | server->rcv.len = 10; |
579 | server->rcv.state = 0; | 579 | server->rcv.state = 0; |
580 | INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc); | 580 | INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc); |
581 | INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc); | 581 | INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc); |
582 | sock->sk->sk_write_space = ncp_tcp_write_space; | 582 | sock->sk->sk_write_space = ncp_tcp_write_space; |
583 | } else { | 583 | } else { |
584 | INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc); | 584 | INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc); |
585 | INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc); | 585 | INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc); |
586 | server->timeout_tm.data = (unsigned long)server; | 586 | server->timeout_tm.data = (unsigned long)server; |
587 | server->timeout_tm.function = ncpdgram_timeout_call; | 587 | server->timeout_tm.function = ncpdgram_timeout_call; |
588 | } | 588 | } |
589 | 589 | ||
590 | ncp_lock_server(server); | 590 | ncp_lock_server(server); |
591 | error = ncp_connect(server); | 591 | error = ncp_connect(server); |
592 | ncp_unlock_server(server); | 592 | ncp_unlock_server(server); |
593 | if (error < 0) | 593 | if (error < 0) |
594 | goto out_packet; | 594 | goto out_packet; |
595 | DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb)); | 595 | DPRINTK("ncp_fill_super: NCP_SBP(sb) = %x\n", (int) NCP_SBP(sb)); |
596 | 596 | ||
597 | error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */ | 597 | error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */ |
598 | #ifdef CONFIG_NCPFS_PACKET_SIGNING | 598 | #ifdef CONFIG_NCPFS_PACKET_SIGNING |
599 | if (ncp_negotiate_size_and_options(server, default_bufsize, | 599 | if (ncp_negotiate_size_and_options(server, default_bufsize, |
600 | NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0) | 600 | NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0) |
601 | { | 601 | { |
602 | if (options != NCP_DEFAULT_OPTIONS) | 602 | if (options != NCP_DEFAULT_OPTIONS) |
603 | { | 603 | { |
604 | if (ncp_negotiate_size_and_options(server, | 604 | if (ncp_negotiate_size_and_options(server, |
605 | default_bufsize, | 605 | default_bufsize, |
606 | options & 2, | 606 | options & 2, |
607 | &(server->buffer_size), &options) != 0) | 607 | &(server->buffer_size), &options) != 0) |
608 | 608 | ||
609 | { | 609 | { |
610 | goto out_disconnect; | 610 | goto out_disconnect; |
611 | } | 611 | } |
612 | } | 612 | } |
613 | if (options & 2) | 613 | if (options & 2) |
614 | server->sign_wanted = 1; | 614 | server->sign_wanted = 1; |
615 | } | 615 | } |
616 | else | 616 | else |
617 | #endif /* CONFIG_NCPFS_PACKET_SIGNING */ | 617 | #endif /* CONFIG_NCPFS_PACKET_SIGNING */ |
618 | if (ncp_negotiate_buffersize(server, default_bufsize, | 618 | if (ncp_negotiate_buffersize(server, default_bufsize, |
619 | &(server->buffer_size)) != 0) | 619 | &(server->buffer_size)) != 0) |
620 | goto out_disconnect; | 620 | goto out_disconnect; |
621 | DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size); | 621 | DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size); |
622 | 622 | ||
623 | memset(&finfo, 0, sizeof(finfo)); | 623 | memset(&finfo, 0, sizeof(finfo)); |
624 | finfo.i.attributes = aDIR; | 624 | finfo.i.attributes = aDIR; |
625 | finfo.i.dataStreamSize = 0; /* ignored */ | 625 | finfo.i.dataStreamSize = 0; /* ignored */ |
626 | finfo.i.dirEntNum = 0; | 626 | finfo.i.dirEntNum = 0; |
627 | finfo.i.DosDirNum = 0; | 627 | finfo.i.DosDirNum = 0; |
628 | #ifdef CONFIG_NCPFS_SMALLDOS | 628 | #ifdef CONFIG_NCPFS_SMALLDOS |
629 | finfo.i.NSCreator = NW_NS_DOS; | 629 | finfo.i.NSCreator = NW_NS_DOS; |
630 | #endif | 630 | #endif |
631 | finfo.volume = NCP_NUMBER_OF_VOLUMES; | 631 | finfo.volume = NCP_NUMBER_OF_VOLUMES; |
632 | /* set dates of mountpoint to Jan 1, 1986; 00:00 */ | 632 | /* set dates of mountpoint to Jan 1, 1986; 00:00 */ |
633 | finfo.i.creationTime = finfo.i.modifyTime | 633 | finfo.i.creationTime = finfo.i.modifyTime |
634 | = cpu_to_le16(0x0000); | 634 | = cpu_to_le16(0x0000); |
635 | finfo.i.creationDate = finfo.i.modifyDate | 635 | finfo.i.creationDate = finfo.i.modifyDate |
636 | = finfo.i.lastAccessDate | 636 | = finfo.i.lastAccessDate |
637 | = cpu_to_le16(0x0C21); | 637 | = cpu_to_le16(0x0C21); |
638 | finfo.i.nameLen = 0; | 638 | finfo.i.nameLen = 0; |
639 | finfo.i.entryName[0] = '\0'; | 639 | finfo.i.entryName[0] = '\0'; |
640 | 640 | ||
641 | finfo.opened = 0; | 641 | finfo.opened = 0; |
642 | finfo.ino = 2; /* tradition */ | 642 | finfo.ino = 2; /* tradition */ |
643 | 643 | ||
644 | server->name_space[finfo.volume] = NW_NS_DOS; | 644 | server->name_space[finfo.volume] = NW_NS_DOS; |
645 | 645 | ||
646 | error = -ENOMEM; | 646 | error = -ENOMEM; |
647 | root_inode = ncp_iget(sb, &finfo); | 647 | root_inode = ncp_iget(sb, &finfo); |
648 | if (!root_inode) | 648 | if (!root_inode) |
649 | goto out_disconnect; | 649 | goto out_disconnect; |
650 | DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber); | 650 | DPRINTK("ncp_fill_super: root vol=%d\n", NCP_FINFO(root_inode)->volNumber); |
651 | sb->s_root = d_alloc_root(root_inode); | 651 | sb->s_root = d_alloc_root(root_inode); |
652 | if (!sb->s_root) | 652 | if (!sb->s_root) |
653 | goto out_no_root; | 653 | goto out_no_root; |
654 | sb->s_root->d_op = &ncp_root_dentry_operations; | 654 | sb->s_root->d_op = &ncp_root_dentry_operations; |
655 | return 0; | 655 | return 0; |
656 | 656 | ||
657 | out_no_root: | 657 | out_no_root: |
658 | iput(root_inode); | 658 | iput(root_inode); |
659 | out_disconnect: | 659 | out_disconnect: |
660 | ncp_lock_server(server); | 660 | ncp_lock_server(server); |
661 | ncp_disconnect(server); | 661 | ncp_disconnect(server); |
662 | ncp_unlock_server(server); | 662 | ncp_unlock_server(server); |
663 | out_packet: | 663 | out_packet: |
664 | ncp_stop_tasks(server); | 664 | ncp_stop_tasks(server); |
665 | vfree(server->packet); | 665 | vfree(server->packet); |
666 | out_nls: | 666 | out_nls: |
667 | #ifdef CONFIG_NCPFS_NLS | 667 | #ifdef CONFIG_NCPFS_NLS |
668 | unload_nls(server->nls_io); | 668 | unload_nls(server->nls_io); |
669 | unload_nls(server->nls_vol); | 669 | unload_nls(server->nls_vol); |
670 | #endif | 670 | #endif |
671 | out_fput2: | 671 | out_fput2: |
672 | if (server->info_filp) | 672 | if (server->info_filp) |
673 | fput(server->info_filp); | 673 | fput(server->info_filp); |
674 | out_fput: | 674 | out_fput: |
675 | /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>: | 675 | /* 23/12/1998 Marcin Dalecki <dalecki@cs.net.pl>: |
676 | * | 676 | * |
677 | * The previously used put_filp(ncp_filp); was bogous, since | 677 | * The previously used put_filp(ncp_filp); was bogous, since |
678 | * it doesn't proper unlocking. | 678 | * it doesn't proper unlocking. |
679 | */ | 679 | */ |
680 | fput(ncp_filp); | 680 | fput(ncp_filp); |
681 | out: | 681 | out: |
682 | sb->s_fs_info = NULL; | 682 | sb->s_fs_info = NULL; |
683 | kfree(server); | 683 | kfree(server); |
684 | return error; | 684 | return error; |
685 | } | 685 | } |
686 | 686 | ||
687 | static void ncp_put_super(struct super_block *sb) | 687 | static void ncp_put_super(struct super_block *sb) |
688 | { | 688 | { |
689 | struct ncp_server *server = NCP_SBP(sb); | 689 | struct ncp_server *server = NCP_SBP(sb); |
690 | 690 | ||
691 | ncp_lock_server(server); | 691 | ncp_lock_server(server); |
692 | ncp_disconnect(server); | 692 | ncp_disconnect(server); |
693 | ncp_unlock_server(server); | 693 | ncp_unlock_server(server); |
694 | 694 | ||
695 | ncp_stop_tasks(server); | 695 | ncp_stop_tasks(server); |
696 | 696 | ||
697 | #ifdef CONFIG_NCPFS_NLS | 697 | #ifdef CONFIG_NCPFS_NLS |
698 | /* unload the NLS charsets */ | 698 | /* unload the NLS charsets */ |
699 | if (server->nls_vol) | 699 | if (server->nls_vol) |
700 | { | 700 | { |
701 | unload_nls(server->nls_vol); | 701 | unload_nls(server->nls_vol); |
702 | server->nls_vol = NULL; | 702 | server->nls_vol = NULL; |
703 | } | 703 | } |
704 | if (server->nls_io) | 704 | if (server->nls_io) |
705 | { | 705 | { |
706 | unload_nls(server->nls_io); | 706 | unload_nls(server->nls_io); |
707 | server->nls_io = NULL; | 707 | server->nls_io = NULL; |
708 | } | 708 | } |
709 | #endif /* CONFIG_NCPFS_NLS */ | 709 | #endif /* CONFIG_NCPFS_NLS */ |
710 | 710 | ||
711 | if (server->info_filp) | 711 | if (server->info_filp) |
712 | fput(server->info_filp); | 712 | fput(server->info_filp); |
713 | fput(server->ncp_filp); | 713 | fput(server->ncp_filp); |
714 | kill_proc(server->m.wdog_pid, SIGTERM, 1); | 714 | kill_proc(server->m.wdog_pid, SIGTERM, 1); |
715 | 715 | ||
716 | kfree(server->priv.data); | 716 | kfree(server->priv.data); |
717 | kfree(server->auth.object_name); | 717 | kfree(server->auth.object_name); |
718 | vfree(server->packet); | 718 | vfree(server->packet); |
719 | sb->s_fs_info = NULL; | 719 | sb->s_fs_info = NULL; |
720 | kfree(server); | 720 | kfree(server); |
721 | } | 721 | } |
722 | 722 | ||
723 | static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf) | 723 | static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf) |
724 | { | 724 | { |
725 | struct dentry* d; | 725 | struct dentry* d; |
726 | struct inode* i; | 726 | struct inode* i; |
727 | struct ncp_inode_info* ni; | 727 | struct ncp_inode_info* ni; |
728 | struct ncp_server* s; | 728 | struct ncp_server* s; |
729 | struct ncp_volume_info vi; | 729 | struct ncp_volume_info vi; |
730 | struct super_block *sb = dentry->d_sb; | 730 | struct super_block *sb = dentry->d_sb; |
731 | int err; | 731 | int err; |
732 | __u8 dh; | 732 | __u8 dh; |
733 | 733 | ||
734 | d = sb->s_root; | 734 | d = sb->s_root; |
735 | if (!d) { | 735 | if (!d) { |
736 | goto dflt; | 736 | goto dflt; |
737 | } | 737 | } |
738 | i = d->d_inode; | 738 | i = d->d_inode; |
739 | if (!i) { | 739 | if (!i) { |
740 | goto dflt; | 740 | goto dflt; |
741 | } | 741 | } |
742 | ni = NCP_FINFO(i); | 742 | ni = NCP_FINFO(i); |
743 | if (!ni) { | 743 | if (!ni) { |
744 | goto dflt; | 744 | goto dflt; |
745 | } | 745 | } |
746 | s = NCP_SBP(sb); | 746 | s = NCP_SBP(sb); |
747 | if (!s) { | 747 | if (!s) { |
748 | goto dflt; | 748 | goto dflt; |
749 | } | 749 | } |
750 | if (!s->m.mounted_vol[0]) { | 750 | if (!s->m.mounted_vol[0]) { |
751 | goto dflt; | 751 | goto dflt; |
752 | } | 752 | } |
753 | 753 | ||
754 | err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh); | 754 | err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh); |
755 | if (err) { | 755 | if (err) { |
756 | goto dflt; | 756 | goto dflt; |
757 | } | 757 | } |
758 | err = ncp_get_directory_info(s, dh, &vi); | 758 | err = ncp_get_directory_info(s, dh, &vi); |
759 | ncp_dirhandle_free(s, dh); | 759 | ncp_dirhandle_free(s, dh); |
760 | if (err) { | 760 | if (err) { |
761 | goto dflt; | 761 | goto dflt; |
762 | } | 762 | } |
763 | buf->f_type = NCP_SUPER_MAGIC; | 763 | buf->f_type = NCP_SUPER_MAGIC; |
764 | buf->f_bsize = vi.sectors_per_block * 512; | 764 | buf->f_bsize = vi.sectors_per_block * 512; |
765 | buf->f_blocks = vi.total_blocks; | 765 | buf->f_blocks = vi.total_blocks; |
766 | buf->f_bfree = vi.free_blocks; | 766 | buf->f_bfree = vi.free_blocks; |
767 | buf->f_bavail = vi.free_blocks; | 767 | buf->f_bavail = vi.free_blocks; |
768 | buf->f_files = vi.total_dir_entries; | 768 | buf->f_files = vi.total_dir_entries; |
769 | buf->f_ffree = vi.available_dir_entries; | 769 | buf->f_ffree = vi.available_dir_entries; |
770 | buf->f_namelen = 12; | 770 | buf->f_namelen = 12; |
771 | return 0; | 771 | return 0; |
772 | 772 | ||
773 | /* We cannot say how much disk space is left on a mounted | 773 | /* We cannot say how much disk space is left on a mounted |
774 | NetWare Server, because free space is distributed over | 774 | NetWare Server, because free space is distributed over |
775 | volumes, and the current user might have disk quotas. So | 775 | volumes, and the current user might have disk quotas. So |
776 | free space is not that simple to determine. Our decision | 776 | free space is not that simple to determine. Our decision |
777 | here is to err conservatively. */ | 777 | here is to err conservatively. */ |
778 | 778 | ||
779 | dflt:; | 779 | dflt:; |
780 | buf->f_type = NCP_SUPER_MAGIC; | 780 | buf->f_type = NCP_SUPER_MAGIC; |
781 | buf->f_bsize = NCP_BLOCK_SIZE; | 781 | buf->f_bsize = NCP_BLOCK_SIZE; |
782 | buf->f_blocks = 0; | 782 | buf->f_blocks = 0; |
783 | buf->f_bfree = 0; | 783 | buf->f_bfree = 0; |
784 | buf->f_bavail = 0; | 784 | buf->f_bavail = 0; |
785 | buf->f_namelen = 12; | 785 | buf->f_namelen = 12; |
786 | return 0; | 786 | return 0; |
787 | } | 787 | } |
788 | 788 | ||
789 | int ncp_notify_change(struct dentry *dentry, struct iattr *attr) | 789 | int ncp_notify_change(struct dentry *dentry, struct iattr *attr) |
790 | { | 790 | { |
791 | struct inode *inode = dentry->d_inode; | 791 | struct inode *inode = dentry->d_inode; |
792 | int result = 0; | 792 | int result = 0; |
793 | __le32 info_mask; | 793 | __le32 info_mask; |
794 | struct nw_modify_dos_info info; | 794 | struct nw_modify_dos_info info; |
795 | struct ncp_server *server; | 795 | struct ncp_server *server; |
796 | 796 | ||
797 | result = -EIO; | 797 | result = -EIO; |
798 | 798 | ||
799 | lock_kernel(); | 799 | lock_kernel(); |
800 | 800 | ||
801 | server = NCP_SERVER(inode); | 801 | server = NCP_SERVER(inode); |
802 | if ((!server) || !ncp_conn_valid(server)) | 802 | if ((!server) || !ncp_conn_valid(server)) |
803 | goto out; | 803 | goto out; |
804 | 804 | ||
805 | /* ageing the dentry to force validation */ | 805 | /* ageing the dentry to force validation */ |
806 | ncp_age_dentry(server, dentry); | 806 | ncp_age_dentry(server, dentry); |
807 | 807 | ||
808 | result = inode_change_ok(inode, attr); | 808 | result = inode_change_ok(inode, attr); |
809 | if (result < 0) | 809 | if (result < 0) |
810 | goto out; | 810 | goto out; |
811 | 811 | ||
812 | result = -EPERM; | 812 | result = -EPERM; |
813 | if (((attr->ia_valid & ATTR_UID) && | 813 | if (((attr->ia_valid & ATTR_UID) && |
814 | (attr->ia_uid != server->m.uid))) | 814 | (attr->ia_uid != server->m.uid))) |
815 | goto out; | 815 | goto out; |
816 | 816 | ||
817 | if (((attr->ia_valid & ATTR_GID) && | 817 | if (((attr->ia_valid & ATTR_GID) && |
818 | (attr->ia_gid != server->m.gid))) | 818 | (attr->ia_gid != server->m.gid))) |
819 | goto out; | 819 | goto out; |
820 | 820 | ||
821 | if (((attr->ia_valid & ATTR_MODE) && | 821 | if (((attr->ia_valid & ATTR_MODE) && |
822 | (attr->ia_mode & | 822 | (attr->ia_mode & |
823 | ~(S_IFREG | S_IFDIR | S_IRWXUGO)))) | 823 | ~(S_IFREG | S_IFDIR | S_IRWXUGO)))) |
824 | goto out; | 824 | goto out; |
825 | 825 | ||
826 | info_mask = 0; | 826 | info_mask = 0; |
827 | memset(&info, 0, sizeof(info)); | 827 | memset(&info, 0, sizeof(info)); |
828 | 828 | ||
829 | #if 1 | 829 | #if 1 |
830 | if ((attr->ia_valid & ATTR_MODE) != 0) | 830 | if ((attr->ia_valid & ATTR_MODE) != 0) |
831 | { | 831 | { |
832 | umode_t newmode = attr->ia_mode; | 832 | umode_t newmode = attr->ia_mode; |
833 | 833 | ||
834 | info_mask |= DM_ATTRIBUTES; | 834 | info_mask |= DM_ATTRIBUTES; |
835 | 835 | ||
836 | if (S_ISDIR(inode->i_mode)) { | 836 | if (S_ISDIR(inode->i_mode)) { |
837 | newmode &= server->m.dir_mode; | 837 | newmode &= server->m.dir_mode; |
838 | } else { | 838 | } else { |
839 | #ifdef CONFIG_NCPFS_EXTRAS | 839 | #ifdef CONFIG_NCPFS_EXTRAS |
840 | if (server->m.flags & NCP_MOUNT_EXTRAS) { | 840 | if (server->m.flags & NCP_MOUNT_EXTRAS) { |
841 | /* any non-default execute bit set */ | 841 | /* any non-default execute bit set */ |
842 | if (newmode & ~server->m.file_mode & S_IXUGO) | 842 | if (newmode & ~server->m.file_mode & S_IXUGO) |
843 | info.attributes |= aSHARED | aSYSTEM; | 843 | info.attributes |= aSHARED | aSYSTEM; |
844 | /* read for group/world and not in default file_mode */ | 844 | /* read for group/world and not in default file_mode */ |
845 | else if (newmode & ~server->m.file_mode & S_IRUGO) | 845 | else if (newmode & ~server->m.file_mode & S_IRUGO) |
846 | info.attributes |= aSHARED; | 846 | info.attributes |= aSHARED; |
847 | } else | 847 | } else |
848 | #endif | 848 | #endif |
849 | newmode &= server->m.file_mode; | 849 | newmode &= server->m.file_mode; |
850 | } | 850 | } |
851 | if (newmode & S_IWUGO) | 851 | if (newmode & S_IWUGO) |
852 | info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); | 852 | info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); |
853 | else | 853 | else |
854 | info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); | 854 | info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT); |
855 | 855 | ||
856 | #ifdef CONFIG_NCPFS_NFS_NS | 856 | #ifdef CONFIG_NCPFS_NFS_NS |
857 | if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) { | 857 | if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) { |
858 | result = ncp_modify_nfs_info(server, | 858 | result = ncp_modify_nfs_info(server, |
859 | NCP_FINFO(inode)->volNumber, | 859 | NCP_FINFO(inode)->volNumber, |
860 | NCP_FINFO(inode)->dirEntNum, | 860 | NCP_FINFO(inode)->dirEntNum, |
861 | attr->ia_mode, 0); | 861 | attr->ia_mode, 0); |
862 | if (result != 0) | 862 | if (result != 0) |
863 | goto out; | 863 | goto out; |
864 | info.attributes &= ~(aSHARED | aSYSTEM); | 864 | info.attributes &= ~(aSHARED | aSYSTEM); |
865 | { | 865 | { |
866 | /* mark partial success */ | 866 | /* mark partial success */ |
867 | struct iattr tmpattr; | 867 | struct iattr tmpattr; |
868 | 868 | ||
869 | tmpattr.ia_valid = ATTR_MODE; | 869 | tmpattr.ia_valid = ATTR_MODE; |
870 | tmpattr.ia_mode = attr->ia_mode; | 870 | tmpattr.ia_mode = attr->ia_mode; |
871 | 871 | ||
872 | result = inode_setattr(inode, &tmpattr); | 872 | result = inode_setattr(inode, &tmpattr); |
873 | if (result) | 873 | if (result) |
874 | goto out; | 874 | goto out; |
875 | } | 875 | } |
876 | } | 876 | } |
877 | #endif | 877 | #endif |
878 | } | 878 | } |
879 | #endif | 879 | #endif |
880 | 880 | ||
881 | /* Do SIZE before attributes, otherwise mtime together with size does not work... | 881 | /* Do SIZE before attributes, otherwise mtime together with size does not work... |
882 | */ | 882 | */ |
883 | if ((attr->ia_valid & ATTR_SIZE) != 0) { | 883 | if ((attr->ia_valid & ATTR_SIZE) != 0) { |
884 | int written; | 884 | int written; |
885 | 885 | ||
886 | DPRINTK("ncpfs: trying to change size to %ld\n", | 886 | DPRINTK("ncpfs: trying to change size to %ld\n", |
887 | attr->ia_size); | 887 | attr->ia_size); |
888 | 888 | ||
889 | if ((result = ncp_make_open(inode, O_WRONLY)) < 0) { | 889 | if ((result = ncp_make_open(inode, O_WRONLY)) < 0) { |
890 | result = -EACCES; | 890 | result = -EACCES; |
891 | goto out; | 891 | goto out; |
892 | } | 892 | } |
893 | ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, | 893 | ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle, |
894 | attr->ia_size, 0, "", &written); | 894 | attr->ia_size, 0, "", &written); |
895 | 895 | ||
896 | /* According to ndir, the changes only take effect after | 896 | /* According to ndir, the changes only take effect after |
897 | closing the file */ | 897 | closing the file */ |
898 | ncp_inode_close(inode); | 898 | ncp_inode_close(inode); |
899 | result = ncp_make_closed(inode); | 899 | result = ncp_make_closed(inode); |
900 | if (result) | 900 | if (result) |
901 | goto out; | 901 | goto out; |
902 | { | 902 | { |
903 | struct iattr tmpattr; | 903 | struct iattr tmpattr; |
904 | 904 | ||
905 | tmpattr.ia_valid = ATTR_SIZE; | 905 | tmpattr.ia_valid = ATTR_SIZE; |
906 | tmpattr.ia_size = attr->ia_size; | 906 | tmpattr.ia_size = attr->ia_size; |
907 | 907 | ||
908 | result = inode_setattr(inode, &tmpattr); | 908 | result = inode_setattr(inode, &tmpattr); |
909 | if (result) | 909 | if (result) |
910 | goto out; | 910 | goto out; |
911 | } | 911 | } |
912 | } | 912 | } |
913 | if ((attr->ia_valid & ATTR_CTIME) != 0) { | 913 | if ((attr->ia_valid & ATTR_CTIME) != 0) { |
914 | info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE); | 914 | info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE); |
915 | ncp_date_unix2dos(attr->ia_ctime.tv_sec, | 915 | ncp_date_unix2dos(attr->ia_ctime.tv_sec, |
916 | &info.creationTime, &info.creationDate); | 916 | &info.creationTime, &info.creationDate); |
917 | } | 917 | } |
918 | if ((attr->ia_valid & ATTR_MTIME) != 0) { | 918 | if ((attr->ia_valid & ATTR_MTIME) != 0) { |
919 | info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE); | 919 | info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE); |
920 | ncp_date_unix2dos(attr->ia_mtime.tv_sec, | 920 | ncp_date_unix2dos(attr->ia_mtime.tv_sec, |
921 | &info.modifyTime, &info.modifyDate); | 921 | &info.modifyTime, &info.modifyDate); |
922 | } | 922 | } |
923 | if ((attr->ia_valid & ATTR_ATIME) != 0) { | 923 | if ((attr->ia_valid & ATTR_ATIME) != 0) { |
924 | __le16 dummy; | 924 | __le16 dummy; |
925 | info_mask |= (DM_LAST_ACCESS_DATE); | 925 | info_mask |= (DM_LAST_ACCESS_DATE); |
926 | ncp_date_unix2dos(attr->ia_atime.tv_sec, | 926 | ncp_date_unix2dos(attr->ia_atime.tv_sec, |
927 | &dummy, &info.lastAccessDate); | 927 | &dummy, &info.lastAccessDate); |
928 | } | 928 | } |
929 | if (info_mask != 0) { | 929 | if (info_mask != 0) { |
930 | result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode), | 930 | result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode), |
931 | inode, info_mask, &info); | 931 | inode, info_mask, &info); |
932 | if (result != 0) { | 932 | if (result != 0) { |
933 | result = -EACCES; | 933 | result = -EACCES; |
934 | 934 | ||
935 | if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) { | 935 | if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) { |
936 | /* NetWare seems not to allow this. I | 936 | /* NetWare seems not to allow this. I |
937 | do not know why. So, just tell the | 937 | do not know why. So, just tell the |
938 | user everything went fine. This is | 938 | user everything went fine. This is |
939 | a terrible hack, but I do not know | 939 | a terrible hack, but I do not know |
940 | how to do this correctly. */ | 940 | how to do this correctly. */ |
941 | result = 0; | 941 | result = 0; |
942 | } else | 942 | } else |
943 | goto out; | 943 | goto out; |
944 | } | 944 | } |
945 | #ifdef CONFIG_NCPFS_STRONG | 945 | #ifdef CONFIG_NCPFS_STRONG |
946 | if ((!result) && (info_mask & DM_ATTRIBUTES)) | 946 | if ((!result) && (info_mask & DM_ATTRIBUTES)) |
947 | NCP_FINFO(inode)->nwattr = info.attributes; | 947 | NCP_FINFO(inode)->nwattr = info.attributes; |
948 | #endif | 948 | #endif |
949 | } | 949 | } |
950 | if (!result) | 950 | if (!result) |
951 | result = inode_setattr(inode, attr); | 951 | result = inode_setattr(inode, attr); |
952 | out: | 952 | out: |
953 | unlock_kernel(); | 953 | unlock_kernel(); |
954 | return result; | 954 | return result; |
955 | } | 955 | } |
956 | 956 | ||
957 | static int ncp_get_sb(struct file_system_type *fs_type, | 957 | static int ncp_get_sb(struct file_system_type *fs_type, |
958 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) | 958 | int flags, const char *dev_name, void *data, struct vfsmount *mnt) |
959 | { | 959 | { |
960 | return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt); | 960 | return get_sb_nodev(fs_type, flags, data, ncp_fill_super, mnt); |
961 | } | 961 | } |
962 | 962 | ||
963 | static struct file_system_type ncp_fs_type = { | 963 | static struct file_system_type ncp_fs_type = { |
964 | .owner = THIS_MODULE, | 964 | .owner = THIS_MODULE, |
965 | .name = "ncpfs", | 965 | .name = "ncpfs", |
966 | .get_sb = ncp_get_sb, | 966 | .get_sb = ncp_get_sb, |
967 | .kill_sb = kill_anon_super, | 967 | .kill_sb = kill_anon_super, |
968 | }; | 968 | }; |
969 | 969 | ||
970 | static int __init init_ncp_fs(void) | 970 | static int __init init_ncp_fs(void) |
971 | { | 971 | { |
972 | int err; | 972 | int err; |
973 | DPRINTK("ncpfs: init_module called\n"); | 973 | DPRINTK("ncpfs: init_module called\n"); |
974 | 974 | ||
975 | err = init_inodecache(); | 975 | err = init_inodecache(); |
976 | if (err) | 976 | if (err) |
977 | goto out1; | 977 | goto out1; |
978 | err = register_filesystem(&ncp_fs_type); | 978 | err = register_filesystem(&ncp_fs_type); |
979 | if (err) | 979 | if (err) |
980 | goto out; | 980 | goto out; |
981 | return 0; | 981 | return 0; |
982 | out: | 982 | out: |
983 | destroy_inodecache(); | 983 | destroy_inodecache(); |
984 | out1: | 984 | out1: |
985 | return err; | 985 | return err; |
986 | } | 986 | } |
987 | 987 | ||
988 | static void __exit exit_ncp_fs(void) | 988 | static void __exit exit_ncp_fs(void) |
989 | { | 989 | { |
990 | DPRINTK("ncpfs: cleanup_module called\n"); | 990 | DPRINTK("ncpfs: cleanup_module called\n"); |
991 | unregister_filesystem(&ncp_fs_type); | 991 | unregister_filesystem(&ncp_fs_type); |
992 | destroy_inodecache(); | 992 | destroy_inodecache(); |
993 | } | 993 | } |
994 | 994 | ||
995 | module_init(init_ncp_fs) | 995 | module_init(init_ncp_fs) |
996 | module_exit(exit_ncp_fs) | 996 | module_exit(exit_ncp_fs) |
997 | MODULE_LICENSE("GPL"); | 997 | MODULE_LICENSE("GPL"); |
998 | 998 |
fs/ncpfs/ioctl.c
1 | /* | 1 | /* |
2 | * ioctl.c | 2 | * ioctl.c |
3 | * | 3 | * |
4 | * Copyright (C) 1995, 1996 by Volker Lendecke | 4 | * Copyright (C) 1995, 1996 by Volker Lendecke |
5 | * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache | 5 | * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache |
6 | * Modified 1998, 1999 Wolfram Pienkoss for NLS | 6 | * Modified 1998, 1999 Wolfram Pienkoss for NLS |
7 | * | 7 | * |
8 | */ | 8 | */ |
9 | 9 | ||
10 | #include <linux/capability.h> | 10 | #include <linux/capability.h> |
11 | #include <linux/compat.h> | 11 | #include <linux/compat.h> |
12 | #include <linux/errno.h> | 12 | #include <linux/errno.h> |
13 | #include <linux/fs.h> | 13 | #include <linux/fs.h> |
14 | #include <linux/ioctl.h> | 14 | #include <linux/ioctl.h> |
15 | #include <linux/time.h> | 15 | #include <linux/time.h> |
16 | #include <linux/mm.h> | 16 | #include <linux/mm.h> |
17 | #include <linux/highuid.h> | 17 | #include <linux/highuid.h> |
18 | #include <linux/smp_lock.h> | 18 | #include <linux/smp_lock.h> |
19 | #include <linux/vmalloc.h> | 19 | #include <linux/vmalloc.h> |
20 | 20 | ||
21 | #include <linux/ncp_fs.h> | 21 | #include <linux/ncp_fs.h> |
22 | 22 | ||
23 | #include <asm/uaccess.h> | 23 | #include <asm/uaccess.h> |
24 | 24 | ||
25 | #include "ncplib_kernel.h" | 25 | #include "ncplib_kernel.h" |
26 | 26 | ||
27 | /* maximum limit for ncp_objectname_ioctl */ | 27 | /* maximum limit for ncp_objectname_ioctl */ |
28 | #define NCP_OBJECT_NAME_MAX_LEN 4096 | 28 | #define NCP_OBJECT_NAME_MAX_LEN 4096 |
29 | /* maximum limit for ncp_privatedata_ioctl */ | 29 | /* maximum limit for ncp_privatedata_ioctl */ |
30 | #define NCP_PRIVATE_DATA_MAX_LEN 8192 | 30 | #define NCP_PRIVATE_DATA_MAX_LEN 8192 |
31 | /* maximum negotiable packet size */ | 31 | /* maximum negotiable packet size */ |
32 | #define NCP_PACKET_SIZE_INTERNAL 65536 | 32 | #define NCP_PACKET_SIZE_INTERNAL 65536 |
33 | 33 | ||
34 | static int | 34 | static int |
35 | ncp_get_fs_info(struct ncp_server * server, struct file *file, | 35 | ncp_get_fs_info(struct ncp_server * server, struct file *file, |
36 | struct ncp_fs_info __user *arg) | 36 | struct ncp_fs_info __user *arg) |
37 | { | 37 | { |
38 | struct inode *inode = file->f_dentry->d_inode; | 38 | struct inode *inode = file->f_path.dentry->d_inode; |
39 | struct ncp_fs_info info; | 39 | struct ncp_fs_info info; |
40 | 40 | ||
41 | if ((file_permission(file, MAY_WRITE) != 0) | 41 | if ((file_permission(file, MAY_WRITE) != 0) |
42 | && (current->uid != server->m.mounted_uid)) { | 42 | && (current->uid != server->m.mounted_uid)) { |
43 | return -EACCES; | 43 | return -EACCES; |
44 | } | 44 | } |
45 | if (copy_from_user(&info, arg, sizeof(info))) | 45 | if (copy_from_user(&info, arg, sizeof(info))) |
46 | return -EFAULT; | 46 | return -EFAULT; |
47 | 47 | ||
48 | if (info.version != NCP_GET_FS_INFO_VERSION) { | 48 | if (info.version != NCP_GET_FS_INFO_VERSION) { |
49 | DPRINTK("info.version invalid: %d\n", info.version); | 49 | DPRINTK("info.version invalid: %d\n", info.version); |
50 | return -EINVAL; | 50 | return -EINVAL; |
51 | } | 51 | } |
52 | /* TODO: info.addr = server->m.serv_addr; */ | 52 | /* TODO: info.addr = server->m.serv_addr; */ |
53 | SET_UID(info.mounted_uid, server->m.mounted_uid); | 53 | SET_UID(info.mounted_uid, server->m.mounted_uid); |
54 | info.connection = server->connection; | 54 | info.connection = server->connection; |
55 | info.buffer_size = server->buffer_size; | 55 | info.buffer_size = server->buffer_size; |
56 | info.volume_number = NCP_FINFO(inode)->volNumber; | 56 | info.volume_number = NCP_FINFO(inode)->volNumber; |
57 | info.directory_id = NCP_FINFO(inode)->DosDirNum; | 57 | info.directory_id = NCP_FINFO(inode)->DosDirNum; |
58 | 58 | ||
59 | if (copy_to_user(arg, &info, sizeof(info))) | 59 | if (copy_to_user(arg, &info, sizeof(info))) |
60 | return -EFAULT; | 60 | return -EFAULT; |
61 | return 0; | 61 | return 0; |
62 | } | 62 | } |
63 | 63 | ||
64 | static int | 64 | static int |
65 | ncp_get_fs_info_v2(struct ncp_server * server, struct file *file, | 65 | ncp_get_fs_info_v2(struct ncp_server * server, struct file *file, |
66 | struct ncp_fs_info_v2 __user * arg) | 66 | struct ncp_fs_info_v2 __user * arg) |
67 | { | 67 | { |
68 | struct inode *inode = file->f_dentry->d_inode; | 68 | struct inode *inode = file->f_path.dentry->d_inode; |
69 | struct ncp_fs_info_v2 info2; | 69 | struct ncp_fs_info_v2 info2; |
70 | 70 | ||
71 | if ((file_permission(file, MAY_WRITE) != 0) | 71 | if ((file_permission(file, MAY_WRITE) != 0) |
72 | && (current->uid != server->m.mounted_uid)) { | 72 | && (current->uid != server->m.mounted_uid)) { |
73 | return -EACCES; | 73 | return -EACCES; |
74 | } | 74 | } |
75 | if (copy_from_user(&info2, arg, sizeof(info2))) | 75 | if (copy_from_user(&info2, arg, sizeof(info2))) |
76 | return -EFAULT; | 76 | return -EFAULT; |
77 | 77 | ||
78 | if (info2.version != NCP_GET_FS_INFO_VERSION_V2) { | 78 | if (info2.version != NCP_GET_FS_INFO_VERSION_V2) { |
79 | DPRINTK("info.version invalid: %d\n", info2.version); | 79 | DPRINTK("info.version invalid: %d\n", info2.version); |
80 | return -EINVAL; | 80 | return -EINVAL; |
81 | } | 81 | } |
82 | info2.mounted_uid = server->m.mounted_uid; | 82 | info2.mounted_uid = server->m.mounted_uid; |
83 | info2.connection = server->connection; | 83 | info2.connection = server->connection; |
84 | info2.buffer_size = server->buffer_size; | 84 | info2.buffer_size = server->buffer_size; |
85 | info2.volume_number = NCP_FINFO(inode)->volNumber; | 85 | info2.volume_number = NCP_FINFO(inode)->volNumber; |
86 | info2.directory_id = NCP_FINFO(inode)->DosDirNum; | 86 | info2.directory_id = NCP_FINFO(inode)->DosDirNum; |
87 | info2.dummy1 = info2.dummy2 = info2.dummy3 = 0; | 87 | info2.dummy1 = info2.dummy2 = info2.dummy3 = 0; |
88 | 88 | ||
89 | if (copy_to_user(arg, &info2, sizeof(info2))) | 89 | if (copy_to_user(arg, &info2, sizeof(info2))) |
90 | return -EFAULT; | 90 | return -EFAULT; |
91 | return 0; | 91 | return 0; |
92 | } | 92 | } |
93 | 93 | ||
94 | #ifdef CONFIG_COMPAT | 94 | #ifdef CONFIG_COMPAT |
95 | struct compat_ncp_objectname_ioctl | 95 | struct compat_ncp_objectname_ioctl |
96 | { | 96 | { |
97 | s32 auth_type; | 97 | s32 auth_type; |
98 | u32 object_name_len; | 98 | u32 object_name_len; |
99 | compat_caddr_t object_name; /* an userspace data, in most cases user name */ | 99 | compat_caddr_t object_name; /* an userspace data, in most cases user name */ |
100 | }; | 100 | }; |
101 | 101 | ||
102 | struct compat_ncp_fs_info_v2 { | 102 | struct compat_ncp_fs_info_v2 { |
103 | s32 version; | 103 | s32 version; |
104 | u32 mounted_uid; | 104 | u32 mounted_uid; |
105 | u32 connection; | 105 | u32 connection; |
106 | u32 buffer_size; | 106 | u32 buffer_size; |
107 | 107 | ||
108 | u32 volume_number; | 108 | u32 volume_number; |
109 | u32 directory_id; | 109 | u32 directory_id; |
110 | 110 | ||
111 | u32 dummy1; | 111 | u32 dummy1; |
112 | u32 dummy2; | 112 | u32 dummy2; |
113 | u32 dummy3; | 113 | u32 dummy3; |
114 | }; | 114 | }; |
115 | 115 | ||
116 | struct compat_ncp_ioctl_request { | 116 | struct compat_ncp_ioctl_request { |
117 | u32 function; | 117 | u32 function; |
118 | u32 size; | 118 | u32 size; |
119 | compat_caddr_t data; | 119 | compat_caddr_t data; |
120 | }; | 120 | }; |
121 | 121 | ||
122 | struct compat_ncp_privatedata_ioctl | 122 | struct compat_ncp_privatedata_ioctl |
123 | { | 123 | { |
124 | u32 len; | 124 | u32 len; |
125 | compat_caddr_t data; /* ~1000 for NDS */ | 125 | compat_caddr_t data; /* ~1000 for NDS */ |
126 | }; | 126 | }; |
127 | 127 | ||
128 | #define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct compat_ncp_fs_info_v2) | 128 | #define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct compat_ncp_fs_info_v2) |
129 | #define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct compat_ncp_ioctl_request) | 129 | #define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct compat_ncp_ioctl_request) |
130 | #define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct compat_ncp_objectname_ioctl) | 130 | #define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct compat_ncp_objectname_ioctl) |
131 | #define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct compat_ncp_objectname_ioctl) | 131 | #define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct compat_ncp_objectname_ioctl) |
132 | #define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct compat_ncp_privatedata_ioctl) | 132 | #define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct compat_ncp_privatedata_ioctl) |
133 | #define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl) | 133 | #define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl) |
134 | 134 | ||
135 | static int | 135 | static int |
136 | ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file, | 136 | ncp_get_compat_fs_info_v2(struct ncp_server * server, struct file *file, |
137 | struct compat_ncp_fs_info_v2 __user * arg) | 137 | struct compat_ncp_fs_info_v2 __user * arg) |
138 | { | 138 | { |
139 | struct inode *inode = file->f_dentry->d_inode; | 139 | struct inode *inode = file->f_path.dentry->d_inode; |
140 | struct compat_ncp_fs_info_v2 info2; | 140 | struct compat_ncp_fs_info_v2 info2; |
141 | 141 | ||
142 | if ((file_permission(file, MAY_WRITE) != 0) | 142 | if ((file_permission(file, MAY_WRITE) != 0) |
143 | && (current->uid != server->m.mounted_uid)) { | 143 | && (current->uid != server->m.mounted_uid)) { |
144 | return -EACCES; | 144 | return -EACCES; |
145 | } | 145 | } |
146 | if (copy_from_user(&info2, arg, sizeof(info2))) | 146 | if (copy_from_user(&info2, arg, sizeof(info2))) |
147 | return -EFAULT; | 147 | return -EFAULT; |
148 | 148 | ||
149 | if (info2.version != NCP_GET_FS_INFO_VERSION_V2) { | 149 | if (info2.version != NCP_GET_FS_INFO_VERSION_V2) { |
150 | DPRINTK("info.version invalid: %d\n", info2.version); | 150 | DPRINTK("info.version invalid: %d\n", info2.version); |
151 | return -EINVAL; | 151 | return -EINVAL; |
152 | } | 152 | } |
153 | info2.mounted_uid = server->m.mounted_uid; | 153 | info2.mounted_uid = server->m.mounted_uid; |
154 | info2.connection = server->connection; | 154 | info2.connection = server->connection; |
155 | info2.buffer_size = server->buffer_size; | 155 | info2.buffer_size = server->buffer_size; |
156 | info2.volume_number = NCP_FINFO(inode)->volNumber; | 156 | info2.volume_number = NCP_FINFO(inode)->volNumber; |
157 | info2.directory_id = NCP_FINFO(inode)->DosDirNum; | 157 | info2.directory_id = NCP_FINFO(inode)->DosDirNum; |
158 | info2.dummy1 = info2.dummy2 = info2.dummy3 = 0; | 158 | info2.dummy1 = info2.dummy2 = info2.dummy3 = 0; |
159 | 159 | ||
160 | if (copy_to_user(arg, &info2, sizeof(info2))) | 160 | if (copy_to_user(arg, &info2, sizeof(info2))) |
161 | return -EFAULT; | 161 | return -EFAULT; |
162 | return 0; | 162 | return 0; |
163 | } | 163 | } |
164 | #endif | 164 | #endif |
165 | 165 | ||
166 | #define NCP_IOC_GETMOUNTUID16 _IOW('n', 2, u16) | 166 | #define NCP_IOC_GETMOUNTUID16 _IOW('n', 2, u16) |
167 | #define NCP_IOC_GETMOUNTUID32 _IOW('n', 2, u32) | 167 | #define NCP_IOC_GETMOUNTUID32 _IOW('n', 2, u32) |
168 | #define NCP_IOC_GETMOUNTUID64 _IOW('n', 2, u64) | 168 | #define NCP_IOC_GETMOUNTUID64 _IOW('n', 2, u64) |
169 | 169 | ||
170 | #ifdef CONFIG_NCPFS_NLS | 170 | #ifdef CONFIG_NCPFS_NLS |
171 | /* Here we are select the iocharset and the codepage for NLS. | 171 | /* Here we are select the iocharset and the codepage for NLS. |
172 | * Thanks Petr Vandrovec for idea and many hints. | 172 | * Thanks Petr Vandrovec for idea and many hints. |
173 | */ | 173 | */ |
174 | static int | 174 | static int |
175 | ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) | 175 | ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) |
176 | { | 176 | { |
177 | struct ncp_nls_ioctl user; | 177 | struct ncp_nls_ioctl user; |
178 | struct nls_table *codepage; | 178 | struct nls_table *codepage; |
179 | struct nls_table *iocharset; | 179 | struct nls_table *iocharset; |
180 | struct nls_table *oldset_io; | 180 | struct nls_table *oldset_io; |
181 | struct nls_table *oldset_cp; | 181 | struct nls_table *oldset_cp; |
182 | 182 | ||
183 | if (!capable(CAP_SYS_ADMIN)) | 183 | if (!capable(CAP_SYS_ADMIN)) |
184 | return -EACCES; | 184 | return -EACCES; |
185 | if (server->root_setuped) | 185 | if (server->root_setuped) |
186 | return -EBUSY; | 186 | return -EBUSY; |
187 | 187 | ||
188 | if (copy_from_user(&user, arg, sizeof(user))) | 188 | if (copy_from_user(&user, arg, sizeof(user))) |
189 | return -EFAULT; | 189 | return -EFAULT; |
190 | 190 | ||
191 | codepage = NULL; | 191 | codepage = NULL; |
192 | user.codepage[NCP_IOCSNAME_LEN] = 0; | 192 | user.codepage[NCP_IOCSNAME_LEN] = 0; |
193 | if (!user.codepage[0] || !strcmp(user.codepage, "default")) | 193 | if (!user.codepage[0] || !strcmp(user.codepage, "default")) |
194 | codepage = load_nls_default(); | 194 | codepage = load_nls_default(); |
195 | else { | 195 | else { |
196 | codepage = load_nls(user.codepage); | 196 | codepage = load_nls(user.codepage); |
197 | if (!codepage) { | 197 | if (!codepage) { |
198 | return -EBADRQC; | 198 | return -EBADRQC; |
199 | } | 199 | } |
200 | } | 200 | } |
201 | 201 | ||
202 | iocharset = NULL; | 202 | iocharset = NULL; |
203 | user.iocharset[NCP_IOCSNAME_LEN] = 0; | 203 | user.iocharset[NCP_IOCSNAME_LEN] = 0; |
204 | if (!user.iocharset[0] || !strcmp(user.iocharset, "default")) { | 204 | if (!user.iocharset[0] || !strcmp(user.iocharset, "default")) { |
205 | iocharset = load_nls_default(); | 205 | iocharset = load_nls_default(); |
206 | NCP_CLR_FLAG(server, NCP_FLAG_UTF8); | 206 | NCP_CLR_FLAG(server, NCP_FLAG_UTF8); |
207 | } else if (!strcmp(user.iocharset, "utf8")) { | 207 | } else if (!strcmp(user.iocharset, "utf8")) { |
208 | iocharset = load_nls_default(); | 208 | iocharset = load_nls_default(); |
209 | NCP_SET_FLAG(server, NCP_FLAG_UTF8); | 209 | NCP_SET_FLAG(server, NCP_FLAG_UTF8); |
210 | } else { | 210 | } else { |
211 | iocharset = load_nls(user.iocharset); | 211 | iocharset = load_nls(user.iocharset); |
212 | if (!iocharset) { | 212 | if (!iocharset) { |
213 | unload_nls(codepage); | 213 | unload_nls(codepage); |
214 | return -EBADRQC; | 214 | return -EBADRQC; |
215 | } | 215 | } |
216 | NCP_CLR_FLAG(server, NCP_FLAG_UTF8); | 216 | NCP_CLR_FLAG(server, NCP_FLAG_UTF8); |
217 | } | 217 | } |
218 | 218 | ||
219 | oldset_cp = server->nls_vol; | 219 | oldset_cp = server->nls_vol; |
220 | server->nls_vol = codepage; | 220 | server->nls_vol = codepage; |
221 | oldset_io = server->nls_io; | 221 | oldset_io = server->nls_io; |
222 | server->nls_io = iocharset; | 222 | server->nls_io = iocharset; |
223 | 223 | ||
224 | if (oldset_cp) | 224 | if (oldset_cp) |
225 | unload_nls(oldset_cp); | 225 | unload_nls(oldset_cp); |
226 | if (oldset_io) | 226 | if (oldset_io) |
227 | unload_nls(oldset_io); | 227 | unload_nls(oldset_io); |
228 | 228 | ||
229 | return 0; | 229 | return 0; |
230 | } | 230 | } |
231 | 231 | ||
232 | static int | 232 | static int |
233 | ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) | 233 | ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg) |
234 | { | 234 | { |
235 | struct ncp_nls_ioctl user; | 235 | struct ncp_nls_ioctl user; |
236 | int len; | 236 | int len; |
237 | 237 | ||
238 | memset(&user, 0, sizeof(user)); | 238 | memset(&user, 0, sizeof(user)); |
239 | if (server->nls_vol && server->nls_vol->charset) { | 239 | if (server->nls_vol && server->nls_vol->charset) { |
240 | len = strlen(server->nls_vol->charset); | 240 | len = strlen(server->nls_vol->charset); |
241 | if (len > NCP_IOCSNAME_LEN) | 241 | if (len > NCP_IOCSNAME_LEN) |
242 | len = NCP_IOCSNAME_LEN; | 242 | len = NCP_IOCSNAME_LEN; |
243 | strncpy(user.codepage, server->nls_vol->charset, len); | 243 | strncpy(user.codepage, server->nls_vol->charset, len); |
244 | user.codepage[len] = 0; | 244 | user.codepage[len] = 0; |
245 | } | 245 | } |
246 | 246 | ||
247 | if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) | 247 | if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) |
248 | strcpy(user.iocharset, "utf8"); | 248 | strcpy(user.iocharset, "utf8"); |
249 | else if (server->nls_io && server->nls_io->charset) { | 249 | else if (server->nls_io && server->nls_io->charset) { |
250 | len = strlen(server->nls_io->charset); | 250 | len = strlen(server->nls_io->charset); |
251 | if (len > NCP_IOCSNAME_LEN) | 251 | if (len > NCP_IOCSNAME_LEN) |
252 | len = NCP_IOCSNAME_LEN; | 252 | len = NCP_IOCSNAME_LEN; |
253 | strncpy(user.iocharset, server->nls_io->charset, len); | 253 | strncpy(user.iocharset, server->nls_io->charset, len); |
254 | user.iocharset[len] = 0; | 254 | user.iocharset[len] = 0; |
255 | } | 255 | } |
256 | 256 | ||
257 | if (copy_to_user(arg, &user, sizeof(user))) | 257 | if (copy_to_user(arg, &user, sizeof(user))) |
258 | return -EFAULT; | 258 | return -EFAULT; |
259 | return 0; | 259 | return 0; |
260 | } | 260 | } |
261 | #endif /* CONFIG_NCPFS_NLS */ | 261 | #endif /* CONFIG_NCPFS_NLS */ |
262 | 262 | ||
263 | int ncp_ioctl(struct inode *inode, struct file *filp, | 263 | int ncp_ioctl(struct inode *inode, struct file *filp, |
264 | unsigned int cmd, unsigned long arg) | 264 | unsigned int cmd, unsigned long arg) |
265 | { | 265 | { |
266 | struct ncp_server *server = NCP_SERVER(inode); | 266 | struct ncp_server *server = NCP_SERVER(inode); |
267 | int result; | 267 | int result; |
268 | struct ncp_ioctl_request request; | 268 | struct ncp_ioctl_request request; |
269 | char* bouncebuffer; | 269 | char* bouncebuffer; |
270 | void __user *argp = (void __user *)arg; | 270 | void __user *argp = (void __user *)arg; |
271 | 271 | ||
272 | switch (cmd) { | 272 | switch (cmd) { |
273 | #ifdef CONFIG_COMPAT | 273 | #ifdef CONFIG_COMPAT |
274 | case NCP_IOC_NCPREQUEST_32: | 274 | case NCP_IOC_NCPREQUEST_32: |
275 | #endif | 275 | #endif |
276 | case NCP_IOC_NCPREQUEST: | 276 | case NCP_IOC_NCPREQUEST: |
277 | if ((file_permission(filp, MAY_WRITE) != 0) | 277 | if ((file_permission(filp, MAY_WRITE) != 0) |
278 | && (current->uid != server->m.mounted_uid)) { | 278 | && (current->uid != server->m.mounted_uid)) { |
279 | return -EACCES; | 279 | return -EACCES; |
280 | } | 280 | } |
281 | #ifdef CONFIG_COMPAT | 281 | #ifdef CONFIG_COMPAT |
282 | if (cmd == NCP_IOC_NCPREQUEST_32) { | 282 | if (cmd == NCP_IOC_NCPREQUEST_32) { |
283 | struct compat_ncp_ioctl_request request32; | 283 | struct compat_ncp_ioctl_request request32; |
284 | if (copy_from_user(&request32, argp, sizeof(request32))) | 284 | if (copy_from_user(&request32, argp, sizeof(request32))) |
285 | return -EFAULT; | 285 | return -EFAULT; |
286 | request.function = request32.function; | 286 | request.function = request32.function; |
287 | request.size = request32.size; | 287 | request.size = request32.size; |
288 | request.data = compat_ptr(request32.data); | 288 | request.data = compat_ptr(request32.data); |
289 | } else | 289 | } else |
290 | #endif | 290 | #endif |
291 | if (copy_from_user(&request, argp, sizeof(request))) | 291 | if (copy_from_user(&request, argp, sizeof(request))) |
292 | return -EFAULT; | 292 | return -EFAULT; |
293 | 293 | ||
294 | if ((request.function > 255) | 294 | if ((request.function > 255) |
295 | || (request.size > | 295 | || (request.size > |
296 | NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) { | 296 | NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) { |
297 | return -EINVAL; | 297 | return -EINVAL; |
298 | } | 298 | } |
299 | bouncebuffer = vmalloc(NCP_PACKET_SIZE_INTERNAL); | 299 | bouncebuffer = vmalloc(NCP_PACKET_SIZE_INTERNAL); |
300 | if (!bouncebuffer) | 300 | if (!bouncebuffer) |
301 | return -ENOMEM; | 301 | return -ENOMEM; |
302 | if (copy_from_user(bouncebuffer, request.data, request.size)) { | 302 | if (copy_from_user(bouncebuffer, request.data, request.size)) { |
303 | vfree(bouncebuffer); | 303 | vfree(bouncebuffer); |
304 | return -EFAULT; | 304 | return -EFAULT; |
305 | } | 305 | } |
306 | ncp_lock_server(server); | 306 | ncp_lock_server(server); |
307 | 307 | ||
308 | /* FIXME: We hack around in the server's structures | 308 | /* FIXME: We hack around in the server's structures |
309 | here to be able to use ncp_request */ | 309 | here to be able to use ncp_request */ |
310 | 310 | ||
311 | server->has_subfunction = 0; | 311 | server->has_subfunction = 0; |
312 | server->current_size = request.size; | 312 | server->current_size = request.size; |
313 | memcpy(server->packet, bouncebuffer, request.size); | 313 | memcpy(server->packet, bouncebuffer, request.size); |
314 | 314 | ||
315 | result = ncp_request2(server, request.function, | 315 | result = ncp_request2(server, request.function, |
316 | bouncebuffer, NCP_PACKET_SIZE_INTERNAL); | 316 | bouncebuffer, NCP_PACKET_SIZE_INTERNAL); |
317 | if (result < 0) | 317 | if (result < 0) |
318 | result = -EIO; | 318 | result = -EIO; |
319 | else | 319 | else |
320 | result = server->reply_size; | 320 | result = server->reply_size; |
321 | ncp_unlock_server(server); | 321 | ncp_unlock_server(server); |
322 | DPRINTK("ncp_ioctl: copy %d bytes\n", | 322 | DPRINTK("ncp_ioctl: copy %d bytes\n", |
323 | result); | 323 | result); |
324 | if (result >= 0) | 324 | if (result >= 0) |
325 | if (copy_to_user(request.data, bouncebuffer, result)) | 325 | if (copy_to_user(request.data, bouncebuffer, result)) |
326 | result = -EFAULT; | 326 | result = -EFAULT; |
327 | vfree(bouncebuffer); | 327 | vfree(bouncebuffer); |
328 | return result; | 328 | return result; |
329 | 329 | ||
330 | case NCP_IOC_CONN_LOGGED_IN: | 330 | case NCP_IOC_CONN_LOGGED_IN: |
331 | 331 | ||
332 | if (!capable(CAP_SYS_ADMIN)) | 332 | if (!capable(CAP_SYS_ADMIN)) |
333 | return -EACCES; | 333 | return -EACCES; |
334 | if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE)) | 334 | if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE)) |
335 | return -EINVAL; | 335 | return -EINVAL; |
336 | if (server->root_setuped) | 336 | if (server->root_setuped) |
337 | return -EBUSY; | 337 | return -EBUSY; |
338 | server->root_setuped = 1; | 338 | server->root_setuped = 1; |
339 | return ncp_conn_logged_in(inode->i_sb); | 339 | return ncp_conn_logged_in(inode->i_sb); |
340 | 340 | ||
341 | case NCP_IOC_GET_FS_INFO: | 341 | case NCP_IOC_GET_FS_INFO: |
342 | return ncp_get_fs_info(server, filp, argp); | 342 | return ncp_get_fs_info(server, filp, argp); |
343 | 343 | ||
344 | case NCP_IOC_GET_FS_INFO_V2: | 344 | case NCP_IOC_GET_FS_INFO_V2: |
345 | return ncp_get_fs_info_v2(server, filp, argp); | 345 | return ncp_get_fs_info_v2(server, filp, argp); |
346 | 346 | ||
347 | #ifdef CONFIG_COMPAT | 347 | #ifdef CONFIG_COMPAT |
348 | case NCP_IOC_GET_FS_INFO_V2_32: | 348 | case NCP_IOC_GET_FS_INFO_V2_32: |
349 | return ncp_get_compat_fs_info_v2(server, filp, argp); | 349 | return ncp_get_compat_fs_info_v2(server, filp, argp); |
350 | #endif | 350 | #endif |
351 | /* we have too many combinations of CONFIG_COMPAT, | 351 | /* we have too many combinations of CONFIG_COMPAT, |
352 | * CONFIG_64BIT and CONFIG_UID16, so just handle | 352 | * CONFIG_64BIT and CONFIG_UID16, so just handle |
353 | * any of the possible ioctls */ | 353 | * any of the possible ioctls */ |
354 | case NCP_IOC_GETMOUNTUID16: | 354 | case NCP_IOC_GETMOUNTUID16: |
355 | case NCP_IOC_GETMOUNTUID32: | 355 | case NCP_IOC_GETMOUNTUID32: |
356 | case NCP_IOC_GETMOUNTUID64: | 356 | case NCP_IOC_GETMOUNTUID64: |
357 | if ((file_permission(filp, MAY_READ) != 0) | 357 | if ((file_permission(filp, MAY_READ) != 0) |
358 | && (current->uid != server->m.mounted_uid)) { | 358 | && (current->uid != server->m.mounted_uid)) { |
359 | return -EACCES; | 359 | return -EACCES; |
360 | } | 360 | } |
361 | if (cmd == NCP_IOC_GETMOUNTUID16) { | 361 | if (cmd == NCP_IOC_GETMOUNTUID16) { |
362 | u16 uid; | 362 | u16 uid; |
363 | SET_UID(uid, server->m.mounted_uid); | 363 | SET_UID(uid, server->m.mounted_uid); |
364 | if (put_user(uid, (u16 __user *)argp)) | 364 | if (put_user(uid, (u16 __user *)argp)) |
365 | return -EFAULT; | 365 | return -EFAULT; |
366 | } else if (cmd == NCP_IOC_GETMOUNTUID32) { | 366 | } else if (cmd == NCP_IOC_GETMOUNTUID32) { |
367 | if (put_user(server->m.mounted_uid, | 367 | if (put_user(server->m.mounted_uid, |
368 | (u32 __user *)argp)) | 368 | (u32 __user *)argp)) |
369 | return -EFAULT; | 369 | return -EFAULT; |
370 | } else { | 370 | } else { |
371 | if (put_user(server->m.mounted_uid, | 371 | if (put_user(server->m.mounted_uid, |
372 | (u64 __user *)argp)) | 372 | (u64 __user *)argp)) |
373 | return -EFAULT; | 373 | return -EFAULT; |
374 | } | 374 | } |
375 | return 0; | 375 | return 0; |
376 | 376 | ||
377 | case NCP_IOC_GETROOT: | 377 | case NCP_IOC_GETROOT: |
378 | { | 378 | { |
379 | struct ncp_setroot_ioctl sr; | 379 | struct ncp_setroot_ioctl sr; |
380 | 380 | ||
381 | if ((file_permission(filp, MAY_READ) != 0) | 381 | if ((file_permission(filp, MAY_READ) != 0) |
382 | && (current->uid != server->m.mounted_uid)) | 382 | && (current->uid != server->m.mounted_uid)) |
383 | { | 383 | { |
384 | return -EACCES; | 384 | return -EACCES; |
385 | } | 385 | } |
386 | if (server->m.mounted_vol[0]) { | 386 | if (server->m.mounted_vol[0]) { |
387 | struct dentry* dentry = inode->i_sb->s_root; | 387 | struct dentry* dentry = inode->i_sb->s_root; |
388 | 388 | ||
389 | if (dentry) { | 389 | if (dentry) { |
390 | struct inode* inode = dentry->d_inode; | 390 | struct inode* inode = dentry->d_inode; |
391 | 391 | ||
392 | if (inode) { | 392 | if (inode) { |
393 | sr.volNumber = NCP_FINFO(inode)->volNumber; | 393 | sr.volNumber = NCP_FINFO(inode)->volNumber; |
394 | sr.dirEntNum = NCP_FINFO(inode)->dirEntNum; | 394 | sr.dirEntNum = NCP_FINFO(inode)->dirEntNum; |
395 | sr.namespace = server->name_space[sr.volNumber]; | 395 | sr.namespace = server->name_space[sr.volNumber]; |
396 | } else | 396 | } else |
397 | DPRINTK("ncpfs: s_root->d_inode==NULL\n"); | 397 | DPRINTK("ncpfs: s_root->d_inode==NULL\n"); |
398 | } else | 398 | } else |
399 | DPRINTK("ncpfs: s_root==NULL\n"); | 399 | DPRINTK("ncpfs: s_root==NULL\n"); |
400 | } else { | 400 | } else { |
401 | sr.volNumber = -1; | 401 | sr.volNumber = -1; |
402 | sr.namespace = 0; | 402 | sr.namespace = 0; |
403 | sr.dirEntNum = 0; | 403 | sr.dirEntNum = 0; |
404 | } | 404 | } |
405 | if (copy_to_user(argp, &sr, sizeof(sr))) | 405 | if (copy_to_user(argp, &sr, sizeof(sr))) |
406 | return -EFAULT; | 406 | return -EFAULT; |
407 | return 0; | 407 | return 0; |
408 | } | 408 | } |
409 | case NCP_IOC_SETROOT: | 409 | case NCP_IOC_SETROOT: |
410 | { | 410 | { |
411 | struct ncp_setroot_ioctl sr; | 411 | struct ncp_setroot_ioctl sr; |
412 | __u32 vnum; | 412 | __u32 vnum; |
413 | __le32 de; | 413 | __le32 de; |
414 | __le32 dosde; | 414 | __le32 dosde; |
415 | struct dentry* dentry; | 415 | struct dentry* dentry; |
416 | 416 | ||
417 | if (!capable(CAP_SYS_ADMIN)) | 417 | if (!capable(CAP_SYS_ADMIN)) |
418 | { | 418 | { |
419 | return -EACCES; | 419 | return -EACCES; |
420 | } | 420 | } |
421 | if (server->root_setuped) return -EBUSY; | 421 | if (server->root_setuped) return -EBUSY; |
422 | if (copy_from_user(&sr, argp, sizeof(sr))) | 422 | if (copy_from_user(&sr, argp, sizeof(sr))) |
423 | return -EFAULT; | 423 | return -EFAULT; |
424 | if (sr.volNumber < 0) { | 424 | if (sr.volNumber < 0) { |
425 | server->m.mounted_vol[0] = 0; | 425 | server->m.mounted_vol[0] = 0; |
426 | vnum = NCP_NUMBER_OF_VOLUMES; | 426 | vnum = NCP_NUMBER_OF_VOLUMES; |
427 | de = 0; | 427 | de = 0; |
428 | dosde = 0; | 428 | dosde = 0; |
429 | } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) { | 429 | } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) { |
430 | return -EINVAL; | 430 | return -EINVAL; |
431 | } else if (ncp_mount_subdir(server, sr.volNumber, | 431 | } else if (ncp_mount_subdir(server, sr.volNumber, |
432 | sr.namespace, sr.dirEntNum, | 432 | sr.namespace, sr.dirEntNum, |
433 | &vnum, &de, &dosde)) { | 433 | &vnum, &de, &dosde)) { |
434 | return -ENOENT; | 434 | return -ENOENT; |
435 | } | 435 | } |
436 | 436 | ||
437 | dentry = inode->i_sb->s_root; | 437 | dentry = inode->i_sb->s_root; |
438 | server->root_setuped = 1; | 438 | server->root_setuped = 1; |
439 | if (dentry) { | 439 | if (dentry) { |
440 | struct inode* inode = dentry->d_inode; | 440 | struct inode* inode = dentry->d_inode; |
441 | 441 | ||
442 | if (inode) { | 442 | if (inode) { |
443 | NCP_FINFO(inode)->volNumber = vnum; | 443 | NCP_FINFO(inode)->volNumber = vnum; |
444 | NCP_FINFO(inode)->dirEntNum = de; | 444 | NCP_FINFO(inode)->dirEntNum = de; |
445 | NCP_FINFO(inode)->DosDirNum = dosde; | 445 | NCP_FINFO(inode)->DosDirNum = dosde; |
446 | } else | 446 | } else |
447 | DPRINTK("ncpfs: s_root->d_inode==NULL\n"); | 447 | DPRINTK("ncpfs: s_root->d_inode==NULL\n"); |
448 | } else | 448 | } else |
449 | DPRINTK("ncpfs: s_root==NULL\n"); | 449 | DPRINTK("ncpfs: s_root==NULL\n"); |
450 | 450 | ||
451 | return 0; | 451 | return 0; |
452 | } | 452 | } |
453 | 453 | ||
454 | #ifdef CONFIG_NCPFS_PACKET_SIGNING | 454 | #ifdef CONFIG_NCPFS_PACKET_SIGNING |
455 | case NCP_IOC_SIGN_INIT: | 455 | case NCP_IOC_SIGN_INIT: |
456 | if ((file_permission(filp, MAY_WRITE) != 0) | 456 | if ((file_permission(filp, MAY_WRITE) != 0) |
457 | && (current->uid != server->m.mounted_uid)) | 457 | && (current->uid != server->m.mounted_uid)) |
458 | { | 458 | { |
459 | return -EACCES; | 459 | return -EACCES; |
460 | } | 460 | } |
461 | if (argp) { | 461 | if (argp) { |
462 | if (server->sign_wanted) | 462 | if (server->sign_wanted) |
463 | { | 463 | { |
464 | struct ncp_sign_init sign; | 464 | struct ncp_sign_init sign; |
465 | 465 | ||
466 | if (copy_from_user(&sign, argp, sizeof(sign))) | 466 | if (copy_from_user(&sign, argp, sizeof(sign))) |
467 | return -EFAULT; | 467 | return -EFAULT; |
468 | memcpy(server->sign_root,sign.sign_root,8); | 468 | memcpy(server->sign_root,sign.sign_root,8); |
469 | memcpy(server->sign_last,sign.sign_last,16); | 469 | memcpy(server->sign_last,sign.sign_last,16); |
470 | server->sign_active = 1; | 470 | server->sign_active = 1; |
471 | } | 471 | } |
472 | /* ignore when signatures not wanted */ | 472 | /* ignore when signatures not wanted */ |
473 | } else { | 473 | } else { |
474 | server->sign_active = 0; | 474 | server->sign_active = 0; |
475 | } | 475 | } |
476 | return 0; | 476 | return 0; |
477 | 477 | ||
478 | case NCP_IOC_SIGN_WANTED: | 478 | case NCP_IOC_SIGN_WANTED: |
479 | if ((file_permission(filp, MAY_READ) != 0) | 479 | if ((file_permission(filp, MAY_READ) != 0) |
480 | && (current->uid != server->m.mounted_uid)) | 480 | && (current->uid != server->m.mounted_uid)) |
481 | { | 481 | { |
482 | return -EACCES; | 482 | return -EACCES; |
483 | } | 483 | } |
484 | 484 | ||
485 | if (put_user(server->sign_wanted, (int __user *)argp)) | 485 | if (put_user(server->sign_wanted, (int __user *)argp)) |
486 | return -EFAULT; | 486 | return -EFAULT; |
487 | return 0; | 487 | return 0; |
488 | case NCP_IOC_SET_SIGN_WANTED: | 488 | case NCP_IOC_SET_SIGN_WANTED: |
489 | { | 489 | { |
490 | int newstate; | 490 | int newstate; |
491 | 491 | ||
492 | if ((file_permission(filp, MAY_WRITE) != 0) | 492 | if ((file_permission(filp, MAY_WRITE) != 0) |
493 | && (current->uid != server->m.mounted_uid)) | 493 | && (current->uid != server->m.mounted_uid)) |
494 | { | 494 | { |
495 | return -EACCES; | 495 | return -EACCES; |
496 | } | 496 | } |
497 | /* get only low 8 bits... */ | 497 | /* get only low 8 bits... */ |
498 | if (get_user(newstate, (unsigned char __user *)argp)) | 498 | if (get_user(newstate, (unsigned char __user *)argp)) |
499 | return -EFAULT; | 499 | return -EFAULT; |
500 | if (server->sign_active) { | 500 | if (server->sign_active) { |
501 | /* cannot turn signatures OFF when active */ | 501 | /* cannot turn signatures OFF when active */ |
502 | if (!newstate) return -EINVAL; | 502 | if (!newstate) return -EINVAL; |
503 | } else { | 503 | } else { |
504 | server->sign_wanted = newstate != 0; | 504 | server->sign_wanted = newstate != 0; |
505 | } | 505 | } |
506 | return 0; | 506 | return 0; |
507 | } | 507 | } |
508 | 508 | ||
509 | #endif /* CONFIG_NCPFS_PACKET_SIGNING */ | 509 | #endif /* CONFIG_NCPFS_PACKET_SIGNING */ |
510 | 510 | ||
511 | #ifdef CONFIG_NCPFS_IOCTL_LOCKING | 511 | #ifdef CONFIG_NCPFS_IOCTL_LOCKING |
512 | case NCP_IOC_LOCKUNLOCK: | 512 | case NCP_IOC_LOCKUNLOCK: |
513 | if ((file_permission(filp, MAY_WRITE) != 0) | 513 | if ((file_permission(filp, MAY_WRITE) != 0) |
514 | && (current->uid != server->m.mounted_uid)) | 514 | && (current->uid != server->m.mounted_uid)) |
515 | { | 515 | { |
516 | return -EACCES; | 516 | return -EACCES; |
517 | } | 517 | } |
518 | { | 518 | { |
519 | struct ncp_lock_ioctl rqdata; | 519 | struct ncp_lock_ioctl rqdata; |
520 | int result; | 520 | int result; |
521 | 521 | ||
522 | if (copy_from_user(&rqdata, argp, sizeof(rqdata))) | 522 | if (copy_from_user(&rqdata, argp, sizeof(rqdata))) |
523 | return -EFAULT; | 523 | return -EFAULT; |
524 | if (rqdata.origin != 0) | 524 | if (rqdata.origin != 0) |
525 | return -EINVAL; | 525 | return -EINVAL; |
526 | /* check for cmd */ | 526 | /* check for cmd */ |
527 | switch (rqdata.cmd) { | 527 | switch (rqdata.cmd) { |
528 | case NCP_LOCK_EX: | 528 | case NCP_LOCK_EX: |
529 | case NCP_LOCK_SH: | 529 | case NCP_LOCK_SH: |
530 | if (rqdata.timeout == 0) | 530 | if (rqdata.timeout == 0) |
531 | rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; | 531 | rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; |
532 | else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT) | 532 | else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT) |
533 | rqdata.timeout = NCP_LOCK_MAX_TIMEOUT; | 533 | rqdata.timeout = NCP_LOCK_MAX_TIMEOUT; |
534 | break; | 534 | break; |
535 | case NCP_LOCK_LOG: | 535 | case NCP_LOCK_LOG: |
536 | rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; /* has no effect */ | 536 | rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; /* has no effect */ |
537 | case NCP_LOCK_CLEAR: | 537 | case NCP_LOCK_CLEAR: |
538 | break; | 538 | break; |
539 | default: | 539 | default: |
540 | return -EINVAL; | 540 | return -EINVAL; |
541 | } | 541 | } |
542 | /* locking needs both read and write access */ | 542 | /* locking needs both read and write access */ |
543 | if ((result = ncp_make_open(inode, O_RDWR)) != 0) | 543 | if ((result = ncp_make_open(inode, O_RDWR)) != 0) |
544 | { | 544 | { |
545 | return result; | 545 | return result; |
546 | } | 546 | } |
547 | result = -EIO; | 547 | result = -EIO; |
548 | if (!ncp_conn_valid(server)) | 548 | if (!ncp_conn_valid(server)) |
549 | goto outrel; | 549 | goto outrel; |
550 | result = -EISDIR; | 550 | result = -EISDIR; |
551 | if (!S_ISREG(inode->i_mode)) | 551 | if (!S_ISREG(inode->i_mode)) |
552 | goto outrel; | 552 | goto outrel; |
553 | if (rqdata.cmd == NCP_LOCK_CLEAR) | 553 | if (rqdata.cmd == NCP_LOCK_CLEAR) |
554 | { | 554 | { |
555 | result = ncp_ClearPhysicalRecord(NCP_SERVER(inode), | 555 | result = ncp_ClearPhysicalRecord(NCP_SERVER(inode), |
556 | NCP_FINFO(inode)->file_handle, | 556 | NCP_FINFO(inode)->file_handle, |
557 | rqdata.offset, | 557 | rqdata.offset, |
558 | rqdata.length); | 558 | rqdata.length); |
559 | if (result > 0) result = 0; /* no such lock */ | 559 | if (result > 0) result = 0; /* no such lock */ |
560 | } | 560 | } |
561 | else | 561 | else |
562 | { | 562 | { |
563 | int lockcmd; | 563 | int lockcmd; |
564 | 564 | ||
565 | switch (rqdata.cmd) | 565 | switch (rqdata.cmd) |
566 | { | 566 | { |
567 | case NCP_LOCK_EX: lockcmd=1; break; | 567 | case NCP_LOCK_EX: lockcmd=1; break; |
568 | case NCP_LOCK_SH: lockcmd=3; break; | 568 | case NCP_LOCK_SH: lockcmd=3; break; |
569 | default: lockcmd=0; break; | 569 | default: lockcmd=0; break; |
570 | } | 570 | } |
571 | result = ncp_LogPhysicalRecord(NCP_SERVER(inode), | 571 | result = ncp_LogPhysicalRecord(NCP_SERVER(inode), |
572 | NCP_FINFO(inode)->file_handle, | 572 | NCP_FINFO(inode)->file_handle, |
573 | lockcmd, | 573 | lockcmd, |
574 | rqdata.offset, | 574 | rqdata.offset, |
575 | rqdata.length, | 575 | rqdata.length, |
576 | rqdata.timeout); | 576 | rqdata.timeout); |
577 | if (result > 0) result = -EAGAIN; | 577 | if (result > 0) result = -EAGAIN; |
578 | } | 578 | } |
579 | outrel: | 579 | outrel: |
580 | ncp_inode_close(inode); | 580 | ncp_inode_close(inode); |
581 | return result; | 581 | return result; |
582 | } | 582 | } |
583 | #endif /* CONFIG_NCPFS_IOCTL_LOCKING */ | 583 | #endif /* CONFIG_NCPFS_IOCTL_LOCKING */ |
584 | 584 | ||
585 | #ifdef CONFIG_COMPAT | 585 | #ifdef CONFIG_COMPAT |
586 | case NCP_IOC_GETOBJECTNAME_32: | 586 | case NCP_IOC_GETOBJECTNAME_32: |
587 | if (current->uid != server->m.mounted_uid) { | 587 | if (current->uid != server->m.mounted_uid) { |
588 | return -EACCES; | 588 | return -EACCES; |
589 | } | 589 | } |
590 | { | 590 | { |
591 | struct compat_ncp_objectname_ioctl user; | 591 | struct compat_ncp_objectname_ioctl user; |
592 | size_t outl; | 592 | size_t outl; |
593 | 593 | ||
594 | if (copy_from_user(&user, argp, sizeof(user))) | 594 | if (copy_from_user(&user, argp, sizeof(user))) |
595 | return -EFAULT; | 595 | return -EFAULT; |
596 | user.auth_type = server->auth.auth_type; | 596 | user.auth_type = server->auth.auth_type; |
597 | outl = user.object_name_len; | 597 | outl = user.object_name_len; |
598 | user.object_name_len = server->auth.object_name_len; | 598 | user.object_name_len = server->auth.object_name_len; |
599 | if (outl > user.object_name_len) | 599 | if (outl > user.object_name_len) |
600 | outl = user.object_name_len; | 600 | outl = user.object_name_len; |
601 | if (outl) { | 601 | if (outl) { |
602 | if (copy_to_user(compat_ptr(user.object_name), | 602 | if (copy_to_user(compat_ptr(user.object_name), |
603 | server->auth.object_name, | 603 | server->auth.object_name, |
604 | outl)) return -EFAULT; | 604 | outl)) return -EFAULT; |
605 | } | 605 | } |
606 | if (copy_to_user(argp, &user, sizeof(user))) | 606 | if (copy_to_user(argp, &user, sizeof(user))) |
607 | return -EFAULT; | 607 | return -EFAULT; |
608 | return 0; | 608 | return 0; |
609 | } | 609 | } |
610 | #endif | 610 | #endif |
611 | case NCP_IOC_GETOBJECTNAME: | 611 | case NCP_IOC_GETOBJECTNAME: |
612 | if (current->uid != server->m.mounted_uid) { | 612 | if (current->uid != server->m.mounted_uid) { |
613 | return -EACCES; | 613 | return -EACCES; |
614 | } | 614 | } |
615 | { | 615 | { |
616 | struct ncp_objectname_ioctl user; | 616 | struct ncp_objectname_ioctl user; |
617 | size_t outl; | 617 | size_t outl; |
618 | 618 | ||
619 | if (copy_from_user(&user, argp, sizeof(user))) | 619 | if (copy_from_user(&user, argp, sizeof(user))) |
620 | return -EFAULT; | 620 | return -EFAULT; |
621 | user.auth_type = server->auth.auth_type; | 621 | user.auth_type = server->auth.auth_type; |
622 | outl = user.object_name_len; | 622 | outl = user.object_name_len; |
623 | user.object_name_len = server->auth.object_name_len; | 623 | user.object_name_len = server->auth.object_name_len; |
624 | if (outl > user.object_name_len) | 624 | if (outl > user.object_name_len) |
625 | outl = user.object_name_len; | 625 | outl = user.object_name_len; |
626 | if (outl) { | 626 | if (outl) { |
627 | if (copy_to_user(user.object_name, | 627 | if (copy_to_user(user.object_name, |
628 | server->auth.object_name, | 628 | server->auth.object_name, |
629 | outl)) return -EFAULT; | 629 | outl)) return -EFAULT; |
630 | } | 630 | } |
631 | if (copy_to_user(argp, &user, sizeof(user))) | 631 | if (copy_to_user(argp, &user, sizeof(user))) |
632 | return -EFAULT; | 632 | return -EFAULT; |
633 | return 0; | 633 | return 0; |
634 | } | 634 | } |
635 | #ifdef CONFIG_COMPAT | 635 | #ifdef CONFIG_COMPAT |
636 | case NCP_IOC_SETOBJECTNAME_32: | 636 | case NCP_IOC_SETOBJECTNAME_32: |
637 | #endif | 637 | #endif |
638 | case NCP_IOC_SETOBJECTNAME: | 638 | case NCP_IOC_SETOBJECTNAME: |
639 | if (current->uid != server->m.mounted_uid) { | 639 | if (current->uid != server->m.mounted_uid) { |
640 | return -EACCES; | 640 | return -EACCES; |
641 | } | 641 | } |
642 | { | 642 | { |
643 | struct ncp_objectname_ioctl user; | 643 | struct ncp_objectname_ioctl user; |
644 | void* newname; | 644 | void* newname; |
645 | void* oldname; | 645 | void* oldname; |
646 | size_t oldnamelen; | 646 | size_t oldnamelen; |
647 | void* oldprivate; | 647 | void* oldprivate; |
648 | size_t oldprivatelen; | 648 | size_t oldprivatelen; |
649 | 649 | ||
650 | #ifdef CONFIG_COMPAT | 650 | #ifdef CONFIG_COMPAT |
651 | if (cmd == NCP_IOC_SETOBJECTNAME_32) { | 651 | if (cmd == NCP_IOC_SETOBJECTNAME_32) { |
652 | struct compat_ncp_objectname_ioctl user32; | 652 | struct compat_ncp_objectname_ioctl user32; |
653 | if (copy_from_user(&user32, argp, sizeof(user32))) | 653 | if (copy_from_user(&user32, argp, sizeof(user32))) |
654 | return -EFAULT; | 654 | return -EFAULT; |
655 | user.auth_type = user32.auth_type; | 655 | user.auth_type = user32.auth_type; |
656 | user.object_name_len = user32.object_name_len; | 656 | user.object_name_len = user32.object_name_len; |
657 | user.object_name = compat_ptr(user32.object_name); | 657 | user.object_name = compat_ptr(user32.object_name); |
658 | } else | 658 | } else |
659 | #endif | 659 | #endif |
660 | if (copy_from_user(&user, argp, sizeof(user))) | 660 | if (copy_from_user(&user, argp, sizeof(user))) |
661 | return -EFAULT; | 661 | return -EFAULT; |
662 | 662 | ||
663 | if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN) | 663 | if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN) |
664 | return -ENOMEM; | 664 | return -ENOMEM; |
665 | if (user.object_name_len) { | 665 | if (user.object_name_len) { |
666 | newname = kmalloc(user.object_name_len, GFP_USER); | 666 | newname = kmalloc(user.object_name_len, GFP_USER); |
667 | if (!newname) | 667 | if (!newname) |
668 | return -ENOMEM; | 668 | return -ENOMEM; |
669 | if (copy_from_user(newname, user.object_name, user.object_name_len)) { | 669 | if (copy_from_user(newname, user.object_name, user.object_name_len)) { |
670 | kfree(newname); | 670 | kfree(newname); |
671 | return -EFAULT; | 671 | return -EFAULT; |
672 | } | 672 | } |
673 | } else { | 673 | } else { |
674 | newname = NULL; | 674 | newname = NULL; |
675 | } | 675 | } |
676 | /* enter critical section */ | 676 | /* enter critical section */ |
677 | /* maybe that kfree can sleep so do that this way */ | 677 | /* maybe that kfree can sleep so do that this way */ |
678 | /* it is at least more SMP friendly (in future...) */ | 678 | /* it is at least more SMP friendly (in future...) */ |
679 | oldname = server->auth.object_name; | 679 | oldname = server->auth.object_name; |
680 | oldnamelen = server->auth.object_name_len; | 680 | oldnamelen = server->auth.object_name_len; |
681 | oldprivate = server->priv.data; | 681 | oldprivate = server->priv.data; |
682 | oldprivatelen = server->priv.len; | 682 | oldprivatelen = server->priv.len; |
683 | server->auth.auth_type = user.auth_type; | 683 | server->auth.auth_type = user.auth_type; |
684 | server->auth.object_name_len = user.object_name_len; | 684 | server->auth.object_name_len = user.object_name_len; |
685 | server->auth.object_name = newname; | 685 | server->auth.object_name = newname; |
686 | server->priv.len = 0; | 686 | server->priv.len = 0; |
687 | server->priv.data = NULL; | 687 | server->priv.data = NULL; |
688 | /* leave critical section */ | 688 | /* leave critical section */ |
689 | kfree(oldprivate); | 689 | kfree(oldprivate); |
690 | kfree(oldname); | 690 | kfree(oldname); |
691 | return 0; | 691 | return 0; |
692 | } | 692 | } |
693 | #ifdef CONFIG_COMPAT | 693 | #ifdef CONFIG_COMPAT |
694 | case NCP_IOC_GETPRIVATEDATA_32: | 694 | case NCP_IOC_GETPRIVATEDATA_32: |
695 | #endif | 695 | #endif |
696 | case NCP_IOC_GETPRIVATEDATA: | 696 | case NCP_IOC_GETPRIVATEDATA: |
697 | if (current->uid != server->m.mounted_uid) { | 697 | if (current->uid != server->m.mounted_uid) { |
698 | return -EACCES; | 698 | return -EACCES; |
699 | } | 699 | } |
700 | { | 700 | { |
701 | struct ncp_privatedata_ioctl user; | 701 | struct ncp_privatedata_ioctl user; |
702 | size_t outl; | 702 | size_t outl; |
703 | 703 | ||
704 | #ifdef CONFIG_COMPAT | 704 | #ifdef CONFIG_COMPAT |
705 | if (cmd == NCP_IOC_GETPRIVATEDATA_32) { | 705 | if (cmd == NCP_IOC_GETPRIVATEDATA_32) { |
706 | struct compat_ncp_privatedata_ioctl user32; | 706 | struct compat_ncp_privatedata_ioctl user32; |
707 | if (copy_from_user(&user32, argp, sizeof(user32))) | 707 | if (copy_from_user(&user32, argp, sizeof(user32))) |
708 | return -EFAULT; | 708 | return -EFAULT; |
709 | user.len = user32.len; | 709 | user.len = user32.len; |
710 | user.data = compat_ptr(user32.data); | 710 | user.data = compat_ptr(user32.data); |
711 | } else | 711 | } else |
712 | #endif | 712 | #endif |
713 | if (copy_from_user(&user, argp, sizeof(user))) | 713 | if (copy_from_user(&user, argp, sizeof(user))) |
714 | return -EFAULT; | 714 | return -EFAULT; |
715 | 715 | ||
716 | outl = user.len; | 716 | outl = user.len; |
717 | user.len = server->priv.len; | 717 | user.len = server->priv.len; |
718 | if (outl > user.len) outl = user.len; | 718 | if (outl > user.len) outl = user.len; |
719 | if (outl) { | 719 | if (outl) { |
720 | if (copy_to_user(user.data, | 720 | if (copy_to_user(user.data, |
721 | server->priv.data, | 721 | server->priv.data, |
722 | outl)) return -EFAULT; | 722 | outl)) return -EFAULT; |
723 | } | 723 | } |
724 | #ifdef CONFIG_COMPAT | 724 | #ifdef CONFIG_COMPAT |
725 | if (cmd == NCP_IOC_GETPRIVATEDATA_32) { | 725 | if (cmd == NCP_IOC_GETPRIVATEDATA_32) { |
726 | struct compat_ncp_privatedata_ioctl user32; | 726 | struct compat_ncp_privatedata_ioctl user32; |
727 | user32.len = user.len; | 727 | user32.len = user.len; |
728 | user32.data = (unsigned long) user.data; | 728 | user32.data = (unsigned long) user.data; |
729 | if (copy_to_user(argp, &user32, sizeof(user32))) | 729 | if (copy_to_user(argp, &user32, sizeof(user32))) |
730 | return -EFAULT; | 730 | return -EFAULT; |
731 | } else | 731 | } else |
732 | #endif | 732 | #endif |
733 | if (copy_to_user(argp, &user, sizeof(user))) | 733 | if (copy_to_user(argp, &user, sizeof(user))) |
734 | return -EFAULT; | 734 | return -EFAULT; |
735 | 735 | ||
736 | return 0; | 736 | return 0; |
737 | } | 737 | } |
738 | #ifdef CONFIG_COMPAT | 738 | #ifdef CONFIG_COMPAT |
739 | case NCP_IOC_SETPRIVATEDATA_32: | 739 | case NCP_IOC_SETPRIVATEDATA_32: |
740 | #endif | 740 | #endif |
741 | case NCP_IOC_SETPRIVATEDATA: | 741 | case NCP_IOC_SETPRIVATEDATA: |
742 | if (current->uid != server->m.mounted_uid) { | 742 | if (current->uid != server->m.mounted_uid) { |
743 | return -EACCES; | 743 | return -EACCES; |
744 | } | 744 | } |
745 | { | 745 | { |
746 | struct ncp_privatedata_ioctl user; | 746 | struct ncp_privatedata_ioctl user; |
747 | void* new; | 747 | void* new; |
748 | void* old; | 748 | void* old; |
749 | size_t oldlen; | 749 | size_t oldlen; |
750 | 750 | ||
751 | #ifdef CONFIG_COMPAT | 751 | #ifdef CONFIG_COMPAT |
752 | if (cmd == NCP_IOC_SETPRIVATEDATA_32) { | 752 | if (cmd == NCP_IOC_SETPRIVATEDATA_32) { |
753 | struct compat_ncp_privatedata_ioctl user32; | 753 | struct compat_ncp_privatedata_ioctl user32; |
754 | if (copy_from_user(&user32, argp, sizeof(user32))) | 754 | if (copy_from_user(&user32, argp, sizeof(user32))) |
755 | return -EFAULT; | 755 | return -EFAULT; |
756 | user.len = user32.len; | 756 | user.len = user32.len; |
757 | user.data = compat_ptr(user32.data); | 757 | user.data = compat_ptr(user32.data); |
758 | } else | 758 | } else |
759 | #endif | 759 | #endif |
760 | if (copy_from_user(&user, argp, sizeof(user))) | 760 | if (copy_from_user(&user, argp, sizeof(user))) |
761 | return -EFAULT; | 761 | return -EFAULT; |
762 | 762 | ||
763 | if (user.len > NCP_PRIVATE_DATA_MAX_LEN) | 763 | if (user.len > NCP_PRIVATE_DATA_MAX_LEN) |
764 | return -ENOMEM; | 764 | return -ENOMEM; |
765 | if (user.len) { | 765 | if (user.len) { |
766 | new = kmalloc(user.len, GFP_USER); | 766 | new = kmalloc(user.len, GFP_USER); |
767 | if (!new) | 767 | if (!new) |
768 | return -ENOMEM; | 768 | return -ENOMEM; |
769 | if (copy_from_user(new, user.data, user.len)) { | 769 | if (copy_from_user(new, user.data, user.len)) { |
770 | kfree(new); | 770 | kfree(new); |
771 | return -EFAULT; | 771 | return -EFAULT; |
772 | } | 772 | } |
773 | } else { | 773 | } else { |
774 | new = NULL; | 774 | new = NULL; |
775 | } | 775 | } |
776 | /* enter critical section */ | 776 | /* enter critical section */ |
777 | old = server->priv.data; | 777 | old = server->priv.data; |
778 | oldlen = server->priv.len; | 778 | oldlen = server->priv.len; |
779 | server->priv.len = user.len; | 779 | server->priv.len = user.len; |
780 | server->priv.data = new; | 780 | server->priv.data = new; |
781 | /* leave critical section */ | 781 | /* leave critical section */ |
782 | kfree(old); | 782 | kfree(old); |
783 | return 0; | 783 | return 0; |
784 | } | 784 | } |
785 | 785 | ||
786 | #ifdef CONFIG_NCPFS_NLS | 786 | #ifdef CONFIG_NCPFS_NLS |
787 | case NCP_IOC_SETCHARSETS: | 787 | case NCP_IOC_SETCHARSETS: |
788 | return ncp_set_charsets(server, argp); | 788 | return ncp_set_charsets(server, argp); |
789 | 789 | ||
790 | case NCP_IOC_GETCHARSETS: | 790 | case NCP_IOC_GETCHARSETS: |
791 | return ncp_get_charsets(server, argp); | 791 | return ncp_get_charsets(server, argp); |
792 | 792 | ||
793 | #endif /* CONFIG_NCPFS_NLS */ | 793 | #endif /* CONFIG_NCPFS_NLS */ |
794 | 794 | ||
795 | case NCP_IOC_SETDENTRYTTL: | 795 | case NCP_IOC_SETDENTRYTTL: |
796 | if ((file_permission(filp, MAY_WRITE) != 0) && | 796 | if ((file_permission(filp, MAY_WRITE) != 0) && |
797 | (current->uid != server->m.mounted_uid)) | 797 | (current->uid != server->m.mounted_uid)) |
798 | return -EACCES; | 798 | return -EACCES; |
799 | { | 799 | { |
800 | u_int32_t user; | 800 | u_int32_t user; |
801 | 801 | ||
802 | if (copy_from_user(&user, argp, sizeof(user))) | 802 | if (copy_from_user(&user, argp, sizeof(user))) |
803 | return -EFAULT; | 803 | return -EFAULT; |
804 | /* 20 secs at most... */ | 804 | /* 20 secs at most... */ |
805 | if (user > 20000) | 805 | if (user > 20000) |
806 | return -EINVAL; | 806 | return -EINVAL; |
807 | user = (user * HZ) / 1000; | 807 | user = (user * HZ) / 1000; |
808 | server->dentry_ttl = user; | 808 | server->dentry_ttl = user; |
809 | return 0; | 809 | return 0; |
810 | } | 810 | } |
811 | 811 | ||
812 | case NCP_IOC_GETDENTRYTTL: | 812 | case NCP_IOC_GETDENTRYTTL: |
813 | { | 813 | { |
814 | u_int32_t user = (server->dentry_ttl * 1000) / HZ; | 814 | u_int32_t user = (server->dentry_ttl * 1000) / HZ; |
815 | if (copy_to_user(argp, &user, sizeof(user))) | 815 | if (copy_to_user(argp, &user, sizeof(user))) |
816 | return -EFAULT; | 816 | return -EFAULT; |
817 | return 0; | 817 | return 0; |
818 | } | 818 | } |
819 | 819 | ||
820 | } | 820 | } |
821 | return -EINVAL; | 821 | return -EINVAL; |
822 | } | 822 | } |
823 | 823 | ||
824 | #ifdef CONFIG_COMPAT | 824 | #ifdef CONFIG_COMPAT |
825 | long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) | 825 | long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg) |
826 | { | 826 | { |
827 | struct inode *inode = file->f_dentry->d_inode; | 827 | struct inode *inode = file->f_path.dentry->d_inode; |
828 | int ret; | 828 | int ret; |
829 | 829 | ||
830 | lock_kernel(); | 830 | lock_kernel(); |
831 | arg = (unsigned long) compat_ptr(arg); | 831 | arg = (unsigned long) compat_ptr(arg); |
832 | ret = ncp_ioctl(inode, file, cmd, arg); | 832 | ret = ncp_ioctl(inode, file, cmd, arg); |
833 | unlock_kernel(); | 833 | unlock_kernel(); |
834 | return ret; | 834 | return ret; |
835 | } | 835 | } |
836 | #endif | 836 | #endif |
837 | 837 |
fs/ncpfs/mmap.c
1 | /* | 1 | /* |
2 | * mmap.c | 2 | * mmap.c |
3 | * | 3 | * |
4 | * Copyright (C) 1995, 1996 by Volker Lendecke | 4 | * Copyright (C) 1995, 1996 by Volker Lendecke |
5 | * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache | 5 | * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache |
6 | * | 6 | * |
7 | */ | 7 | */ |
8 | 8 | ||
9 | #include <linux/stat.h> | 9 | #include <linux/stat.h> |
10 | #include <linux/time.h> | 10 | #include <linux/time.h> |
11 | #include <linux/kernel.h> | 11 | #include <linux/kernel.h> |
12 | #include <linux/mm.h> | 12 | #include <linux/mm.h> |
13 | #include <linux/shm.h> | 13 | #include <linux/shm.h> |
14 | #include <linux/errno.h> | 14 | #include <linux/errno.h> |
15 | #include <linux/mman.h> | 15 | #include <linux/mman.h> |
16 | #include <linux/string.h> | 16 | #include <linux/string.h> |
17 | #include <linux/slab.h> | 17 | #include <linux/slab.h> |
18 | #include <linux/fcntl.h> | 18 | #include <linux/fcntl.h> |
19 | #include <linux/ncp_fs.h> | 19 | #include <linux/ncp_fs.h> |
20 | 20 | ||
21 | #include "ncplib_kernel.h" | 21 | #include "ncplib_kernel.h" |
22 | #include <asm/uaccess.h> | 22 | #include <asm/uaccess.h> |
23 | #include <asm/system.h> | 23 | #include <asm/system.h> |
24 | 24 | ||
25 | /* | 25 | /* |
26 | * Fill in the supplied page for mmap | 26 | * Fill in the supplied page for mmap |
27 | */ | 27 | */ |
28 | static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area, | 28 | static struct page* ncp_file_mmap_nopage(struct vm_area_struct *area, |
29 | unsigned long address, int *type) | 29 | unsigned long address, int *type) |
30 | { | 30 | { |
31 | struct file *file = area->vm_file; | 31 | struct file *file = area->vm_file; |
32 | struct dentry *dentry = file->f_dentry; | 32 | struct dentry *dentry = file->f_path.dentry; |
33 | struct inode *inode = dentry->d_inode; | 33 | struct inode *inode = dentry->d_inode; |
34 | struct page* page; | 34 | struct page* page; |
35 | char *pg_addr; | 35 | char *pg_addr; |
36 | unsigned int already_read; | 36 | unsigned int already_read; |
37 | unsigned int count; | 37 | unsigned int count; |
38 | int bufsize; | 38 | int bufsize; |
39 | int pos; | 39 | int pos; |
40 | 40 | ||
41 | page = alloc_page(GFP_HIGHUSER); /* ncpfs has nothing against high pages | 41 | page = alloc_page(GFP_HIGHUSER); /* ncpfs has nothing against high pages |
42 | as long as recvmsg and memset works on it */ | 42 | as long as recvmsg and memset works on it */ |
43 | if (!page) | 43 | if (!page) |
44 | return page; | 44 | return page; |
45 | pg_addr = kmap(page); | 45 | pg_addr = kmap(page); |
46 | address &= PAGE_MASK; | 46 | address &= PAGE_MASK; |
47 | pos = address - area->vm_start + (area->vm_pgoff << PAGE_SHIFT); | 47 | pos = address - area->vm_start + (area->vm_pgoff << PAGE_SHIFT); |
48 | 48 | ||
49 | count = PAGE_SIZE; | 49 | count = PAGE_SIZE; |
50 | if (address + PAGE_SIZE > area->vm_end) { | 50 | if (address + PAGE_SIZE > area->vm_end) { |
51 | count = area->vm_end - address; | 51 | count = area->vm_end - address; |
52 | } | 52 | } |
53 | /* what we can read in one go */ | 53 | /* what we can read in one go */ |
54 | bufsize = NCP_SERVER(inode)->buffer_size; | 54 | bufsize = NCP_SERVER(inode)->buffer_size; |
55 | 55 | ||
56 | already_read = 0; | 56 | already_read = 0; |
57 | if (ncp_make_open(inode, O_RDONLY) >= 0) { | 57 | if (ncp_make_open(inode, O_RDONLY) >= 0) { |
58 | while (already_read < count) { | 58 | while (already_read < count) { |
59 | int read_this_time; | 59 | int read_this_time; |
60 | int to_read; | 60 | int to_read; |
61 | 61 | ||
62 | to_read = bufsize - (pos % bufsize); | 62 | to_read = bufsize - (pos % bufsize); |
63 | 63 | ||
64 | to_read = min_t(unsigned int, to_read, count - already_read); | 64 | to_read = min_t(unsigned int, to_read, count - already_read); |
65 | 65 | ||
66 | if (ncp_read_kernel(NCP_SERVER(inode), | 66 | if (ncp_read_kernel(NCP_SERVER(inode), |
67 | NCP_FINFO(inode)->file_handle, | 67 | NCP_FINFO(inode)->file_handle, |
68 | pos, to_read, | 68 | pos, to_read, |
69 | pg_addr + already_read, | 69 | pg_addr + already_read, |
70 | &read_this_time) != 0) { | 70 | &read_this_time) != 0) { |
71 | read_this_time = 0; | 71 | read_this_time = 0; |
72 | } | 72 | } |
73 | pos += read_this_time; | 73 | pos += read_this_time; |
74 | already_read += read_this_time; | 74 | already_read += read_this_time; |
75 | 75 | ||
76 | if (read_this_time < to_read) { | 76 | if (read_this_time < to_read) { |
77 | break; | 77 | break; |
78 | } | 78 | } |
79 | } | 79 | } |
80 | ncp_inode_close(inode); | 80 | ncp_inode_close(inode); |
81 | 81 | ||
82 | } | 82 | } |
83 | 83 | ||
84 | if (already_read < PAGE_SIZE) | 84 | if (already_read < PAGE_SIZE) |
85 | memset(pg_addr + already_read, 0, PAGE_SIZE - already_read); | 85 | memset(pg_addr + already_read, 0, PAGE_SIZE - already_read); |
86 | flush_dcache_page(page); | 86 | flush_dcache_page(page); |
87 | kunmap(page); | 87 | kunmap(page); |
88 | 88 | ||
89 | /* | 89 | /* |
90 | * If I understand ncp_read_kernel() properly, the above always | 90 | * If I understand ncp_read_kernel() properly, the above always |
91 | * fetches from the network, here the analogue of disk. | 91 | * fetches from the network, here the analogue of disk. |
92 | * -- wli | 92 | * -- wli |
93 | */ | 93 | */ |
94 | if (type) | 94 | if (type) |
95 | *type = VM_FAULT_MAJOR; | 95 | *type = VM_FAULT_MAJOR; |
96 | count_vm_event(PGMAJFAULT); | 96 | count_vm_event(PGMAJFAULT); |
97 | return page; | 97 | return page; |
98 | } | 98 | } |
99 | 99 | ||
100 | static struct vm_operations_struct ncp_file_mmap = | 100 | static struct vm_operations_struct ncp_file_mmap = |
101 | { | 101 | { |
102 | .nopage = ncp_file_mmap_nopage, | 102 | .nopage = ncp_file_mmap_nopage, |
103 | }; | 103 | }; |
104 | 104 | ||
105 | 105 | ||
106 | /* This is used for a general mmap of a ncp file */ | 106 | /* This is used for a general mmap of a ncp file */ |
107 | int ncp_mmap(struct file *file, struct vm_area_struct *vma) | 107 | int ncp_mmap(struct file *file, struct vm_area_struct *vma) |
108 | { | 108 | { |
109 | struct inode *inode = file->f_dentry->d_inode; | 109 | struct inode *inode = file->f_path.dentry->d_inode; |
110 | 110 | ||
111 | DPRINTK("ncp_mmap: called\n"); | 111 | DPRINTK("ncp_mmap: called\n"); |
112 | 112 | ||
113 | if (!ncp_conn_valid(NCP_SERVER(inode))) | 113 | if (!ncp_conn_valid(NCP_SERVER(inode))) |
114 | return -EIO; | 114 | return -EIO; |
115 | 115 | ||
116 | /* only PAGE_COW or read-only supported now */ | 116 | /* only PAGE_COW or read-only supported now */ |
117 | if (vma->vm_flags & VM_SHARED) | 117 | if (vma->vm_flags & VM_SHARED) |
118 | return -EINVAL; | 118 | return -EINVAL; |
119 | /* we do not support files bigger than 4GB... We eventually | 119 | /* we do not support files bigger than 4GB... We eventually |
120 | supports just 4GB... */ | 120 | supports just 4GB... */ |
121 | if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff | 121 | if (((vma->vm_end - vma->vm_start) >> PAGE_SHIFT) + vma->vm_pgoff |
122 | > (1U << (32 - PAGE_SHIFT))) | 122 | > (1U << (32 - PAGE_SHIFT))) |
123 | return -EFBIG; | 123 | return -EFBIG; |
124 | 124 | ||
125 | vma->vm_ops = &ncp_file_mmap; | 125 | vma->vm_ops = &ncp_file_mmap; |
126 | file_accessed(file); | 126 | file_accessed(file); |
127 | return 0; | 127 | return 0; |
128 | } | 128 | } |
129 | 129 |