]> git.proxmox.com Git - mirror_ubuntu-artful-kernel.git/blame - fs/ncpfs/inode.c
perf report: Drop cycles 0 for LBR print
[mirror_ubuntu-artful-kernel.git] / fs / ncpfs / inode.c
CommitLineData
1da177e4
LT
1/*
2 * inode.c
3 *
4 * Copyright (C) 1995, 1996 by Volker Lendecke
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
7 * Modified 1998 Wolfram Pienkoss for NLS
8 * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
9 *
10 */
11
b41f8b84
JP
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
1da177e4
LT
14#include <linux/module.h>
15
7c0f6ba6 16#include <linux/uaccess.h>
1da177e4
LT
17#include <asm/byteorder.h>
18
19#include <linux/time.h>
20#include <linux/kernel.h>
21#include <linux/mm.h>
22#include <linux/string.h>
23#include <linux/stat.h>
24#include <linux/errno.h>
25#include <linux/file.h>
26#include <linux/fcntl.h>
27#include <linux/slab.h>
28#include <linux/vmalloc.h>
29#include <linux/init.h>
1da177e4 30#include <linux/vfs.h>
564cd138
MS
31#include <linux/mount.h>
32#include <linux/seq_file.h>
3f07c014 33#include <linux/sched/signal.h>
34286d66 34#include <linux/namei.h>
1da177e4 35
1da177e4
LT
36#include <net/sock.h>
37
32c419d9 38#include "ncp_fs.h"
1da177e4
LT
39#include "getopt.h"
40
564cd138
MS
41#define NCP_DEFAULT_FILE_MODE 0600
42#define NCP_DEFAULT_DIR_MODE 0700
43#define NCP_DEFAULT_TIME_OUT 10
44#define NCP_DEFAULT_RETRY_COUNT 20
45
94ee8494 46static void ncp_evict_inode(struct inode *);
1da177e4 47static void ncp_put_super(struct super_block *);
726c3342 48static int ncp_statfs(struct dentry *, struct kstatfs *);
34c80b1d 49static int ncp_show_options(struct seq_file *, struct dentry *);
1da177e4 50
e18b890b 51static struct kmem_cache * ncp_inode_cachep;
1da177e4
LT
52
53static struct inode *ncp_alloc_inode(struct super_block *sb)
54{
55 struct ncp_inode_info *ei;
e94b1766 56 ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
1da177e4
LT
57 if (!ei)
58 return NULL;
59 return &ei->vfs_inode;
60}
61
fa0d7e3d 62static void ncp_i_callback(struct rcu_head *head)
1da177e4 63{
fa0d7e3d 64 struct inode *inode = container_of(head, struct inode, i_rcu);
1da177e4
LT
65 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
66}
67
fa0d7e3d
NP
68static void ncp_destroy_inode(struct inode *inode)
69{
70 call_rcu(&inode->i_rcu, ncp_i_callback);
71}
72
51cc5068 73static void init_once(void *foo)
1da177e4
LT
74{
75 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
76
a35afb83
CL
77 mutex_init(&ei->open_mutex);
78 inode_init_once(&ei->vfs_inode);
1da177e4 79}
20c2df83 80
1da177e4
LT
81static int init_inodecache(void)
82{
83 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
84 sizeof(struct ncp_inode_info),
fffb60f9 85 0, (SLAB_RECLAIM_ACCOUNT|
5d097056 86 SLAB_MEM_SPREAD|SLAB_ACCOUNT),
20c2df83 87 init_once);
1da177e4
LT
88 if (ncp_inode_cachep == NULL)
89 return -ENOMEM;
90 return 0;
91}
92
93static void destroy_inodecache(void)
94{
8c0a8537
KS
95 /*
96 * Make sure all delayed rcu free inodes are flushed before we
97 * destroy cache.
98 */
99 rcu_barrier();
1a1d92c1 100 kmem_cache_destroy(ncp_inode_cachep);
1da177e4
LT
101}
102
103static int ncp_remount(struct super_block *sb, int *flags, char* data)
104{
02b9984d 105 sync_filesystem(sb);
1da177e4
LT
106 *flags |= MS_NODIRATIME;
107 return 0;
108}
109
ee9b6d61 110static const struct super_operations ncp_sops =
1da177e4
LT
111{
112 .alloc_inode = ncp_alloc_inode,
113 .destroy_inode = ncp_destroy_inode,
114 .drop_inode = generic_delete_inode,
94ee8494 115 .evict_inode = ncp_evict_inode,
1da177e4
LT
116 .put_super = ncp_put_super,
117 .statfs = ncp_statfs,
118 .remount_fs = ncp_remount,
564cd138 119 .show_options = ncp_show_options,
1da177e4
LT
120};
121
1da177e4
LT
122/*
123 * Fill in the ncpfs-specific information in the inode.
124 */
125static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
126{
127 NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
128 NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
129 NCP_FINFO(inode)->volNumber = nwinfo->volume;
130}
131
132void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
133{
134 ncp_update_dirent(inode, nwinfo);
135 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
136 NCP_FINFO(inode)->access = nwinfo->access;
137 memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
138 sizeof(nwinfo->file_handle));
d3b73ca1 139 ncp_dbg(1, "updated %s, volnum=%d, dirent=%u\n",
1da177e4
LT
140 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
141 NCP_FINFO(inode)->dirEntNum);
142}
143
144static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
145{
146 /* NFS namespace mode overrides others if it's set. */
d3b73ca1 147 ncp_dbg(1, "(%s) nfs.mode=0%o\n", nwi->entryName, nwi->nfs.mode);
1da177e4
LT
148 if (nwi->nfs.mode) {
149 /* XXX Security? */
150 inode->i_mode = nwi->nfs.mode;
151 }
152
2e54eb96 153 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
1da177e4
LT
154
155 inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
156 inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
157 inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
158 inode->i_atime.tv_nsec = 0;
159 inode->i_mtime.tv_nsec = 0;
160 inode->i_ctime.tv_nsec = 0;
161}
162
163static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
164{
165 struct nw_info_struct *nwi = &nwinfo->i;
166 struct ncp_server *server = NCP_SERVER(inode);
167
168 if (nwi->attributes & aDIR) {
169 inode->i_mode = server->m.dir_mode;
170 /* for directories dataStreamSize seems to be some
171 Object ID ??? */
2e54eb96 172 i_size_write(inode, NCP_BLOCK_SIZE);
1da177e4 173 } else {
2e54eb96
PV
174 u32 size;
175
1da177e4 176 inode->i_mode = server->m.file_mode;
2e54eb96
PV
177 size = le32_to_cpu(nwi->dataStreamSize);
178 i_size_write(inode, size);
1da177e4
LT
179#ifdef CONFIG_NCPFS_EXTRAS
180 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS))
181 && (nwi->attributes & aSHARED)) {
182 switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
183 case aHIDDEN:
184 if (server->m.flags & NCP_MOUNT_SYMLINKS) {
2e54eb96
PV
185 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
186 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
1da177e4
LT
187 inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
188 NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
189 break;
190 }
191 }
192 /* FALLTHROUGH */
193 case 0:
194 if (server->m.flags & NCP_MOUNT_EXTRAS)
195 inode->i_mode |= S_IRUGO;
196 break;
197 case aSYSTEM:
198 if (server->m.flags & NCP_MOUNT_EXTRAS)
199 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
200 break;
201 /* case aSYSTEM|aHIDDEN: */
202 default:
203 /* reserved combination */
204 break;
205 }
206 }
207#endif
208 }
209 if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
210}
211
212void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
213{
214 NCP_FINFO(inode)->flags = 0;
215 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
216 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
217 ncp_update_attrs(inode, nwinfo);
218 }
219
220 ncp_update_dates(inode, &nwinfo->i);
221 ncp_update_dirent(inode, nwinfo);
222}
223
224/*
2e54eb96 225 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
1da177e4
LT
226 */
227static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
228{
229 struct ncp_server *server = NCP_SERVER(inode);
230
231 NCP_FINFO(inode)->flags = 0;
232
233 ncp_update_attrs(inode, nwinfo);
234
d3b73ca1 235 ncp_dbg(2, "inode->i_mode = %u\n", inode->i_mode);
1da177e4 236
bfe86848 237 set_nlink(inode, 1);
1da177e4
LT
238 inode->i_uid = server->m.uid;
239 inode->i_gid = server->m.gid;
1da177e4
LT
240
241 ncp_update_dates(inode, &nwinfo->i);
242 ncp_update_inode(inode, nwinfo);
243}
244
245#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
92e1d5be 246static const struct inode_operations ncp_symlink_inode_operations = {
6b255391 247 .get_link = page_get_link,
1da177e4
LT
248 .setattr = ncp_notify_change,
249};
250#endif
251
252/*
253 * Get a new inode.
254 */
255struct inode *
256ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
257{
258 struct inode *inode;
259
260 if (info == NULL) {
b41f8b84 261 pr_err("%s: info is NULL\n", __func__);
1da177e4
LT
262 return NULL;
263 }
264
265 inode = new_inode(sb);
266 if (inode) {
267 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
268
269 inode->i_ino = info->ino;
270 ncp_set_attr(inode, info);
271 if (S_ISREG(inode->i_mode)) {
272 inode->i_op = &ncp_file_inode_operations;
273 inode->i_fop = &ncp_file_operations;
274 } else if (S_ISDIR(inode->i_mode)) {
275 inode->i_op = &ncp_dir_inode_operations;
276 inode->i_fop = &ncp_dir_operations;
277#ifdef CONFIG_NCPFS_NFS_NS
278 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
279 init_special_inode(inode, inode->i_mode,
280 new_decode_dev(info->i.nfs.rdev));
281#endif
282#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
283 } else if (S_ISLNK(inode->i_mode)) {
284 inode->i_op = &ncp_symlink_inode_operations;
21fc61c7 285 inode_nohighmem(inode);
1da177e4
LT
286 inode->i_data.a_ops = &ncp_symlink_aops;
287#endif
288 } else {
289 make_bad_inode(inode);
290 }
291 insert_inode_hash(inode);
292 } else
b41f8b84 293 pr_err("%s: iget failed!\n", __func__);
1da177e4
LT
294 return inode;
295}
296
297static void
94ee8494 298ncp_evict_inode(struct inode *inode)
1da177e4 299{
91b0abe3 300 truncate_inode_pages_final(&inode->i_data);
dbd5768f 301 clear_inode(inode);
fef26658 302
1da177e4 303 if (S_ISDIR(inode->i_mode)) {
d3b73ca1 304 ncp_dbg(2, "put directory %ld\n", inode->i_ino);
1da177e4
LT
305 }
306
307 if (ncp_make_closed(inode) != 0) {
308 /* We can't do anything but complain. */
b41f8b84 309 pr_err("%s: could not close\n", __func__);
1da177e4 310 }
1da177e4
LT
311}
312
313static void ncp_stop_tasks(struct ncp_server *server) {
314 struct sock* sk = server->ncp_sock->sk;
2a4df5d3
PV
315
316 lock_sock(sk);
1da177e4
LT
317 sk->sk_error_report = server->error_report;
318 sk->sk_data_ready = server->data_ready;
319 sk->sk_write_space = server->write_space;
2a4df5d3 320 release_sock(sk);
1da177e4 321 del_timer_sync(&server->timeout_tm);
5d8e4bdd 322
43829731 323 flush_work(&server->rcv.tq);
5d8e4bdd 324 if (sk->sk_socket->type == SOCK_STREAM)
43829731 325 flush_work(&server->tx.tq);
5d8e4bdd 326 else
43829731 327 flush_work(&server->timeout_tq);
1da177e4
LT
328}
329
34c80b1d 330static int ncp_show_options(struct seq_file *seq, struct dentry *root)
564cd138 331{
34c80b1d 332 struct ncp_server *server = NCP_SBP(root->d_sb);
564cd138
MS
333 unsigned int tmp;
334
1ac7fd81
EB
335 if (!uid_eq(server->m.uid, GLOBAL_ROOT_UID))
336 seq_printf(seq, ",uid=%u",
337 from_kuid_munged(&init_user_ns, server->m.uid));
338 if (!gid_eq(server->m.gid, GLOBAL_ROOT_GID))
339 seq_printf(seq, ",gid=%u",
340 from_kgid_munged(&init_user_ns, server->m.gid));
341 if (!uid_eq(server->m.mounted_uid, GLOBAL_ROOT_UID))
342 seq_printf(seq, ",owner=%u",
343 from_kuid_munged(&init_user_ns, server->m.mounted_uid));
564cd138
MS
344 tmp = server->m.file_mode & S_IALLUGO;
345 if (tmp != NCP_DEFAULT_FILE_MODE)
346 seq_printf(seq, ",mode=0%o", tmp);
347 tmp = server->m.dir_mode & S_IALLUGO;
348 if (tmp != NCP_DEFAULT_DIR_MODE)
349 seq_printf(seq, ",dirmode=0%o", tmp);
350 if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
351 tmp = server->m.time_out * 100 / HZ;
352 seq_printf(seq, ",timeout=%u", tmp);
353 }
354 if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
355 seq_printf(seq, ",retry=%u", server->m.retry_count);
356 if (server->m.flags != 0)
357 seq_printf(seq, ",flags=%lu", server->m.flags);
358 if (server->m.wdog_pid != NULL)
359 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
360
361 return 0;
362}
363
1da177e4
LT
364static const struct ncp_option ncp_opts[] = {
365 { "uid", OPT_INT, 'u' },
366 { "gid", OPT_INT, 'g' },
367 { "owner", OPT_INT, 'o' },
368 { "mode", OPT_INT, 'm' },
369 { "dirmode", OPT_INT, 'd' },
370 { "timeout", OPT_INT, 't' },
371 { "retry", OPT_INT, 'r' },
372 { "flags", OPT_INT, 'f' },
373 { "wdogpid", OPT_INT, 'w' },
374 { "ncpfd", OPT_INT, 'n' },
375 { "infofd", OPT_INT, 'i' }, /* v5 */
376 { "version", OPT_INT, 'v' },
377 { NULL, 0, 0 } };
378
379static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
380 int optval;
381 char *optarg;
382 unsigned long optint;
383 int version = 0;
1de24126 384 int ret;
1da177e4
LT
385
386 data->flags = 0;
387 data->int_flags = 0;
1ac7fd81 388 data->mounted_uid = GLOBAL_ROOT_UID;
2154227a 389 data->wdog_pid = NULL;
1da177e4 390 data->ncp_fd = ~0;
564cd138
MS
391 data->time_out = NCP_DEFAULT_TIME_OUT;
392 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
1ac7fd81
EB
393 data->uid = GLOBAL_ROOT_UID;
394 data->gid = GLOBAL_ROOT_GID;
564cd138
MS
395 data->file_mode = NCP_DEFAULT_FILE_MODE;
396 data->dir_mode = NCP_DEFAULT_DIR_MODE;
1da177e4
LT
397 data->info_fd = -1;
398 data->mounted_vol[0] = 0;
399
400 while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
1de24126
EB
401 ret = optval;
402 if (ret < 0)
403 goto err;
1da177e4
LT
404 switch (optval) {
405 case 'u':
1ac7fd81 406 data->uid = make_kuid(current_user_ns(), optint);
4fbeb19d
WY
407 if (!uid_valid(data->uid)) {
408 ret = -EINVAL;
1ac7fd81 409 goto err;
4fbeb19d 410 }
1da177e4
LT
411 break;
412 case 'g':
1ac7fd81 413 data->gid = make_kgid(current_user_ns(), optint);
4fbeb19d
WY
414 if (!gid_valid(data->gid)) {
415 ret = -EINVAL;
1ac7fd81 416 goto err;
4fbeb19d 417 }
1da177e4
LT
418 break;
419 case 'o':
1ac7fd81 420 data->mounted_uid = make_kuid(current_user_ns(), optint);
4fbeb19d
WY
421 if (!uid_valid(data->mounted_uid)) {
422 ret = -EINVAL;
1ac7fd81 423 goto err;
4fbeb19d 424 }
1da177e4
LT
425 break;
426 case 'm':
427 data->file_mode = optint;
428 break;
429 case 'd':
430 data->dir_mode = optint;
431 break;
432 case 't':
433 data->time_out = optint;
434 break;
435 case 'r':
436 data->retry_count = optint;
437 break;
438 case 'f':
439 data->flags = optint;
440 break;
441 case 'w':
2154227a 442 data->wdog_pid = find_get_pid(optint);
1da177e4
LT
443 break;
444 case 'n':
445 data->ncp_fd = optint;
446 break;
447 case 'i':
448 data->info_fd = optint;
449 break;
450 case 'v':
1de24126
EB
451 ret = -ECHRNG;
452 if (optint < NCP_MOUNT_VERSION_V4)
453 goto err;
454 if (optint > NCP_MOUNT_VERSION_V5)
455 goto err;
1da177e4
LT
456 version = optint;
457 break;
458
459 }
460 }
461 return 0;
1de24126
EB
462err:
463 put_pid(data->wdog_pid);
464 data->wdog_pid = NULL;
465 return ret;
1da177e4
LT
466}
467
468static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
469{
470 struct ncp_mount_data_kernel data;
471 struct ncp_server *server;
1da177e4 472 struct inode *root_inode;
1da177e4
LT
473 struct socket *sock;
474 int error;
475 int default_bufsize;
476#ifdef CONFIG_NCPFS_PACKET_SIGNING
477 int options;
478#endif
479 struct ncp_entry_info finfo;
480
2a5cac17 481 memset(&data, 0, sizeof(data));
f8314dc6 482 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
1da177e4
LT
483 if (!server)
484 return -ENOMEM;
485 sb->s_fs_info = server;
1da177e4
LT
486
487 error = -EFAULT;
488 if (raw_data == NULL)
489 goto out;
490 switch (*(int*)raw_data) {
491 case NCP_MOUNT_VERSION:
492 {
493 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
494
495 data.flags = md->flags;
496 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
1ac7fd81 497 data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
2154227a 498 data.wdog_pid = find_get_pid(md->wdog_pid);
1da177e4
LT
499 data.ncp_fd = md->ncp_fd;
500 data.time_out = md->time_out;
501 data.retry_count = md->retry_count;
1ac7fd81
EB
502 data.uid = make_kuid(current_user_ns(), md->uid);
503 data.gid = make_kgid(current_user_ns(), md->gid);
1da177e4
LT
504 data.file_mode = md->file_mode;
505 data.dir_mode = md->dir_mode;
506 data.info_fd = -1;
507 memcpy(data.mounted_vol, md->mounted_vol,
508 NCP_VOLNAME_LEN+1);
509 }
510 break;
511 case NCP_MOUNT_VERSION_V4:
512 {
513 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
514
515 data.flags = md->flags;
1ac7fd81 516 data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
2154227a 517 data.wdog_pid = find_get_pid(md->wdog_pid);
1da177e4
LT
518 data.ncp_fd = md->ncp_fd;
519 data.time_out = md->time_out;
520 data.retry_count = md->retry_count;
1ac7fd81
EB
521 data.uid = make_kuid(current_user_ns(), md->uid);
522 data.gid = make_kgid(current_user_ns(), md->gid);
1da177e4
LT
523 data.file_mode = md->file_mode;
524 data.dir_mode = md->dir_mode;
525 data.info_fd = -1;
1da177e4
LT
526 }
527 break;
528 default:
529 error = -ECHRNG;
530 if (memcmp(raw_data, "vers", 4) == 0) {
531 error = ncp_parse_options(&data, raw_data);
532 }
533 if (error)
534 goto out;
535 break;
536 }
1ac7fd81
EB
537 error = -EINVAL;
538 if (!uid_valid(data.mounted_uid) || !uid_valid(data.uid) ||
539 !gid_valid(data.gid))
540 goto out;
44ba8406 541 sock = sockfd_lookup(data.ncp_fd, &error);
1da177e4 542 if (!sock)
44ba8406
AV
543 goto out;
544
1da177e4
LT
545 if (sock->type == SOCK_STREAM)
546 default_bufsize = 0xF000;
547 else
548 default_bufsize = 1024;
549
550 sb->s_flags |= MS_NODIRATIME; /* probably even noatime */
551 sb->s_maxbytes = 0xFFFFFFFFU;
552 sb->s_blocksize = 1024; /* Eh... Is this correct? */
553 sb->s_blocksize_bits = 10;
554 sb->s_magic = NCP_SUPER_MAGIC;
555 sb->s_op = &ncp_sops;
0378c405 556 sb->s_d_op = &ncp_dentry_operations;
f1970c73 557 sb->s_bdi = &server->bdi;
1da177e4
LT
558
559 server = NCP_SBP(sb);
560 memset(server, 0, sizeof(*server));
561
b4caecd4 562 error = bdi_setup_and_register(&server->bdi, "ncpfs");
f1970c73 563 if (error)
759c361e 564 goto out_fput;
f1970c73 565
1da177e4
LT
566 server->ncp_sock = sock;
567
568 if (data.info_fd != -1) {
44ba8406 569 struct socket *info_sock = sockfd_lookup(data.info_fd, &error);
1da177e4 570 if (!info_sock)
44ba8406
AV
571 goto out_bdi;
572 server->info_sock = info_sock;
1da177e4
LT
573 error = -EBADFD;
574 if (info_sock->type != SOCK_STREAM)
575 goto out_fput2;
1da177e4
LT
576 }
577
578/* server->lock = 0; */
8e3f9045 579 mutex_init(&server->mutex);
1da177e4
LT
580 server->packet = NULL;
581/* server->buffer_size = 0; */
582/* server->conn_status = 0; */
583/* server->root_dentry = NULL; */
584/* server->root_setuped = 0; */
2e54eb96 585 mutex_init(&server->root_setup_lock);
1da177e4
LT
586#ifdef CONFIG_NCPFS_PACKET_SIGNING
587/* server->sign_wanted = 0; */
588/* server->sign_active = 0; */
589#endif
2e54eb96 590 init_rwsem(&server->auth_rwsem);
1da177e4
LT
591 server->auth.auth_type = NCP_AUTH_NONE;
592/* server->auth.object_name_len = 0; */
593/* server->auth.object_name = NULL; */
594/* server->auth.object_type = 0; */
595/* server->priv.len = 0; */
596/* server->priv.data = NULL; */
597
598 server->m = data;
25985edc 599 /* Although anything producing this is buggy, it happens
1da177e4
LT
600 now because of PATH_MAX changes.. */
601 if (server->m.time_out < 1) {
602 server->m.time_out = 10;
b41f8b84 603 pr_info("You need to recompile your ncpfs utils..\n");
1da177e4
LT
604 }
605 server->m.time_out = server->m.time_out * HZ / 100;
606 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
607 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
608
609#ifdef CONFIG_NCPFS_NLS
610 /* load the default NLS charsets */
611 server->nls_vol = load_nls_default();
612 server->nls_io = load_nls_default();
613#endif /* CONFIG_NCPFS_NLS */
614
2e54eb96 615 atomic_set(&server->dentry_ttl, 0); /* no caching */
1da177e4
LT
616
617 INIT_LIST_HEAD(&server->tx.requests);
8e3f9045 618 mutex_init(&server->rcv.creq_mutex);
1da177e4
LT
619 server->tx.creq = NULL;
620 server->rcv.creq = NULL;
1da177e4
LT
621
622 init_timer(&server->timeout_tm);
623#undef NCP_PACKET_SIZE
624#define NCP_PACKET_SIZE 131072
625 error = -ENOMEM;
626 server->packet_size = NCP_PACKET_SIZE;
627 server->packet = vmalloc(NCP_PACKET_SIZE);
628 if (server->packet == NULL)
629 goto out_nls;
c5f93cf1
PO
630 server->txbuf = vmalloc(NCP_PACKET_SIZE);
631 if (server->txbuf == NULL)
632 goto out_packet;
633 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
634 if (server->rxbuf == NULL)
635 goto out_txbuf;
1da177e4 636
2a4df5d3
PV
637 lock_sock(sock->sk);
638 server->data_ready = sock->sk->sk_data_ready;
639 server->write_space = sock->sk->sk_write_space;
640 server->error_report = sock->sk->sk_error_report;
641 sock->sk->sk_user_data = server;
1da177e4
LT
642 sock->sk->sk_data_ready = ncp_tcp_data_ready;
643 sock->sk->sk_error_report = ncp_tcp_error_report;
644 if (sock->type == SOCK_STREAM) {
645 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
646 server->rcv.len = 10;
647 server->rcv.state = 0;
c4028958
DH
648 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
649 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
1da177e4
LT
650 sock->sk->sk_write_space = ncp_tcp_write_space;
651 } else {
c4028958
DH
652 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
653 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
1da177e4
LT
654 server->timeout_tm.data = (unsigned long)server;
655 server->timeout_tm.function = ncpdgram_timeout_call;
656 }
2a4df5d3 657 release_sock(sock->sk);
1da177e4
LT
658
659 ncp_lock_server(server);
660 error = ncp_connect(server);
661 ncp_unlock_server(server);
662 if (error < 0)
c5f93cf1 663 goto out_rxbuf;
15a03ac6 664 ncp_dbg(1, "NCP_SBP(sb) = %p\n", NCP_SBP(sb));
1da177e4
LT
665
666 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
667#ifdef CONFIG_NCPFS_PACKET_SIGNING
668 if (ncp_negotiate_size_and_options(server, default_bufsize,
669 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
670 {
671 if (options != NCP_DEFAULT_OPTIONS)
672 {
673 if (ncp_negotiate_size_and_options(server,
674 default_bufsize,
675 options & 2,
676 &(server->buffer_size), &options) != 0)
677
678 {
679 goto out_disconnect;
680 }
681 }
2e54eb96 682 ncp_lock_server(server);
1da177e4
LT
683 if (options & 2)
684 server->sign_wanted = 1;
2e54eb96 685 ncp_unlock_server(server);
1da177e4
LT
686 }
687 else
688#endif /* CONFIG_NCPFS_PACKET_SIGNING */
689 if (ncp_negotiate_buffersize(server, default_bufsize,
690 &(server->buffer_size)) != 0)
691 goto out_disconnect;
d3b73ca1 692 ncp_dbg(1, "bufsize = %d\n", server->buffer_size);
1da177e4
LT
693
694 memset(&finfo, 0, sizeof(finfo));
695 finfo.i.attributes = aDIR;
696 finfo.i.dataStreamSize = 0; /* ignored */
697 finfo.i.dirEntNum = 0;
698 finfo.i.DosDirNum = 0;
699#ifdef CONFIG_NCPFS_SMALLDOS
700 finfo.i.NSCreator = NW_NS_DOS;
701#endif
702 finfo.volume = NCP_NUMBER_OF_VOLUMES;
703 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
704 finfo.i.creationTime = finfo.i.modifyTime
705 = cpu_to_le16(0x0000);
706 finfo.i.creationDate = finfo.i.modifyDate
707 = finfo.i.lastAccessDate
708 = cpu_to_le16(0x0C21);
709 finfo.i.nameLen = 0;
710 finfo.i.entryName[0] = '\0';
711
712 finfo.opened = 0;
713 finfo.ino = 2; /* tradition */
714
715 server->name_space[finfo.volume] = NW_NS_DOS;
716
717 error = -ENOMEM;
718 root_inode = ncp_iget(sb, &finfo);
719 if (!root_inode)
720 goto out_disconnect;
d3b73ca1 721 ncp_dbg(1, "root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
48fde701 722 sb->s_root = d_make_root(root_inode);
1da177e4 723 if (!sb->s_root)
48fde701 724 goto out_disconnect;
1da177e4
LT
725 return 0;
726
1da177e4
LT
727out_disconnect:
728 ncp_lock_server(server);
729 ncp_disconnect(server);
730 ncp_unlock_server(server);
c5f93cf1 731out_rxbuf:
1da177e4 732 ncp_stop_tasks(server);
c5f93cf1
PO
733 vfree(server->rxbuf);
734out_txbuf:
735 vfree(server->txbuf);
736out_packet:
1da177e4
LT
737 vfree(server->packet);
738out_nls:
739#ifdef CONFIG_NCPFS_NLS
740 unload_nls(server->nls_io);
741 unload_nls(server->nls_vol);
742#endif
2e54eb96
PV
743 mutex_destroy(&server->rcv.creq_mutex);
744 mutex_destroy(&server->root_setup_lock);
745 mutex_destroy(&server->mutex);
1da177e4 746out_fput2:
44ba8406
AV
747 if (server->info_sock)
748 sockfd_put(server->info_sock);
f1970c73 749out_bdi:
759c361e
DH
750 bdi_destroy(&server->bdi);
751out_fput:
44ba8406 752 sockfd_put(sock);
1da177e4 753out:
1de24126 754 put_pid(data.wdog_pid);
1da177e4
LT
755 sb->s_fs_info = NULL;
756 kfree(server);
757 return error;
758}
759
1dcddd4a
AV
760static void delayed_free(struct rcu_head *p)
761{
762 struct ncp_server *server = container_of(p, struct ncp_server, rcu);
763#ifdef CONFIG_NCPFS_NLS
764 /* unload the NLS charsets */
765 unload_nls(server->nls_vol);
766 unload_nls(server->nls_io);
767#endif /* CONFIG_NCPFS_NLS */
768 kfree(server);
769}
770
1da177e4
LT
771static void ncp_put_super(struct super_block *sb)
772{
773 struct ncp_server *server = NCP_SBP(sb);
774
775 ncp_lock_server(server);
776 ncp_disconnect(server);
777 ncp_unlock_server(server);
778
779 ncp_stop_tasks(server);
780
2e54eb96
PV
781 mutex_destroy(&server->rcv.creq_mutex);
782 mutex_destroy(&server->root_setup_lock);
783 mutex_destroy(&server->mutex);
1da177e4 784
44ba8406
AV
785 if (server->info_sock)
786 sockfd_put(server->info_sock);
787 sockfd_put(server->ncp_sock);
2154227a
EB
788 kill_pid(server->m.wdog_pid, SIGTERM, 1);
789 put_pid(server->m.wdog_pid);
1da177e4 790
f1970c73 791 bdi_destroy(&server->bdi);
44db77f3
PE
792 kfree(server->priv.data);
793 kfree(server->auth.object_name);
c5f93cf1
PO
794 vfree(server->rxbuf);
795 vfree(server->txbuf);
1da177e4 796 vfree(server->packet);
1dcddd4a 797 call_rcu(&server->rcu, delayed_free);
1da177e4
LT
798}
799
726c3342 800static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
1da177e4
LT
801{
802 struct dentry* d;
803 struct inode* i;
804 struct ncp_inode_info* ni;
805 struct ncp_server* s;
806 struct ncp_volume_info vi;
726c3342 807 struct super_block *sb = dentry->d_sb;
1da177e4
LT
808 int err;
809 __u8 dh;
810
811 d = sb->s_root;
812 if (!d) {
813 goto dflt;
814 }
2b0143b5 815 i = d_inode(d);
1da177e4
LT
816 if (!i) {
817 goto dflt;
818 }
819 ni = NCP_FINFO(i);
820 if (!ni) {
821 goto dflt;
822 }
823 s = NCP_SBP(sb);
824 if (!s) {
825 goto dflt;
826 }
827 if (!s->m.mounted_vol[0]) {
828 goto dflt;
829 }
830
831 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
832 if (err) {
833 goto dflt;
834 }
835 err = ncp_get_directory_info(s, dh, &vi);
836 ncp_dirhandle_free(s, dh);
837 if (err) {
838 goto dflt;
839 }
840 buf->f_type = NCP_SUPER_MAGIC;
841 buf->f_bsize = vi.sectors_per_block * 512;
842 buf->f_blocks = vi.total_blocks;
843 buf->f_bfree = vi.free_blocks;
844 buf->f_bavail = vi.free_blocks;
845 buf->f_files = vi.total_dir_entries;
846 buf->f_ffree = vi.available_dir_entries;
847 buf->f_namelen = 12;
848 return 0;
849
850 /* We cannot say how much disk space is left on a mounted
851 NetWare Server, because free space is distributed over
852 volumes, and the current user might have disk quotas. So
853 free space is not that simple to determine. Our decision
854 here is to err conservatively. */
855
856dflt:;
857 buf->f_type = NCP_SUPER_MAGIC;
858 buf->f_bsize = NCP_BLOCK_SIZE;
859 buf->f_blocks = 0;
860 buf->f_bfree = 0;
861 buf->f_bavail = 0;
862 buf->f_namelen = 12;
863 return 0;
864}
865
866int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
867{
2b0143b5 868 struct inode *inode = d_inode(dentry);
1da177e4
LT
869 int result = 0;
870 __le32 info_mask;
871 struct nw_modify_dos_info info;
872 struct ncp_server *server;
873
874 result = -EIO;
875
1da177e4 876 server = NCP_SERVER(inode);
2e54eb96 877 if (!server) /* How this could happen? */
1da177e4
LT
878 goto out;
879
338b2f57 880 result = -EPERM;
2b0143b5 881 if (IS_DEADDIR(d_inode(dentry)))
338b2f57
AV
882 goto out;
883
1da177e4
LT
884 /* ageing the dentry to force validation */
885 ncp_age_dentry(server, dentry);
886
31051c85 887 result = setattr_prepare(dentry, attr);
1da177e4
LT
888 if (result < 0)
889 goto out;
890
891 result = -EPERM;
1ac7fd81 892 if ((attr->ia_valid & ATTR_UID) && !uid_eq(attr->ia_uid, server->m.uid))
1da177e4
LT
893 goto out;
894
1ac7fd81 895 if ((attr->ia_valid & ATTR_GID) && !gid_eq(attr->ia_gid, server->m.gid))
1da177e4
LT
896 goto out;
897
898 if (((attr->ia_valid & ATTR_MODE) &&
899 (attr->ia_mode &
900 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
901 goto out;
902
903 info_mask = 0;
904 memset(&info, 0, sizeof(info));
905
906#if 1
907 if ((attr->ia_valid & ATTR_MODE) != 0)
908 {
909 umode_t newmode = attr->ia_mode;
910
911 info_mask |= DM_ATTRIBUTES;
912
913 if (S_ISDIR(inode->i_mode)) {
914 newmode &= server->m.dir_mode;
915 } else {
916#ifdef CONFIG_NCPFS_EXTRAS
917 if (server->m.flags & NCP_MOUNT_EXTRAS) {
918 /* any non-default execute bit set */
919 if (newmode & ~server->m.file_mode & S_IXUGO)
920 info.attributes |= aSHARED | aSYSTEM;
921 /* read for group/world and not in default file_mode */
922 else if (newmode & ~server->m.file_mode & S_IRUGO)
923 info.attributes |= aSHARED;
924 } else
925#endif
926 newmode &= server->m.file_mode;
927 }
928 if (newmode & S_IWUGO)
929 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
930 else
931 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
932
933#ifdef CONFIG_NCPFS_NFS_NS
934 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
935 result = ncp_modify_nfs_info(server,
936 NCP_FINFO(inode)->volNumber,
937 NCP_FINFO(inode)->dirEntNum,
938 attr->ia_mode, 0);
939 if (result != 0)
940 goto out;
941 info.attributes &= ~(aSHARED | aSYSTEM);
942 {
943 /* mark partial success */
944 struct iattr tmpattr;
945
946 tmpattr.ia_valid = ATTR_MODE;
947 tmpattr.ia_mode = attr->ia_mode;
948
1025774c
CH
949 setattr_copy(inode, &tmpattr);
950 mark_inode_dirty(inode);
1da177e4
LT
951 }
952 }
953#endif
954 }
955#endif
956
957 /* Do SIZE before attributes, otherwise mtime together with size does not work...
958 */
959 if ((attr->ia_valid & ATTR_SIZE) != 0) {
960 int written;
961
15a03ac6 962 ncp_dbg(1, "trying to change size to %llu\n", attr->ia_size);
1da177e4
LT
963
964 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
965 result = -EACCES;
966 goto out;
967 }
968 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
969 attr->ia_size, 0, "", &written);
970
971 /* According to ndir, the changes only take effect after
972 closing the file */
973 ncp_inode_close(inode);
974 result = ncp_make_closed(inode);
975 if (result)
976 goto out;
1025774c
CH
977
978 if (attr->ia_size != i_size_read(inode)) {
3e7a8069 979 truncate_setsize(inode, attr->ia_size);
1025774c 980 mark_inode_dirty(inode);
1da177e4
LT
981 }
982 }
983 if ((attr->ia_valid & ATTR_CTIME) != 0) {
984 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
985 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
986 &info.creationTime, &info.creationDate);
987 }
988 if ((attr->ia_valid & ATTR_MTIME) != 0) {
989 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
990 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
991 &info.modifyTime, &info.modifyDate);
992 }
993 if ((attr->ia_valid & ATTR_ATIME) != 0) {
994 __le16 dummy;
995 info_mask |= (DM_LAST_ACCESS_DATE);
996 ncp_date_unix2dos(attr->ia_atime.tv_sec,
997 &dummy, &info.lastAccessDate);
998 }
999 if (info_mask != 0) {
1000 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
1001 inode, info_mask, &info);
1002 if (result != 0) {
1da177e4
LT
1003 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1004 /* NetWare seems not to allow this. I
1005 do not know why. So, just tell the
1006 user everything went fine. This is
1007 a terrible hack, but I do not know
1008 how to do this correctly. */
1009 result = 0;
1010 } else
1011 goto out;
1012 }
1013#ifdef CONFIG_NCPFS_STRONG
1014 if ((!result) && (info_mask & DM_ATTRIBUTES))
1015 NCP_FINFO(inode)->nwattr = info.attributes;
1016#endif
1017 }
1025774c
CH
1018 if (result)
1019 goto out;
1020
1021 setattr_copy(inode, attr);
1022 mark_inode_dirty(inode);
1023
1da177e4 1024out:
2e54eb96
PV
1025 if (result > 0)
1026 result = -EACCES;
1da177e4
LT
1027 return result;
1028}
1029
3c26ff6e
AV
1030static struct dentry *ncp_mount(struct file_system_type *fs_type,
1031 int flags, const char *dev_name, void *data)
1da177e4 1032{
3c26ff6e 1033 return mount_nodev(fs_type, flags, data, ncp_fill_super);
1da177e4
LT
1034}
1035
1036static struct file_system_type ncp_fs_type = {
1037 .owner = THIS_MODULE,
1038 .name = "ncpfs",
3c26ff6e 1039 .mount = ncp_mount,
1da177e4 1040 .kill_sb = kill_anon_super,
564cd138 1041 .fs_flags = FS_BINARY_MOUNTDATA,
1da177e4 1042};
7f78e035 1043MODULE_ALIAS_FS("ncpfs");
1da177e4
LT
1044
1045static int __init init_ncp_fs(void)
1046{
1047 int err;
d3b73ca1 1048 ncp_dbg(1, "called\n");
1da177e4 1049
1da177e4
LT
1050 err = init_inodecache();
1051 if (err)
1052 goto out1;
1053 err = register_filesystem(&ncp_fs_type);
1054 if (err)
1055 goto out;
1056 return 0;
1057out:
1058 destroy_inodecache();
1059out1:
1060 return err;
1061}
1062
1063static void __exit exit_ncp_fs(void)
1064{
d3b73ca1 1065 ncp_dbg(1, "called\n");
1da177e4
LT
1066 unregister_filesystem(&ncp_fs_type);
1067 destroy_inodecache();
1da177e4
LT
1068}
1069
1070module_init(init_ncp_fs)
1071module_exit(exit_ncp_fs)
1072MODULE_LICENSE("GPL");