summaryrefslogtreecommitdiffstats
path: root/fs/ncpfs
diff options
context:
space:
mode:
authorStephen Hemminger <stephen@networkplumber.org>2017-11-14 11:37:15 -0500
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2017-11-28 07:55:01 -0500
commit1bb8155080c652c4853e6228f8f0d262b3049699 (patch)
tree04bcb6824789224bb16dd9a35fd5fc454881d616 /fs/ncpfs
parente02554e9a4338c58e75fdfb0ef908a5adc86cba5 (diff)
ncpfs: move net/ncpfs to drivers/staging/ncpfs
The Netware Core Protocol is a file system that talks to Netware clients over IPX. Since IPX has been dead for many years move the file system into staging for eventual interment. Signed-off-by: Stephen Hemminger <stephen@networkplumber.org> Acked-by: David S. Miller <davem@davemloft.net> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Diffstat (limited to 'fs/ncpfs')
-rw-r--r--fs/ncpfs/Kconfig108
-rw-r--r--fs/ncpfs/Makefile17
-rw-r--r--fs/ncpfs/dir.c1232
-rw-r--r--fs/ncpfs/file.c263
-rw-r--r--fs/ncpfs/getopt.c76
-rw-r--r--fs/ncpfs/getopt.h17
-rw-r--r--fs/ncpfs/inode.c1066
-rw-r--r--fs/ncpfs/ioctl.c923
-rw-r--r--fs/ncpfs/mmap.c125
-rw-r--r--fs/ncpfs/ncp_fs.h101
-rw-r--r--fs/ncpfs/ncp_fs_i.h31
-rw-r--r--fs/ncpfs/ncp_fs_sb.h174
-rw-r--r--fs/ncpfs/ncplib_kernel.c1322
-rw-r--r--fs/ncpfs/ncplib_kernel.h215
-rw-r--r--fs/ncpfs/ncpsign_kernel.c128
-rw-r--r--fs/ncpfs/ncpsign_kernel.h27
-rw-r--r--fs/ncpfs/sock.c854
-rw-r--r--fs/ncpfs/symlink.c182
18 files changed, 0 insertions, 6861 deletions
diff --git a/fs/ncpfs/Kconfig b/fs/ncpfs/Kconfig
deleted file mode 100644
index c931cf22a1f6..000000000000
--- a/fs/ncpfs/Kconfig
+++ /dev/null
@@ -1,108 +0,0 @@
1#
2# NCP Filesystem configuration
3#
4config NCP_FS
5 tristate "NCP file system support (to mount NetWare volumes)"
6 depends on IPX!=n || INET
7 help
8 NCP (NetWare Core Protocol) is a protocol that runs over IPX and is
9 used by Novell NetWare clients to talk to file servers. It is to
10 IPX what NFS is to TCP/IP, if that helps. Saying Y here allows you
11 to mount NetWare file server volumes and to access them just like
12 any other Unix directory. For details, please read the file
13 <file:Documentation/filesystems/ncpfs.txt> in the kernel source and
14 the IPX-HOWTO from <http://www.tldp.org/docs.html#howto>.
15
16 You do not have to say Y here if you want your Linux box to act as a
17 file *server* for Novell NetWare clients.
18
19 General information about how to connect Linux, Windows machines and
20 Macs is on the WWW at <http://www.eats.com/linux_mac_win.html>.
21
22 To compile this as a module, choose M here: the module will be called
23 ncpfs. Say N unless you are connected to a Novell network.
24
25config NCPFS_PACKET_SIGNING
26 bool "Packet signatures"
27 depends on NCP_FS
28 help
29 NCP allows packets to be signed for stronger security. If you want
30 security, say Y. Normal users can leave it off. To be able to use
31 packet signing you must use ncpfs > 2.0.12.
32
33config NCPFS_IOCTL_LOCKING
34 bool "Proprietary file locking"
35 depends on NCP_FS
36 help
37 Allows locking of records on remote volumes. Say N unless you have
38 special applications which are able to utilize this locking scheme.
39
40config NCPFS_STRONG
41 bool "Clear remove/delete inhibit when needed"
42 depends on NCP_FS
43 help
44 Allows manipulation of files flagged as Delete or Rename Inhibit.
45 To use this feature you must mount volumes with the ncpmount
46 parameter "-s" (ncpfs-2.0.12 and newer). Say Y unless you are not
47 mounting volumes with -f 444.
48
49config NCPFS_NFS_NS
50 bool "Use NFS namespace if available"
51 depends on NCP_FS
52 help
53 Allows you to utilize NFS namespace on NetWare servers. It brings
54 you case sensitive filenames. Say Y. You can disable it at
55 mount-time with the `-N nfs' parameter of ncpmount.
56
57config NCPFS_OS2_NS
58 bool "Use LONG (OS/2) namespace if available"
59 depends on NCP_FS
60 help
61 Allows you to utilize OS2/LONG namespace on NetWare servers.
62 Filenames in this namespace are limited to 255 characters, they are
63 case insensitive, and case in names is preserved. Say Y. You can
64 disable it at mount time with the -N os2 parameter of ncpmount.
65
66config NCPFS_SMALLDOS
67 bool "Lowercase DOS filenames"
68 depends on NCP_FS
69 ---help---
70 If you say Y here, every filename on a NetWare server volume using
71 the OS2/LONG namespace and created under DOS or on a volume using
72 DOS namespace will be converted to lowercase characters.
73 Saying N here will give you these filenames in uppercase.
74
75 This is only a cosmetic option since the OS2/LONG namespace is case
76 insensitive. The only major reason for this option is backward
77 compatibility when moving from DOS to OS2/LONG namespace support.
78 Long filenames (created by Win95) will not be affected.
79
80 This option does not solve the problem that filenames appear
81 differently under Linux and under Windows, since Windows does an
82 additional conversions on the client side. You can achieve similar
83 effects by saying Y to "Allow using of Native Language Support"
84 below.
85
86config NCPFS_NLS
87 bool "Use Native Language Support"
88 depends on NCP_FS
89 select NLS
90 help
91 Allows you to use codepages and I/O charsets for file name
92 translation between the server file system and input/output. This
93 may be useful, if you want to access the server with other operating
94 systems, e.g. Windows 95. See also NLS for more Information.
95
96 To select codepages and I/O charsets use ncpfs-2.2.0.13 or newer.
97
98config NCPFS_EXTRAS
99 bool "Enable symbolic links and execute flags"
100 depends on NCP_FS
101 help
102 This enables the use of symbolic links and an execute permission
103 bit on NCPFS. The file server need not have long name space or NFS
104 name space loaded for these to work.
105
106 To use the new attributes, it is recommended to use the flags
107 '-f 600 -d 755' on the ncpmount command line.
108
diff --git a/fs/ncpfs/Makefile b/fs/ncpfs/Makefile
deleted file mode 100644
index 66fe5f878817..000000000000
--- a/fs/ncpfs/Makefile
+++ /dev/null
@@ -1,17 +0,0 @@
1# SPDX-License-Identifier: GPL-2.0
2#
3# Makefile for the linux ncp filesystem routines.
4#
5
6obj-$(CONFIG_NCP_FS) += ncpfs.o
7
8ncpfs-y := dir.o file.o inode.o ioctl.o mmap.o ncplib_kernel.o sock.o \
9 ncpsign_kernel.o getopt.o
10
11ncpfs-$(CONFIG_NCPFS_EXTRAS) += symlink.o
12ncpfs-$(CONFIG_NCPFS_NFS_NS) += symlink.o
13
14# If you want debugging output, please uncomment the following line
15# ccflags-y := -DDEBUG_NCP=1
16
17CFLAGS_ncplib_kernel.o := -finline-functions
diff --git a/fs/ncpfs/dir.c b/fs/ncpfs/dir.c
deleted file mode 100644
index 0c57c5c5d40a..000000000000
--- a/fs/ncpfs/dir.c
+++ /dev/null
@@ -1,1232 +0,0 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * dir.c
4 *
5 * Copyright (C) 1995, 1996 by Volker Lendecke
6 * Modified for big endian by J.F. Chadima and David S. Miller
7 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
8 * Modified 1998, 1999 Wolfram Pienkoss for NLS
9 * Modified 1999 Wolfram Pienkoss for directory caching
10 * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
11 *
12 */
13
14
15#include <linux/time.h>
16#include <linux/errno.h>
17#include <linux/stat.h>
18#include <linux/kernel.h>
19#include <linux/vmalloc.h>
20#include <linux/mm.h>
21#include <linux/namei.h>
22#include <linux/uaccess.h>
23#include <asm/byteorder.h>
24
25#include "ncp_fs.h"
26
27static void ncp_read_volume_list(struct file *, struct dir_context *,
28 struct ncp_cache_control *);
29static void ncp_do_readdir(struct file *, struct dir_context *,
30 struct ncp_cache_control *);
31
32static int ncp_readdir(struct file *, struct dir_context *);
33
34static int ncp_create(struct inode *, struct dentry *, umode_t, bool);
35static struct dentry *ncp_lookup(struct inode *, struct dentry *, unsigned int);
36static int ncp_unlink(struct inode *, struct dentry *);
37static int ncp_mkdir(struct inode *, struct dentry *, umode_t);
38static int ncp_rmdir(struct inode *, struct dentry *);
39static int ncp_rename(struct inode *, struct dentry *,
40 struct inode *, struct dentry *, unsigned int);
41static int ncp_mknod(struct inode * dir, struct dentry *dentry,
42 umode_t mode, dev_t rdev);
43#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
44extern int ncp_symlink(struct inode *, struct dentry *, const char *);
45#else
46#define ncp_symlink NULL
47#endif
48
49const struct file_operations ncp_dir_operations =
50{
51 .llseek = generic_file_llseek,
52 .read = generic_read_dir,
53 .iterate = ncp_readdir,
54 .unlocked_ioctl = ncp_ioctl,
55#ifdef CONFIG_COMPAT
56 .compat_ioctl = ncp_compat_ioctl,
57#endif
58};
59
60const struct inode_operations ncp_dir_inode_operations =
61{
62 .create = ncp_create,
63 .lookup = ncp_lookup,
64 .unlink = ncp_unlink,
65 .symlink = ncp_symlink,
66 .mkdir = ncp_mkdir,
67 .rmdir = ncp_rmdir,
68 .mknod = ncp_mknod,
69 .rename = ncp_rename,
70 .setattr = ncp_notify_change,
71};
72
73/*
74 * Dentry operations routines
75 */
76static int ncp_lookup_validate(struct dentry *, unsigned int);
77static int ncp_hash_dentry(const struct dentry *, struct qstr *);
78static int ncp_compare_dentry(const struct dentry *,
79 unsigned int, const char *, const struct qstr *);
80static int ncp_delete_dentry(const struct dentry *);
81static void ncp_d_prune(struct dentry *dentry);
82
83const struct dentry_operations ncp_dentry_operations =
84{
85 .d_revalidate = ncp_lookup_validate,
86 .d_hash = ncp_hash_dentry,
87 .d_compare = ncp_compare_dentry,
88 .d_delete = ncp_delete_dentry,
89 .d_prune = ncp_d_prune,
90};
91
92#define ncp_namespace(i) (NCP_SERVER(i)->name_space[NCP_FINFO(i)->volNumber])
93
94static inline int ncp_preserve_entry_case(struct inode *i, __u32 nscreator)
95{
96#ifdef CONFIG_NCPFS_SMALLDOS
97 int ns = ncp_namespace(i);
98
99 if ((ns == NW_NS_DOS)
100#ifdef CONFIG_NCPFS_OS2_NS
101 || ((ns == NW_NS_OS2) && (nscreator == NW_NS_DOS))
102#endif /* CONFIG_NCPFS_OS2_NS */
103 )
104 return 0;
105#endif /* CONFIG_NCPFS_SMALLDOS */
106 return 1;
107}
108
109#define ncp_preserve_case(i) (ncp_namespace(i) != NW_NS_DOS)
110
111static inline int ncp_case_sensitive(const struct inode *i)
112{
113#ifdef CONFIG_NCPFS_NFS_NS
114 return ncp_namespace(i) == NW_NS_NFS;
115#else
116 return 0;
117#endif /* CONFIG_NCPFS_NFS_NS */
118}
119
120/*
121 * Note: leave the hash unchanged if the directory
122 * is case-sensitive.
123 */
124static int
125ncp_hash_dentry(const struct dentry *dentry, struct qstr *this)
126{
127 struct inode *inode = d_inode_rcu(dentry);
128
129 if (!inode)
130 return 0;
131
132 if (!ncp_case_sensitive(inode)) {
133 struct nls_table *t;
134 unsigned long hash;
135 int i;
136
137 t = NCP_IO_TABLE(dentry->d_sb);
138 hash = init_name_hash(dentry);
139 for (i=0; i<this->len ; i++)
140 hash = partial_name_hash(ncp_tolower(t, this->name[i]),
141 hash);
142 this->hash = end_name_hash(hash);
143 }
144 return 0;
145}
146
147static int
148ncp_compare_dentry(const struct dentry *dentry,
149 unsigned int len, const char *str, const struct qstr *name)
150{
151 struct inode *pinode;
152
153 if (len != name->len)
154 return 1;
155
156 pinode = d_inode_rcu(dentry->d_parent);
157 if (!pinode)
158 return 1;
159
160 if (ncp_case_sensitive(pinode))
161 return strncmp(str, name->name, len);
162
163 return ncp_strnicmp(NCP_IO_TABLE(pinode->i_sb), str, name->name, len);
164}
165
166/*
167 * This is the callback from dput() when d_count is going to 0.
168 * We use this to unhash dentries with bad inodes.
169 * Closing files can be safely postponed until iput() - it's done there anyway.
170 */
171static int
172ncp_delete_dentry(const struct dentry * dentry)
173{
174 struct inode *inode = d_inode(dentry);
175
176 if (inode) {
177 if (is_bad_inode(inode))
178 return 1;
179 } else
180 {
181 /* N.B. Unhash negative dentries? */
182 }
183 return 0;
184}
185
186static inline int
187ncp_single_volume(struct ncp_server *server)
188{
189 return (server->m.mounted_vol[0] != '\0');
190}
191
192static inline int ncp_is_server_root(struct inode *inode)
193{
194 return !ncp_single_volume(NCP_SERVER(inode)) &&
195 is_root_inode(inode);
196}
197
198
199/*
200 * This is the callback when the dcache has a lookup hit.
201 */
202
203
204#ifdef CONFIG_NCPFS_STRONG
205/* try to delete a readonly file (NW R bit set) */
206
207static int
208ncp_force_unlink(struct inode *dir, struct dentry* dentry)
209{
210 int res=0x9c,res2;
211 struct nw_modify_dos_info info;
212 __le32 old_nwattr;
213 struct inode *inode;
214
215 memset(&info, 0, sizeof(info));
216
217 /* remove the Read-Only flag on the NW server */
218 inode = d_inode(dentry);
219
220 old_nwattr = NCP_FINFO(inode)->nwattr;
221 info.attributes = old_nwattr & ~(aRONLY|aDELETEINHIBIT|aRENAMEINHIBIT);
222 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
223 if (res2)
224 goto leave_me;
225
226 /* now try again the delete operation */
227 res = ncp_del_file_or_subdir2(NCP_SERVER(dir), dentry);
228
229 if (res) /* delete failed, set R bit again */
230 {
231 info.attributes = old_nwattr;
232 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(inode), inode, NULL, DM_ATTRIBUTES, &info);
233 if (res2)
234 goto leave_me;
235 }
236leave_me:
237 return(res);
238}
239#endif /* CONFIG_NCPFS_STRONG */
240
241#ifdef CONFIG_NCPFS_STRONG
242static int
243ncp_force_rename(struct inode *old_dir, struct dentry* old_dentry, char *_old_name,
244 struct inode *new_dir, struct dentry* new_dentry, char *_new_name)
245{
246 struct nw_modify_dos_info info;
247 int res=0x90,res2;
248 struct inode *old_inode = d_inode(old_dentry);
249 __le32 old_nwattr = NCP_FINFO(old_inode)->nwattr;
250 __le32 new_nwattr = 0; /* shut compiler warning */
251 int old_nwattr_changed = 0;
252 int new_nwattr_changed = 0;
253
254 memset(&info, 0, sizeof(info));
255
256 /* remove the Read-Only flag on the NW server */
257
258 info.attributes = old_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
259 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
260 if (!res2)
261 old_nwattr_changed = 1;
262 if (new_dentry && d_really_is_positive(new_dentry)) {
263 new_nwattr = NCP_FINFO(d_inode(new_dentry))->nwattr;
264 info.attributes = new_nwattr & ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
265 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
266 if (!res2)
267 new_nwattr_changed = 1;
268 }
269 /* now try again the rename operation */
270 /* but only if something really happened */
271 if (new_nwattr_changed || old_nwattr_changed) {
272 res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
273 old_dir, _old_name,
274 new_dir, _new_name);
275 }
276 if (res)
277 goto leave_me;
278 /* file was successfully renamed, so:
279 do not set attributes on old file - it no longer exists
280 copy attributes from old file to new */
281 new_nwattr_changed = old_nwattr_changed;
282 new_nwattr = old_nwattr;
283 old_nwattr_changed = 0;
284
285leave_me:;
286 if (old_nwattr_changed) {
287 info.attributes = old_nwattr;
288 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(old_inode), old_inode, NULL, DM_ATTRIBUTES, &info);
289 /* ignore errors */
290 }
291 if (new_nwattr_changed) {
292 info.attributes = new_nwattr;
293 res2 = ncp_modify_file_or_subdir_dos_info_path(NCP_SERVER(new_dir), new_dir, _new_name, DM_ATTRIBUTES, &info);
294 /* ignore errors */
295 }
296 return(res);
297}
298#endif /* CONFIG_NCPFS_STRONG */
299
300
301static int
302ncp_lookup_validate(struct dentry *dentry, unsigned int flags)
303{
304 struct ncp_server *server;
305 struct dentry *parent;
306 struct inode *dir;
307 struct ncp_entry_info finfo;
308 int res, val = 0, len;
309 __u8 __name[NCP_MAXPATHLEN + 1];
310
311 if (dentry == dentry->d_sb->s_root)
312 return 1;
313
314 if (flags & LOOKUP_RCU)
315 return -ECHILD;
316
317 parent = dget_parent(dentry);
318 dir = d_inode(parent);
319
320 if (d_really_is_negative(dentry))
321 goto finished;
322
323 server = NCP_SERVER(dir);
324
325 /*
326 * Inspired by smbfs:
327 * The default validation is based on dentry age:
328 * We set the max age at mount time. (But each
329 * successful server lookup renews the timestamp.)
330 */
331 val = NCP_TEST_AGE(server, dentry);
332 if (val)
333 goto finished;
334
335 ncp_dbg(2, "%pd2 not valid, age=%ld, server lookup\n",
336 dentry, NCP_GET_AGE(dentry));
337
338 len = sizeof(__name);
339 if (ncp_is_server_root(dir)) {
340 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
341 dentry->d_name.len, 1);
342 if (!res) {
343 res = ncp_lookup_volume(server, __name, &(finfo.i));
344 if (!res)
345 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
346 }
347 } else {
348 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
349 dentry->d_name.len, !ncp_preserve_case(dir));
350 if (!res)
351 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
352 }
353 finfo.volume = finfo.i.volNumber;
354 ncp_dbg(2, "looked for %pd/%s, res=%d\n",
355 dentry->d_parent, __name, res);
356 /*
357 * If we didn't find it, or if it has a different dirEntNum to
358 * what we remember, it's not valid any more.
359 */
360 if (!res) {
361 struct inode *inode = d_inode(dentry);
362
363 inode_lock(inode);
364 if (finfo.i.dirEntNum == NCP_FINFO(inode)->dirEntNum) {
365 ncp_new_dentry(dentry);
366 val=1;
367 } else
368 ncp_dbg(2, "found, but dirEntNum changed\n");
369
370 ncp_update_inode2(inode, &finfo);
371 inode_unlock(inode);
372 }
373
374finished:
375 ncp_dbg(2, "result=%d\n", val);
376 dput(parent);
377 return val;
378}
379
380static time_t ncp_obtain_mtime(struct dentry *dentry)
381{
382 struct inode *inode = d_inode(dentry);
383 struct ncp_server *server = NCP_SERVER(inode);
384 struct nw_info_struct i;
385
386 if (!ncp_conn_valid(server) || ncp_is_server_root(inode))
387 return 0;
388
389 if (ncp_obtain_info(server, inode, NULL, &i))
390 return 0;
391
392 return ncp_date_dos2unix(i.modifyTime, i.modifyDate);
393}
394
395static inline void
396ncp_invalidate_dircache_entries(struct dentry *parent)
397{
398 struct ncp_server *server = NCP_SERVER(d_inode(parent));
399 struct dentry *dentry;
400
401 spin_lock(&parent->d_lock);
402 list_for_each_entry(dentry, &parent->d_subdirs, d_child) {
403 dentry->d_fsdata = NULL;
404 ncp_age_dentry(server, dentry);
405 }
406 spin_unlock(&parent->d_lock);
407}
408
409static int ncp_readdir(struct file *file, struct dir_context *ctx)
410{
411 struct dentry *dentry = file->f_path.dentry;
412 struct inode *inode = d_inode(dentry);
413 struct page *page = NULL;
414 struct ncp_server *server = NCP_SERVER(inode);
415 union ncp_dir_cache *cache = NULL;
416 struct ncp_cache_control ctl;
417 int result, mtime_valid = 0;
418 time_t mtime = 0;
419
420 ctl.page = NULL;
421 ctl.cache = NULL;
422
423 ncp_dbg(2, "reading %pD2, pos=%d\n", file, (int)ctx->pos);
424
425 result = -EIO;
426 /* Do not generate '.' and '..' when server is dead. */
427 if (!ncp_conn_valid(server))
428 goto out;
429
430 result = 0;
431 if (!dir_emit_dots(file, ctx))
432 goto out;
433
434 page = grab_cache_page(&inode->i_data, 0);
435 if (!page)
436 goto read_really;
437
438 ctl.cache = cache = kmap(page);
439 ctl.head = cache->head;
440
441 if (!PageUptodate(page) || !ctl.head.eof)
442 goto init_cache;
443
444 if (ctx->pos == 2) {
445 if (jiffies - ctl.head.time >= NCP_MAX_AGE(server))
446 goto init_cache;
447
448 mtime = ncp_obtain_mtime(dentry);
449 mtime_valid = 1;
450 if ((!mtime) || (mtime != ctl.head.mtime))
451 goto init_cache;
452 }
453
454 if (ctx->pos > ctl.head.end)
455 goto finished;
456
457 ctl.fpos = ctx->pos + (NCP_DIRCACHE_START - 2);
458 ctl.ofs = ctl.fpos / NCP_DIRCACHE_SIZE;
459 ctl.idx = ctl.fpos % NCP_DIRCACHE_SIZE;
460
461 for (;;) {
462 if (ctl.ofs != 0) {
463 ctl.page = find_lock_page(&inode->i_data, ctl.ofs);
464 if (!ctl.page)
465 goto invalid_cache;
466 ctl.cache = kmap(ctl.page);
467 if (!PageUptodate(ctl.page))
468 goto invalid_cache;
469 }
470 while (ctl.idx < NCP_DIRCACHE_SIZE) {
471 struct dentry *dent;
472 bool over;
473
474 spin_lock(&dentry->d_lock);
475 if (!(NCP_FINFO(inode)->flags & NCPI_DIR_CACHE)) {
476 spin_unlock(&dentry->d_lock);
477 goto invalid_cache;
478 }
479 dent = ctl.cache->dentry[ctl.idx];
480 if (unlikely(!lockref_get_not_dead(&dent->d_lockref))) {
481 spin_unlock(&dentry->d_lock);
482 goto invalid_cache;
483 }
484 spin_unlock(&dentry->d_lock);
485 if (d_really_is_negative(dent)) {
486 dput(dent);
487 goto invalid_cache;
488 }
489 over = !dir_emit(ctx, dent->d_name.name,
490 dent->d_name.len,
491 d_inode(dent)->i_ino, DT_UNKNOWN);
492 dput(dent);
493 if (over)
494 goto finished;
495 ctx->pos += 1;
496 ctl.idx += 1;
497 if (ctx->pos > ctl.head.end)
498 goto finished;
499 }
500 if (ctl.page) {
501 kunmap(ctl.page);
502 SetPageUptodate(ctl.page);
503 unlock_page(ctl.page);
504 put_page(ctl.page);
505 ctl.page = NULL;
506 }
507 ctl.idx = 0;
508 ctl.ofs += 1;
509 }
510invalid_cache:
511 if (ctl.page) {
512 kunmap(ctl.page);
513 unlock_page(ctl.page);
514 put_page(ctl.page);
515 ctl.page = NULL;
516 }
517 ctl.cache = cache;
518init_cache:
519 ncp_invalidate_dircache_entries(dentry);
520 if (!mtime_valid) {
521 mtime = ncp_obtain_mtime(dentry);
522 mtime_valid = 1;
523 }
524 ctl.head.mtime = mtime;
525 ctl.head.time = jiffies;
526 ctl.head.eof = 0;
527 ctl.fpos = 2;
528 ctl.ofs = 0;
529 ctl.idx = NCP_DIRCACHE_START;
530 ctl.filled = 0;
531 ctl.valid = 1;
532read_really:
533 spin_lock(&dentry->d_lock);
534 NCP_FINFO(inode)->flags |= NCPI_DIR_CACHE;
535 spin_unlock(&dentry->d_lock);
536 if (ncp_is_server_root(inode)) {
537 ncp_read_volume_list(file, ctx, &ctl);
538 } else {
539 ncp_do_readdir(file, ctx, &ctl);
540 }
541 ctl.head.end = ctl.fpos - 1;
542 ctl.head.eof = ctl.valid;
543finished:
544 if (ctl.page) {
545 kunmap(ctl.page);
546 SetPageUptodate(ctl.page);
547 unlock_page(ctl.page);
548 put_page(ctl.page);
549 }
550 if (page) {
551 cache->head = ctl.head;
552 kunmap(page);
553 SetPageUptodate(page);
554 unlock_page(page);
555 put_page(page);
556 }
557out:
558 return result;
559}
560
561static void ncp_d_prune(struct dentry *dentry)
562{
563 if (!dentry->d_fsdata) /* not referenced from page cache */
564 return;
565 NCP_FINFO(d_inode(dentry->d_parent))->flags &= ~NCPI_DIR_CACHE;
566}
567
568static int
569ncp_fill_cache(struct file *file, struct dir_context *ctx,
570 struct ncp_cache_control *ctrl, struct ncp_entry_info *entry,
571 int inval_childs)
572{
573 struct dentry *newdent, *dentry = file->f_path.dentry;
574 struct inode *dir = d_inode(dentry);
575 struct ncp_cache_control ctl = *ctrl;
576 struct qstr qname;
577 int valid = 0;
578 int hashed = 0;
579 ino_t ino = 0;
580 __u8 __name[NCP_MAXPATHLEN + 1];
581
582 qname.len = sizeof(__name);
583 if (ncp_vol2io(NCP_SERVER(dir), __name, &qname.len,
584 entry->i.entryName, entry->i.nameLen,
585 !ncp_preserve_entry_case(dir, entry->i.NSCreator)))
586 return 1; /* I'm not sure */
587
588 qname.name = __name;
589
590 newdent = d_hash_and_lookup(dentry, &qname);
591 if (IS_ERR(newdent))
592 goto end_advance;
593 if (!newdent) {
594 newdent = d_alloc(dentry, &qname);
595 if (!newdent)
596 goto end_advance;
597 } else {
598 hashed = 1;
599
600 /* If case sensitivity changed for this volume, all entries below this one
601 should be thrown away. This entry itself is not affected, as its case
602 sensitivity is controlled by its own parent. */
603 if (inval_childs)
604 shrink_dcache_parent(newdent);
605
606 /*
607 * NetWare's OS2 namespace is case preserving yet case
608 * insensitive. So we update dentry's name as received from
609 * server. Parent dir's i_mutex is locked because we're in
610 * readdir.
611 */
612 dentry_update_name_case(newdent, &qname);
613 }
614
615 if (d_really_is_negative(newdent)) {
616 struct inode *inode;
617
618 entry->opened = 0;
619 entry->ino = iunique(dir->i_sb, 2);
620 inode = ncp_iget(dir->i_sb, entry);
621 if (inode) {
622 d_instantiate(newdent, inode);
623 if (!hashed)
624 d_rehash(newdent);
625 } else {
626 spin_lock(&dentry->d_lock);
627 NCP_FINFO(dir)->flags &= ~NCPI_DIR_CACHE;
628 spin_unlock(&dentry->d_lock);
629 }
630 } else {
631 struct inode *inode = d_inode(newdent);
632
633 inode_lock_nested(inode, I_MUTEX_CHILD);
634 ncp_update_inode2(inode, entry);
635 inode_unlock(inode);
636 }
637
638 if (ctl.idx >= NCP_DIRCACHE_SIZE) {
639 if (ctl.page) {
640 kunmap(ctl.page);
641 SetPageUptodate(ctl.page);
642 unlock_page(ctl.page);
643 put_page(ctl.page);
644 }
645 ctl.cache = NULL;
646 ctl.idx -= NCP_DIRCACHE_SIZE;
647 ctl.ofs += 1;
648 ctl.page = grab_cache_page(&dir->i_data, ctl.ofs);
649 if (ctl.page)
650 ctl.cache = kmap(ctl.page);
651 }
652 if (ctl.cache) {
653 if (d_really_is_positive(newdent)) {
654 newdent->d_fsdata = newdent;
655 ctl.cache->dentry[ctl.idx] = newdent;
656 ino = d_inode(newdent)->i_ino;
657 ncp_new_dentry(newdent);
658 }
659 valid = 1;
660 }
661 dput(newdent);
662end_advance:
663 if (!valid)
664 ctl.valid = 0;
665 if (!ctl.filled && (ctl.fpos == ctx->pos)) {
666 if (!ino)
667 ino = iunique(dir->i_sb, 2);
668 ctl.filled = !dir_emit(ctx, qname.name, qname.len,
669 ino, DT_UNKNOWN);
670 if (!ctl.filled)
671 ctx->pos += 1;
672 }
673 ctl.fpos += 1;
674 ctl.idx += 1;
675 *ctrl = ctl;
676 return (ctl.valid || !ctl.filled);
677}
678
679static void
680ncp_read_volume_list(struct file *file, struct dir_context *ctx,
681 struct ncp_cache_control *ctl)
682{
683 struct inode *inode = file_inode(file);
684 struct ncp_server *server = NCP_SERVER(inode);
685 struct ncp_volume_info info;
686 struct ncp_entry_info entry;
687 int i;
688
689 ncp_dbg(1, "pos=%ld\n", (unsigned long)ctx->pos);
690
691 for (i = 0; i < NCP_NUMBER_OF_VOLUMES; i++) {
692 int inval_dentry;
693
694 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
695 return;
696 if (!strlen(info.volume_name))
697 continue;
698
699 ncp_dbg(1, "found vol: %s\n", info.volume_name);
700
701 if (ncp_lookup_volume(server, info.volume_name,
702 &entry.i)) {
703 ncp_dbg(1, "could not lookup vol %s\n",
704 info.volume_name);
705 continue;
706 }
707 inval_dentry = ncp_update_known_namespace(server, entry.i.volNumber, NULL);
708 entry.volume = entry.i.volNumber;
709 if (!ncp_fill_cache(file, ctx, ctl, &entry, inval_dentry))
710 return;
711 }
712}
713
714static void
715ncp_do_readdir(struct file *file, struct dir_context *ctx,
716 struct ncp_cache_control *ctl)
717{
718 struct inode *dir = file_inode(file);
719 struct ncp_server *server = NCP_SERVER(dir);
720 struct nw_search_sequence seq;
721 struct ncp_entry_info entry;
722 int err;
723 void* buf;
724 int more;
725 size_t bufsize;
726
727 ncp_dbg(1, "%pD2, fpos=%ld\n", file, (unsigned long)ctx->pos);
728 ncp_vdbg("init %pD, volnum=%d, dirent=%u\n",
729 file, NCP_FINFO(dir)->volNumber, NCP_FINFO(dir)->dirEntNum);
730
731 err = ncp_initialize_search(server, dir, &seq);
732 if (err) {
733 ncp_dbg(1, "init failed, err=%d\n", err);
734 return;
735 }
736 /* We MUST NOT use server->buffer_size handshaked with server if we are
737 using UDP, as for UDP server uses max. buffer size determined by
738 MTU, and for TCP server uses hardwired value 65KB (== 66560 bytes).
739 So we use 128KB, just to be sure, as there is no way how to know
740 this value in advance. */
741 bufsize = 131072;
742 buf = vmalloc(bufsize);
743 if (!buf)
744 return;
745 do {
746 int cnt;
747 char* rpl;
748 size_t rpls;
749
750 err = ncp_search_for_fileset(server, &seq, &more, &cnt, buf, bufsize, &rpl, &rpls);
751 if (err) /* Error */
752 break;
753 if (!cnt) /* prevent endless loop */
754 break;
755 while (cnt--) {
756 size_t onerpl;
757
758 if (rpls < offsetof(struct nw_info_struct, entryName))
759 break; /* short packet */
760 ncp_extract_file_info(rpl, &entry.i);
761 onerpl = offsetof(struct nw_info_struct, entryName) + entry.i.nameLen;
762 if (rpls < onerpl)
763 break; /* short packet */
764 (void)ncp_obtain_nfs_info(server, &entry.i);
765 rpl += onerpl;
766 rpls -= onerpl;
767 entry.volume = entry.i.volNumber;
768 if (!ncp_fill_cache(file, ctx, ctl, &entry, 0))
769 break;
770 }
771 } while (more);
772 vfree(buf);
773 return;
774}
775
776int ncp_conn_logged_in(struct super_block *sb)
777{
778 struct ncp_server* server = NCP_SBP(sb);
779 int result;
780
781 if (ncp_single_volume(server)) {
782 int len;
783 struct dentry* dent;
784 __u32 volNumber;
785 __le32 dirEntNum;
786 __le32 DosDirNum;
787 __u8 __name[NCP_MAXPATHLEN + 1];
788
789 len = sizeof(__name);
790 result = ncp_io2vol(server, __name, &len, server->m.mounted_vol,
791 strlen(server->m.mounted_vol), 1);
792 if (result)
793 goto out;
794 result = -ENOENT;
795 if (ncp_get_volume_root(server, __name, &volNumber, &dirEntNum, &DosDirNum)) {
796 ncp_vdbg("%s not found\n", server->m.mounted_vol);
797 goto out;
798 }
799 dent = sb->s_root;
800 if (dent) {
801 struct inode* ino = d_inode(dent);
802 if (ino) {
803 ncp_update_known_namespace(server, volNumber, NULL);
804 NCP_FINFO(ino)->volNumber = volNumber;
805 NCP_FINFO(ino)->dirEntNum = dirEntNum;
806 NCP_FINFO(ino)->DosDirNum = DosDirNum;
807 result = 0;
808 } else {
809 ncp_dbg(1, "d_inode(sb->s_root) == NULL!\n");
810 }
811 } else {
812 ncp_dbg(1, "sb->s_root == NULL!\n");
813 }
814 } else
815 result = 0;
816
817out:
818 return result;
819}
820
821static struct dentry *ncp_lookup(struct inode *dir, struct dentry *dentry, unsigned int flags)
822{
823 struct ncp_server *server = NCP_SERVER(dir);
824 struct inode *inode = NULL;
825 struct ncp_entry_info finfo;
826 int error, res, len;
827 __u8 __name[NCP_MAXPATHLEN + 1];
828
829 error = -EIO;
830 if (!ncp_conn_valid(server))
831 goto finished;
832
833 ncp_vdbg("server lookup for %pd2\n", dentry);
834
835 len = sizeof(__name);
836 if (ncp_is_server_root(dir)) {
837 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
838 dentry->d_name.len, 1);
839 if (!res)
840 res = ncp_lookup_volume(server, __name, &(finfo.i));
841 if (!res)
842 ncp_update_known_namespace(server, finfo.i.volNumber, NULL);
843 } else {
844 res = ncp_io2vol(server, __name, &len, dentry->d_name.name,
845 dentry->d_name.len, !ncp_preserve_case(dir));
846 if (!res)
847 res = ncp_obtain_info(server, dir, __name, &(finfo.i));
848 }
849 ncp_vdbg("looked for %pd2, res=%d\n", dentry, res);
850 /*
851 * If we didn't find an entry, make a negative dentry.
852 */
853 if (res)
854 goto add_entry;
855
856 /*
857 * Create an inode for the entry.
858 */
859 finfo.opened = 0;
860 finfo.ino = iunique(dir->i_sb, 2);
861 finfo.volume = finfo.i.volNumber;
862 error = -EACCES;
863 inode = ncp_iget(dir->i_sb, &finfo);
864
865 if (inode) {
866 ncp_new_dentry(dentry);
867add_entry:
868 d_add(dentry, inode);
869 error = 0;
870 }
871
872finished:
873 ncp_vdbg("result=%d\n", error);
874 return ERR_PTR(error);
875}
876
877/*
878 * This code is common to create, mkdir, and mknod.
879 */
880static int ncp_instantiate(struct inode *dir, struct dentry *dentry,
881 struct ncp_entry_info *finfo)
882{
883 struct inode *inode;
884 int error = -EINVAL;
885
886 finfo->ino = iunique(dir->i_sb, 2);
887 inode = ncp_iget(dir->i_sb, finfo);
888 if (!inode)
889 goto out_close;
890 d_instantiate(dentry,inode);
891 error = 0;
892out:
893 return error;
894
895out_close:
896 ncp_vdbg("%pd2 failed, closing file\n", dentry);
897 ncp_close_file(NCP_SERVER(dir), finfo->file_handle);
898 goto out;
899}
900
901int ncp_create_new(struct inode *dir, struct dentry *dentry, umode_t mode,
902 dev_t rdev, __le32 attributes)
903{
904 struct ncp_server *server = NCP_SERVER(dir);
905 struct ncp_entry_info finfo;
906 int error, result, len;
907 int opmode;
908 __u8 __name[NCP_MAXPATHLEN + 1];
909
910 ncp_vdbg("creating %pd2, mode=%hx\n", dentry, mode);
911
912 ncp_age_dentry(server, dentry);
913 len = sizeof(__name);
914 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
915 dentry->d_name.len, !ncp_preserve_case(dir));
916 if (error)
917 goto out;
918
919 error = -EACCES;
920
921 if (S_ISREG(mode) &&
922 (server->m.flags & NCP_MOUNT_EXTRAS) &&
923 (mode & S_IXUGO))
924 attributes |= aSYSTEM | aSHARED;
925
926 result = ncp_open_create_file_or_subdir(server, dir, __name,
927 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
928 attributes, AR_READ | AR_WRITE, &finfo);
929 opmode = O_RDWR;
930 if (result) {
931 result = ncp_open_create_file_or_subdir(server, dir, __name,
932 OC_MODE_CREATE | OC_MODE_OPEN | OC_MODE_REPLACE,
933 attributes, AR_WRITE, &finfo);
934 if (result) {
935 if (result == 0x87)
936 error = -ENAMETOOLONG;
937 else if (result < 0)
938 error = result;
939 ncp_dbg(1, "%pd2 failed\n", dentry);
940 goto out;
941 }
942 opmode = O_WRONLY;
943 }
944 finfo.access = opmode;
945 if (ncp_is_nfs_extras(server, finfo.volume)) {
946 finfo.i.nfs.mode = mode;
947 finfo.i.nfs.rdev = new_encode_dev(rdev);
948 if (ncp_modify_nfs_info(server, finfo.volume,
949 finfo.i.dirEntNum,
950 mode, new_encode_dev(rdev)) != 0)
951 goto out;
952 }
953
954 error = ncp_instantiate(dir, dentry, &finfo);
955out:
956 return error;
957}
958
959static int ncp_create(struct inode *dir, struct dentry *dentry, umode_t mode,
960 bool excl)
961{
962 return ncp_create_new(dir, dentry, mode, 0, 0);
963}
964
965static int ncp_mkdir(struct inode *dir, struct dentry *dentry, umode_t mode)
966{
967 struct ncp_entry_info finfo;
968 struct ncp_server *server = NCP_SERVER(dir);
969 int error, len;
970 __u8 __name[NCP_MAXPATHLEN + 1];
971
972 ncp_dbg(1, "making %pd2\n", dentry);
973
974 ncp_age_dentry(server, dentry);
975 len = sizeof(__name);
976 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
977 dentry->d_name.len, !ncp_preserve_case(dir));
978 if (error)
979 goto out;
980
981 error = ncp_open_create_file_or_subdir(server, dir, __name,
982 OC_MODE_CREATE, aDIR,
983 cpu_to_le16(0xffff),
984 &finfo);
985 if (error == 0) {
986 if (ncp_is_nfs_extras(server, finfo.volume)) {
987 mode |= S_IFDIR;
988 finfo.i.nfs.mode = mode;
989 if (ncp_modify_nfs_info(server,
990 finfo.volume,
991 finfo.i.dirEntNum,
992 mode, 0) != 0)
993 goto out;
994 }
995 error = ncp_instantiate(dir, dentry, &finfo);
996 } else if (error > 0) {
997 error = -EACCES;
998 }
999out:
1000 return error;
1001}
1002
1003static int ncp_rmdir(struct inode *dir, struct dentry *dentry)
1004{
1005 struct ncp_server *server = NCP_SERVER(dir);
1006 int error, result, len;
1007 __u8 __name[NCP_MAXPATHLEN + 1];
1008
1009 ncp_dbg(1, "removing %pd2\n", dentry);
1010
1011 len = sizeof(__name);
1012 error = ncp_io2vol(server, __name, &len, dentry->d_name.name,
1013 dentry->d_name.len, !ncp_preserve_case(dir));
1014 if (error)
1015 goto out;
1016
1017 result = ncp_del_file_or_subdir(server, dir, __name);
1018 switch (result) {
1019 case 0x00:
1020 error = 0;
1021 break;
1022 case 0x85: /* unauthorized to delete file */
1023 case 0x8A: /* unauthorized to delete file */
1024 error = -EACCES;
1025 break;
1026 case 0x8F:
1027 case 0x90: /* read only */
1028 error = -EPERM;
1029 break;
1030 case 0x9F: /* in use by another client */
1031 error = -EBUSY;
1032 break;
1033 case 0xA0: /* directory not empty */
1034 error = -ENOTEMPTY;
1035 break;
1036 case 0xFF: /* someone deleted file */
1037 error = -ENOENT;
1038 break;
1039 default:
1040 error = result < 0 ? result : -EACCES;
1041 break;
1042 }
1043out:
1044 return error;
1045}
1046
1047static int ncp_unlink(struct inode *dir, struct dentry *dentry)
1048{
1049 struct inode *inode = d_inode(dentry);
1050 struct ncp_server *server;
1051 int error;
1052
1053 server = NCP_SERVER(dir);
1054 ncp_dbg(1, "unlinking %pd2\n", dentry);
1055
1056 /*
1057 * Check whether to close the file ...
1058 */
1059 if (inode) {
1060 ncp_vdbg("closing file\n");
1061 ncp_make_closed(inode);
1062 }
1063
1064 error = ncp_del_file_or_subdir2(server, dentry);
1065#ifdef CONFIG_NCPFS_STRONG
1066 /* 9C is Invalid path.. It should be 8F, 90 - read only, but
1067 it is not :-( */
1068 if ((error == 0x9C || error == 0x90) && server->m.flags & NCP_MOUNT_STRONG) { /* R/O */
1069 error = ncp_force_unlink(dir, dentry);
1070 }
1071#endif
1072 switch (error) {
1073 case 0x00:
1074 ncp_dbg(1, "removed %pd2\n", dentry);
1075 break;
1076 case 0x85:
1077 case 0x8A:
1078 error = -EACCES;
1079 break;
1080 case 0x8D: /* some files in use */
1081 case 0x8E: /* all files in use */
1082 error = -EBUSY;
1083 break;
1084 case 0x8F: /* some read only */
1085 case 0x90: /* all read only */
1086 case 0x9C: /* !!! returned when in-use or read-only by NW4 */
1087 error = -EPERM;
1088 break;
1089 case 0xFF:
1090 error = -ENOENT;
1091 break;
1092 default:
1093 error = error < 0 ? error : -EACCES;
1094 break;
1095 }
1096 return error;
1097}
1098
1099static int ncp_rename(struct inode *old_dir, struct dentry *old_dentry,
1100 struct inode *new_dir, struct dentry *new_dentry,
1101 unsigned int flags)
1102{
1103 struct ncp_server *server = NCP_SERVER(old_dir);
1104 int error;
1105 int old_len, new_len;
1106 __u8 __old_name[NCP_MAXPATHLEN + 1], __new_name[NCP_MAXPATHLEN + 1];
1107
1108 if (flags)
1109 return -EINVAL;
1110
1111 ncp_dbg(1, "%pd2 to %pd2\n", old_dentry, new_dentry);
1112
1113 ncp_age_dentry(server, old_dentry);
1114 ncp_age_dentry(server, new_dentry);
1115
1116 old_len = sizeof(__old_name);
1117 error = ncp_io2vol(server, __old_name, &old_len,
1118 old_dentry->d_name.name, old_dentry->d_name.len,
1119 !ncp_preserve_case(old_dir));
1120 if (error)
1121 goto out;
1122
1123 new_len = sizeof(__new_name);
1124 error = ncp_io2vol(server, __new_name, &new_len,
1125 new_dentry->d_name.name, new_dentry->d_name.len,
1126 !ncp_preserve_case(new_dir));
1127 if (error)
1128 goto out;
1129
1130 error = ncp_ren_or_mov_file_or_subdir(server, old_dir, __old_name,
1131 new_dir, __new_name);
1132#ifdef CONFIG_NCPFS_STRONG
1133 if ((error == 0x90 || error == 0x8B || error == -EACCES) &&
1134 server->m.flags & NCP_MOUNT_STRONG) { /* RO */
1135 error = ncp_force_rename(old_dir, old_dentry, __old_name,
1136 new_dir, new_dentry, __new_name);
1137 }
1138#endif
1139 switch (error) {
1140 case 0x00:
1141 ncp_dbg(1, "renamed %pd -> %pd\n",
1142 old_dentry, new_dentry);
1143 ncp_d_prune(old_dentry);
1144 ncp_d_prune(new_dentry);
1145 break;
1146 case 0x9E:
1147 error = -ENAMETOOLONG;
1148 break;
1149 case 0xFF:
1150 error = -ENOENT;
1151 break;
1152 default:
1153 error = error < 0 ? error : -EACCES;
1154 break;
1155 }
1156out:
1157 return error;
1158}
1159
1160static int ncp_mknod(struct inode * dir, struct dentry *dentry,
1161 umode_t mode, dev_t rdev)
1162{
1163 if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber)) {
1164 ncp_dbg(1, "mode = 0%ho\n", mode);
1165 return ncp_create_new(dir, dentry, mode, rdev, 0);
1166 }
1167 return -EPERM; /* Strange, but true */
1168}
1169
1170/* The following routines are taken directly from msdos-fs */
1171
1172/* Linear day numbers of the respective 1sts in non-leap years. */
1173
1174static int day_n[] =
1175{0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334, 0, 0, 0, 0};
1176/* Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec */
1177
1178static int utc2local(int time)
1179{
1180 return time - sys_tz.tz_minuteswest * 60;
1181}
1182
1183static int local2utc(int time)
1184{
1185 return time + sys_tz.tz_minuteswest * 60;
1186}
1187
1188/* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1189int
1190ncp_date_dos2unix(__le16 t, __le16 d)
1191{
1192 unsigned short time = le16_to_cpu(t), date = le16_to_cpu(d);
1193 int month, year, secs;
1194
1195 /* first subtract and mask after that... Otherwise, if
1196 date == 0, bad things happen */
1197 month = ((date >> 5) - 1) & 15;
1198 year = date >> 9;
1199 secs = (time & 31) * 2 + 60 * ((time >> 5) & 63) + (time >> 11) * 3600 +
1200 86400 * ((date & 31) - 1 + day_n[month] + (year / 4) +
1201 year * 365 - ((year & 3) == 0 && month < 2 ? 1 : 0) + 3653);
1202 /* days since 1.1.70 plus 80's leap day */
1203 return local2utc(secs);
1204}
1205
1206
1207/* Convert linear UNIX date to a MS-DOS time/date pair. */
1208void
1209ncp_date_unix2dos(int unix_date, __le16 *time, __le16 *date)
1210{
1211 int day, year, nl_day, month;
1212
1213 unix_date = utc2local(unix_date);
1214 *time = cpu_to_le16(
1215 (unix_date % 60) / 2 + (((unix_date / 60) % 60) << 5) +
1216 (((unix_date / 3600) % 24) << 11));
1217 day = unix_date / 86400 - 3652;
1218 year = day / 365;
1219 if ((year + 3) / 4 + 365 * year > day)
1220 year--;
1221 day -= (year + 3) / 4 + 365 * year;
1222 if (day == 59 && !(year & 3)) {
1223 nl_day = day;
1224 month = 2;
1225 } else {
1226 nl_day = (year & 3) || day <= 59 ? day : day - 1;
1227 for (month = 1; month < 12; month++)
1228 if (day_n[month] > nl_day)
1229 break;
1230 }
1231 *date = cpu_to_le16(nl_day - day_n[month - 1] + 1 + (month << 5) + (year << 9));
1232}
diff --git a/fs/ncpfs/file.c b/fs/ncpfs/file.c
deleted file mode 100644
index 8f8cc0334ddd..000000000000
--- a/fs/ncpfs/file.c
+++ /dev/null
@@ -1,263 +0,0 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * file.c
4 *
5 * Copyright (C) 1995, 1996 by Volker Lendecke
6 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
7 *
8 */
9
10#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11
12#include <linux/uaccess.h>
13
14#include <linux/time.h>
15#include <linux/kernel.h>
16#include <linux/errno.h>
17#include <linux/fcntl.h>
18#include <linux/stat.h>
19#include <linux/mm.h>
20#include <linux/vmalloc.h>
21#include <linux/sched.h>
22
23#include "ncp_fs.h"
24
25static int ncp_fsync(struct file *file, loff_t start, loff_t end, int datasync)
26{
27 return file_write_and_wait_range(file, start, end);
28}
29
30/*
31 * Open a file with the specified read/write mode.
32 */
33int ncp_make_open(struct inode *inode, int right)
34{
35 int error;
36 int access;
37
38 error = -EINVAL;
39 if (!inode) {
40 pr_err("%s: got NULL inode\n", __func__);
41 goto out;
42 }
43
44 ncp_dbg(1, "opened=%d, volume # %u, dir entry # %u\n",
45 atomic_read(&NCP_FINFO(inode)->opened),
46 NCP_FINFO(inode)->volNumber,
47 NCP_FINFO(inode)->dirEntNum);
48 error = -EACCES;
49 mutex_lock(&NCP_FINFO(inode)->open_mutex);
50 if (!atomic_read(&NCP_FINFO(inode)->opened)) {
51 struct ncp_entry_info finfo;
52 int result;
53
54 /* tries max. rights */
55 finfo.access = O_RDWR;
56 result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
57 inode, NULL, OC_MODE_OPEN,
58 0, AR_READ | AR_WRITE, &finfo);
59 if (!result)
60 goto update;
61 /* RDWR did not succeeded, try readonly or writeonly as requested */
62 switch (right) {
63 case O_RDONLY:
64 finfo.access = O_RDONLY;
65 result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
66 inode, NULL, OC_MODE_OPEN,
67 0, AR_READ, &finfo);
68 break;
69 case O_WRONLY:
70 finfo.access = O_WRONLY;
71 result = ncp_open_create_file_or_subdir(NCP_SERVER(inode),
72 inode, NULL, OC_MODE_OPEN,
73 0, AR_WRITE, &finfo);
74 break;
75 }
76 if (result) {
77 ncp_vdbg("failed, result=%d\n", result);
78 goto out_unlock;
79 }
80 /*
81 * Update the inode information.
82 */
83 update:
84 ncp_update_inode(inode, &finfo);
85 atomic_set(&NCP_FINFO(inode)->opened, 1);
86 }
87
88 access = NCP_FINFO(inode)->access;
89 ncp_vdbg("file open, access=%x\n", access);
90 if (access == right || access == O_RDWR) {
91 atomic_inc(&NCP_FINFO(inode)->opened);
92 error = 0;
93 }
94
95out_unlock:
96 mutex_unlock(&NCP_FINFO(inode)->open_mutex);
97out:
98 return error;
99}
100
101static ssize_t
102ncp_file_read_iter(struct kiocb *iocb, struct iov_iter *to)
103{
104 struct file *file = iocb->ki_filp;
105 struct inode *inode = file_inode(file);
106 size_t already_read = 0;
107 off_t pos = iocb->ki_pos;
108 size_t bufsize;
109 int error;
110 void *freepage;
111 size_t freelen;
112
113 ncp_dbg(1, "enter %pD2\n", file);
114
115 if (!iov_iter_count(to))
116 return 0;
117 if (pos > inode->i_sb->s_maxbytes)
118 return 0;
119 iov_iter_truncate(to, inode->i_sb->s_maxbytes - pos);
120
121 error = ncp_make_open(inode, O_RDONLY);
122 if (error) {
123 ncp_dbg(1, "open failed, error=%d\n", error);
124 return error;
125 }
126
127 bufsize = NCP_SERVER(inode)->buffer_size;
128
129 error = -EIO;
130 freelen = ncp_read_bounce_size(bufsize);
131 freepage = vmalloc(freelen);
132 if (!freepage)
133 goto outrel;
134 error = 0;
135 /* First read in as much as possible for each bufsize. */
136 while (iov_iter_count(to)) {
137 int read_this_time;
138 size_t to_read = min_t(size_t,
139 bufsize - (pos % bufsize),
140 iov_iter_count(to));
141
142 error = ncp_read_bounce(NCP_SERVER(inode),
143 NCP_FINFO(inode)->file_handle,
144 pos, to_read, to, &read_this_time,
145 freepage, freelen);
146 if (error) {
147 error = -EIO; /* NW errno -> Linux errno */
148 break;
149 }
150 pos += read_this_time;
151 already_read += read_this_time;
152
153 if (read_this_time != to_read)
154 break;
155 }
156 vfree(freepage);
157
158 iocb->ki_pos = pos;
159
160 file_accessed(file);
161
162 ncp_dbg(1, "exit %pD2\n", file);
163outrel:
164 ncp_inode_close(inode);
165 return already_read ? already_read : error;
166}
167
168static ssize_t
169ncp_file_write_iter(struct kiocb *iocb, struct iov_iter *from)
170{
171 struct file *file = iocb->ki_filp;
172 struct inode *inode = file_inode(file);
173 size_t already_written = 0;
174 size_t bufsize;
175 int errno;
176 void *bouncebuffer;
177 off_t pos;
178
179 ncp_dbg(1, "enter %pD2\n", file);
180 errno = generic_write_checks(iocb, from);
181 if (errno <= 0)
182 return errno;
183
184 errno = ncp_make_open(inode, O_WRONLY);
185 if (errno) {
186 ncp_dbg(1, "open failed, error=%d\n", errno);
187 return errno;
188 }
189 bufsize = NCP_SERVER(inode)->buffer_size;
190
191 errno = file_update_time(file);
192 if (errno)
193 goto outrel;
194
195 bouncebuffer = vmalloc(bufsize);
196 if (!bouncebuffer) {
197 errno = -EIO; /* -ENOMEM */
198 goto outrel;
199 }
200 pos = iocb->ki_pos;
201 while (iov_iter_count(from)) {
202 int written_this_time;
203 size_t to_write = min_t(size_t,
204 bufsize - (pos % bufsize),
205 iov_iter_count(from));
206
207 if (!copy_from_iter_full(bouncebuffer, to_write, from)) {
208 errno = -EFAULT;
209 break;
210 }
211 if (ncp_write_kernel(NCP_SERVER(inode),
212 NCP_FINFO(inode)->file_handle,
213 pos, to_write, bouncebuffer, &written_this_time) != 0) {
214 errno = -EIO;
215 break;
216 }
217 pos += written_this_time;
218 already_written += written_this_time;
219
220 if (written_this_time != to_write)
221 break;
222 }
223 vfree(bouncebuffer);
224
225 iocb->ki_pos = pos;
226
227 if (pos > i_size_read(inode)) {
228 inode_lock(inode);
229 if (pos > i_size_read(inode))
230 i_size_write(inode, pos);
231 inode_unlock(inode);
232 }
233 ncp_dbg(1, "exit %pD2\n", file);
234outrel:
235 ncp_inode_close(inode);
236 return already_written ? already_written : errno;
237}
238
239static int ncp_release(struct inode *inode, struct file *file) {
240 if (ncp_make_closed(inode)) {
241 ncp_dbg(1, "failed to close\n");
242 }
243 return 0;
244}
245
246const struct file_operations ncp_file_operations =
247{
248 .llseek = generic_file_llseek,
249 .read_iter = ncp_file_read_iter,
250 .write_iter = ncp_file_write_iter,
251 .unlocked_ioctl = ncp_ioctl,
252#ifdef CONFIG_COMPAT
253 .compat_ioctl = ncp_compat_ioctl,
254#endif
255 .mmap = ncp_mmap,
256 .release = ncp_release,
257 .fsync = ncp_fsync,
258};
259
260const struct inode_operations ncp_file_inode_operations =
261{
262 .setattr = ncp_notify_change,
263};
diff --git a/fs/ncpfs/getopt.c b/fs/ncpfs/getopt.c
deleted file mode 100644
index 5c941bef14c4..000000000000
--- a/fs/ncpfs/getopt.c
+++ /dev/null
@@ -1,76 +0,0 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * getopt.c
4 */
5
6#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
7
8#include <linux/kernel.h>
9#include <linux/string.h>
10
11#include <asm/errno.h>
12
13#include "getopt.h"
14
15/**
16 * ncp_getopt - option parser
17 * @caller: name of the caller, for error messages
18 * @options: the options string
19 * @opts: an array of &struct option entries controlling parser operations
20 * @optopt: output; will contain the current option
21 * @optarg: output; will contain the value (if one exists)
22 * @value: output; may be NULL; will be overwritten with the integer value
23 * of the current argument.
24 *
25 * Helper to parse options on the format used by mount ("a=b,c=d,e,f").
26 * Returns opts->val if a matching entry in the 'opts' array is found,
27 * 0 when no more tokens are found, -1 if an error is encountered.
28 */
29int ncp_getopt(const char *caller, char **options, const struct ncp_option *opts,
30 char **optopt, char **optarg, unsigned long *value)
31{
32 char *token;
33 char *val;
34
35 do {
36 if ((token = strsep(options, ",")) == NULL)
37 return 0;
38 } while (*token == '\0');
39 if (optopt)
40 *optopt = token;
41
42 if ((val = strchr (token, '=')) != NULL) {
43 *val++ = 0;
44 }
45 *optarg = val;
46 for (; opts->name; opts++) {
47 if (!strcmp(opts->name, token)) {
48 if (!val) {
49 if (opts->has_arg & OPT_NOPARAM) {
50 return opts->val;
51 }
52 pr_info("%s: the %s option requires an argument\n",
53 caller, token);
54 return -EINVAL;
55 }
56 if (opts->has_arg & OPT_INT) {
57 int rc = kstrtoul(val, 0, value);
58
59 if (rc) {
60 pr_info("%s: invalid numeric value in %s=%s\n",
61 caller, token, val);
62 return rc;
63 }
64 return opts->val;
65 }
66 if (opts->has_arg & OPT_STRING) {
67 return opts->val;
68 }
69 pr_info("%s: unexpected argument %s to the %s option\n",
70 caller, val, token);
71 return -EINVAL;
72 }
73 }
74 pr_info("%s: Unrecognized mount option %s\n", caller, token);
75 return -EOPNOTSUPP;
76}
diff --git a/fs/ncpfs/getopt.h b/fs/ncpfs/getopt.h
deleted file mode 100644
index 30f0da317670..000000000000
--- a/fs/ncpfs/getopt.h
+++ /dev/null
@@ -1,17 +0,0 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _LINUX_GETOPT_H
3#define _LINUX_GETOPT_H
4
5#define OPT_NOPARAM 1
6#define OPT_INT 2
7#define OPT_STRING 4
8struct ncp_option {
9 const char *name;
10 unsigned int has_arg;
11 int val;
12};
13
14extern int ncp_getopt(const char *caller, char **options, const struct ncp_option *opts,
15 char **optopt, char **optarg, unsigned long *value);
16
17#endif /* _LINUX_GETOPT_H */
diff --git a/fs/ncpfs/inode.c b/fs/ncpfs/inode.c
deleted file mode 100644
index 129f1937fa2c..000000000000
--- a/fs/ncpfs/inode.c
+++ /dev/null
@@ -1,1066 +0,0 @@
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
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
14#include <linux/module.h>
15
16#include <linux/uaccess.h>
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>
30#include <linux/vfs.h>
31#include <linux/mount.h>
32#include <linux/seq_file.h>
33#include <linux/sched/signal.h>
34#include <linux/namei.h>
35
36#include <net/sock.h>
37
38#include "ncp_fs.h"
39#include "getopt.h"
40
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
46static void ncp_evict_inode(struct inode *);
47static void ncp_put_super(struct super_block *);
48static int ncp_statfs(struct dentry *, struct kstatfs *);
49static int ncp_show_options(struct seq_file *, struct dentry *);
50
51static struct kmem_cache * ncp_inode_cachep;
52
53static struct inode *ncp_alloc_inode(struct super_block *sb)
54{
55 struct ncp_inode_info *ei;
56 ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
57 if (!ei)
58 return NULL;
59 return &ei->vfs_inode;
60}
61
62static void ncp_i_callback(struct rcu_head *head)
63{
64 struct inode *inode = container_of(head, struct inode, i_rcu);
65 kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
66}
67
68static void ncp_destroy_inode(struct inode *inode)
69{
70 call_rcu(&inode->i_rcu, ncp_i_callback);
71}
72
73static void init_once(void *foo)
74{
75 struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
76
77 mutex_init(&ei->open_mutex);
78 inode_init_once(&ei->vfs_inode);
79}
80
81static int init_inodecache(void)
82{
83 ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
84 sizeof(struct ncp_inode_info),
85 0, (SLAB_RECLAIM_ACCOUNT|
86 SLAB_MEM_SPREAD|SLAB_ACCOUNT),
87 init_once);
88 if (ncp_inode_cachep == NULL)
89 return -ENOMEM;
90 return 0;
91}
92
93static void destroy_inodecache(void)
94{
95 /*
96 * Make sure all delayed rcu free inodes are flushed before we
97 * destroy cache.
98 */
99 rcu_barrier();
100 kmem_cache_destroy(ncp_inode_cachep);
101}
102
103static int ncp_remount(struct super_block *sb, int *flags, char* data)
104{
105 sync_filesystem(sb);
106 *flags |= MS_NODIRATIME;
107 return 0;
108}
109
110static const struct super_operations ncp_sops =
111{
112 .alloc_inode = ncp_alloc_inode,
113 .destroy_inode = ncp_destroy_inode,
114 .drop_inode = generic_delete_inode,
115 .evict_inode = ncp_evict_inode,
116 .put_super = ncp_put_super,
117 .statfs = ncp_statfs,
118 .remount_fs = ncp_remount,
119 .show_options = ncp_show_options,
120};
121
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));
139 ncp_dbg(1, "updated %s, volnum=%d, dirent=%u\n",
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. */
147 ncp_dbg(1, "(%s) nfs.mode=0%o\n", nwi->entryName, nwi->nfs.mode);
148 if (nwi->nfs.mode) {
149 /* XXX Security? */
150 inode->i_mode = nwi->nfs.mode;
151 }
152
153 inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
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 ??? */
172 i_size_write(inode, NCP_BLOCK_SIZE);
173 } else {
174 u32 size;
175
176 inode->i_mode = server->m.file_mode;
177 size = le32_to_cpu(nwi->dataStreamSize);
178 i_size_write(inode, size);
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) {
185 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
186 && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
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/*
225 * Fill in the inode based on the ncp_entry_info structure. Used only for brand new inodes.
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
235 ncp_dbg(2, "inode->i_mode = %u\n", inode->i_mode);
236
237 set_nlink(inode, 1);
238 inode->i_uid = server->m.uid;
239 inode->i_gid = server->m.gid;
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)
246static const struct inode_operations ncp_symlink_inode_operations = {
247 .get_link = page_get_link,
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) {
261 pr_err("%s: info is NULL\n", __func__);
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;
285 inode_nohighmem(inode);
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
293 pr_err("%s: iget failed!\n", __func__);
294 return inode;
295}
296
297static void
298ncp_evict_inode(struct inode *inode)
299{
300 truncate_inode_pages_final(&inode->i_data);
301 clear_inode(inode);
302
303 if (S_ISDIR(inode->i_mode)) {
304 ncp_dbg(2, "put directory %ld\n", inode->i_ino);
305 }
306
307 if (ncp_make_closed(inode) != 0) {
308 /* We can't do anything but complain. */
309 pr_err("%s: could not close\n", __func__);
310 }
311}
312
313static void ncp_stop_tasks(struct ncp_server *server) {
314 struct sock* sk = server->ncp_sock->sk;
315
316 lock_sock(sk);
317 sk->sk_error_report = server->error_report;
318 sk->sk_data_ready = server->data_ready;
319 sk->sk_write_space = server->write_space;
320 release_sock(sk);
321 del_timer_sync(&server->timeout_tm);
322
323 flush_work(&server->rcv.tq);
324 if (sk->sk_socket->type == SOCK_STREAM)
325 flush_work(&server->tx.tq);
326 else
327 flush_work(&server->timeout_tq);
328}
329
330static int ncp_show_options(struct seq_file *seq, struct dentry *root)
331{
332 struct ncp_server *server = NCP_SBP(root->d_sb);
333 unsigned int tmp;
334
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));
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
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;
384 int ret;
385
386 data->flags = 0;
387 data->int_flags = 0;
388 data->mounted_uid = GLOBAL_ROOT_UID;
389 data->wdog_pid = NULL;
390 data->ncp_fd = ~0;
391 data->time_out = NCP_DEFAULT_TIME_OUT;
392 data->retry_count = NCP_DEFAULT_RETRY_COUNT;
393 data->uid = GLOBAL_ROOT_UID;
394 data->gid = GLOBAL_ROOT_GID;
395 data->file_mode = NCP_DEFAULT_FILE_MODE;
396 data->dir_mode = NCP_DEFAULT_DIR_MODE;
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) {
401 ret = optval;
402 if (ret < 0)
403 goto err;
404 switch (optval) {
405 case 'u':
406 data->uid = make_kuid(current_user_ns(), optint);
407 if (!uid_valid(data->uid)) {
408 ret = -EINVAL;
409 goto err;
410 }
411 break;
412 case 'g':
413 data->gid = make_kgid(current_user_ns(), optint);
414 if (!gid_valid(data->gid)) {
415 ret = -EINVAL;
416 goto err;
417 }
418 break;
419 case 'o':
420 data->mounted_uid = make_kuid(current_user_ns(), optint);
421 if (!uid_valid(data->mounted_uid)) {
422 ret = -EINVAL;
423 goto err;
424 }
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':
442 data->wdog_pid = find_get_pid(optint);
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':
451 ret = -ECHRNG;
452 if (optint < NCP_MOUNT_VERSION_V4)
453 goto err;
454 if (optint > NCP_MOUNT_VERSION_V5)
455 goto err;
456 version = optint;
457 break;
458
459 }
460 }
461 return 0;
462err:
463 put_pid(data->wdog_pid);
464 data->wdog_pid = NULL;
465 return ret;
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;
472 struct inode *root_inode;
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
481 memset(&data, 0, sizeof(data));
482 server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
483 if (!server)
484 return -ENOMEM;
485 sb->s_fs_info = server;
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;
497 data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
498 data.wdog_pid = find_get_pid(md->wdog_pid);
499 data.ncp_fd = md->ncp_fd;
500 data.time_out = md->time_out;
501 data.retry_count = md->retry_count;
502 data.uid = make_kuid(current_user_ns(), md->uid);
503 data.gid = make_kgid(current_user_ns(), md->gid);
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;
516 data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
517 data.wdog_pid = find_get_pid(md->wdog_pid);
518 data.ncp_fd = md->ncp_fd;
519 data.time_out = md->time_out;
520 data.retry_count = md->retry_count;
521 data.uid = make_kuid(current_user_ns(), md->uid);
522 data.gid = make_kgid(current_user_ns(), md->gid);
523 data.file_mode = md->file_mode;
524 data.dir_mode = md->dir_mode;
525 data.info_fd = -1;
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 }
537 error = -EINVAL;
538 if (!uid_valid(data.mounted_uid) || !uid_valid(data.uid) ||
539 !gid_valid(data.gid))
540 goto out;
541 sock = sockfd_lookup(data.ncp_fd, &error);
542 if (!sock)
543 goto out;
544
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;
556 sb->s_d_op = &ncp_dentry_operations;
557
558 server = NCP_SBP(sb);
559 memset(server, 0, sizeof(*server));
560
561 error = super_setup_bdi(sb);
562 if (error)
563 goto out_fput;
564
565 server->ncp_sock = sock;
566
567 if (data.info_fd != -1) {
568 struct socket *info_sock = sockfd_lookup(data.info_fd, &error);
569 if (!info_sock)
570 goto out_fput;
571 server->info_sock = info_sock;
572 error = -EBADFD;
573 if (info_sock->type != SOCK_STREAM)
574 goto out_fput2;
575 }
576
577/* server->lock = 0; */
578 mutex_init(&server->mutex);
579 server->packet = NULL;
580/* server->buffer_size = 0; */
581/* server->conn_status = 0; */
582/* server->root_dentry = NULL; */
583/* server->root_setuped = 0; */
584 mutex_init(&server->root_setup_lock);
585#ifdef CONFIG_NCPFS_PACKET_SIGNING
586/* server->sign_wanted = 0; */
587/* server->sign_active = 0; */
588#endif
589 init_rwsem(&server->auth_rwsem);
590 server->auth.auth_type = NCP_AUTH_NONE;
591/* server->auth.object_name_len = 0; */
592/* server->auth.object_name = NULL; */
593/* server->auth.object_type = 0; */
594/* server->priv.len = 0; */
595/* server->priv.data = NULL; */
596
597 server->m = data;
598 /* Although anything producing this is buggy, it happens
599 now because of PATH_MAX changes.. */
600 if (server->m.time_out < 1) {
601 server->m.time_out = 10;
602 pr_info("You need to recompile your ncpfs utils..\n");
603 }
604 server->m.time_out = server->m.time_out * HZ / 100;
605 server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
606 server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
607
608#ifdef CONFIG_NCPFS_NLS
609 /* load the default NLS charsets */
610 server->nls_vol = load_nls_default();
611 server->nls_io = load_nls_default();
612#endif /* CONFIG_NCPFS_NLS */
613
614 atomic_set(&server->dentry_ttl, 0); /* no caching */
615
616 INIT_LIST_HEAD(&server->tx.requests);
617 mutex_init(&server->rcv.creq_mutex);
618 server->tx.creq = NULL;
619 server->rcv.creq = NULL;
620
621 timer_setup(&server->timeout_tm, ncpdgram_timeout_call, 0);
622#undef NCP_PACKET_SIZE
623#define NCP_PACKET_SIZE 131072
624 error = -ENOMEM;
625 server->packet_size = NCP_PACKET_SIZE;
626 server->packet = vmalloc(NCP_PACKET_SIZE);
627 if (server->packet == NULL)
628 goto out_nls;
629 server->txbuf = vmalloc(NCP_PACKET_SIZE);
630 if (server->txbuf == NULL)
631 goto out_packet;
632 server->rxbuf = vmalloc(NCP_PACKET_SIZE);
633 if (server->rxbuf == NULL)
634 goto out_txbuf;
635
636 lock_sock(sock->sk);
637 server->data_ready = sock->sk->sk_data_ready;
638 server->write_space = sock->sk->sk_write_space;
639 server->error_report = sock->sk->sk_error_report;
640 sock->sk->sk_user_data = server;
641 sock->sk->sk_data_ready = ncp_tcp_data_ready;
642 sock->sk->sk_error_report = ncp_tcp_error_report;
643 if (sock->type == SOCK_STREAM) {
644 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
645 server->rcv.len = 10;
646 server->rcv.state = 0;
647 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
648 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
649 sock->sk->sk_write_space = ncp_tcp_write_space;
650 } else {
651 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
652 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
653 }
654 release_sock(sock->sk);
655
656 ncp_lock_server(server);
657 error = ncp_connect(server);
658 ncp_unlock_server(server);
659 if (error < 0)
660 goto out_rxbuf;
661 ncp_dbg(1, "NCP_SBP(sb) = %p\n", NCP_SBP(sb));
662
663 error = -EMSGSIZE; /* -EREMOTESIDEINCOMPATIBLE */
664#ifdef CONFIG_NCPFS_PACKET_SIGNING
665 if (ncp_negotiate_size_and_options(server, default_bufsize,
666 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
667 {
668 if (options != NCP_DEFAULT_OPTIONS)
669 {
670 if (ncp_negotiate_size_and_options(server,
671 default_bufsize,
672 options & 2,
673 &(server->buffer_size), &options) != 0)
674
675 {
676 goto out_disconnect;
677 }
678 }
679 ncp_lock_server(server);
680 if (options & 2)
681 server->sign_wanted = 1;
682 ncp_unlock_server(server);
683 }
684 else
685#endif /* CONFIG_NCPFS_PACKET_SIGNING */
686 if (ncp_negotiate_buffersize(server, default_bufsize,
687 &(server->buffer_size)) != 0)
688 goto out_disconnect;
689 ncp_dbg(1, "bufsize = %d\n", server->buffer_size);
690
691 memset(&finfo, 0, sizeof(finfo));
692 finfo.i.attributes = aDIR;
693 finfo.i.dataStreamSize = 0; /* ignored */
694 finfo.i.dirEntNum = 0;
695 finfo.i.DosDirNum = 0;
696#ifdef CONFIG_NCPFS_SMALLDOS
697 finfo.i.NSCreator = NW_NS_DOS;
698#endif
699 finfo.volume = NCP_NUMBER_OF_VOLUMES;
700 /* set dates of mountpoint to Jan 1, 1986; 00:00 */
701 finfo.i.creationTime = finfo.i.modifyTime
702 = cpu_to_le16(0x0000);
703 finfo.i.creationDate = finfo.i.modifyDate
704 = finfo.i.lastAccessDate
705 = cpu_to_le16(0x0C21);
706 finfo.i.nameLen = 0;
707 finfo.i.entryName[0] = '\0';
708
709 finfo.opened = 0;
710 finfo.ino = 2; /* tradition */
711
712 server->name_space[finfo.volume] = NW_NS_DOS;
713
714 error = -ENOMEM;
715 root_inode = ncp_iget(sb, &finfo);
716 if (!root_inode)
717 goto out_disconnect;
718 ncp_dbg(1, "root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
719 sb->s_root = d_make_root(root_inode);
720 if (!sb->s_root)
721 goto out_disconnect;
722 return 0;
723
724out_disconnect:
725 ncp_lock_server(server);
726 ncp_disconnect(server);
727 ncp_unlock_server(server);
728out_rxbuf:
729 ncp_stop_tasks(server);
730 vfree(server->rxbuf);
731out_txbuf:
732 vfree(server->txbuf);
733out_packet:
734 vfree(server->packet);
735out_nls:
736#ifdef CONFIG_NCPFS_NLS
737 unload_nls(server->nls_io);
738 unload_nls(server->nls_vol);
739#endif
740 mutex_destroy(&server->rcv.creq_mutex);
741 mutex_destroy(&server->root_setup_lock);
742 mutex_destroy(&server->mutex);
743out_fput2:
744 if (server->info_sock)
745 sockfd_put(server->info_sock);
746out_fput:
747 sockfd_put(sock);
748out:
749 put_pid(data.wdog_pid);
750 sb->s_fs_info = NULL;
751 kfree(server);
752 return error;
753}
754
755static void delayed_free(struct rcu_head *p)
756{
757 struct ncp_server *server = container_of(p, struct ncp_server, rcu);
758#ifdef CONFIG_NCPFS_NLS
759 /* unload the NLS charsets */
760 unload_nls(server->nls_vol);
761 unload_nls(server->nls_io);
762#endif /* CONFIG_NCPFS_NLS */
763 kfree(server);
764}
765
766static void ncp_put_super(struct super_block *sb)
767{
768 struct ncp_server *server = NCP_SBP(sb);
769
770 ncp_lock_server(server);
771 ncp_disconnect(server);
772 ncp_unlock_server(server);
773
774 ncp_stop_tasks(server);
775
776 mutex_destroy(&server->rcv.creq_mutex);
777 mutex_destroy(&server->root_setup_lock);
778 mutex_destroy(&server->mutex);
779
780 if (server->info_sock)
781 sockfd_put(server->info_sock);
782 sockfd_put(server->ncp_sock);
783 kill_pid(server->m.wdog_pid, SIGTERM, 1);
784 put_pid(server->m.wdog_pid);
785
786 kfree(server->priv.data);
787 kfree(server->auth.object_name);
788 vfree(server->rxbuf);
789 vfree(server->txbuf);
790 vfree(server->packet);
791 call_rcu(&server->rcu, delayed_free);
792}
793
794static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
795{
796 struct dentry* d;
797 struct inode* i;
798 struct ncp_inode_info* ni;
799 struct ncp_server* s;
800 struct ncp_volume_info vi;
801 struct super_block *sb = dentry->d_sb;
802 int err;
803 __u8 dh;
804
805 d = sb->s_root;
806 if (!d) {
807 goto dflt;
808 }
809 i = d_inode(d);
810 if (!i) {
811 goto dflt;
812 }
813 ni = NCP_FINFO(i);
814 if (!ni) {
815 goto dflt;
816 }
817 s = NCP_SBP(sb);
818 if (!s) {
819 goto dflt;
820 }
821 if (!s->m.mounted_vol[0]) {
822 goto dflt;
823 }
824
825 err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
826 if (err) {
827 goto dflt;
828 }
829 err = ncp_get_directory_info(s, dh, &vi);
830 ncp_dirhandle_free(s, dh);
831 if (err) {
832 goto dflt;
833 }
834 buf->f_type = NCP_SUPER_MAGIC;
835 buf->f_bsize = vi.sectors_per_block * 512;
836 buf->f_blocks = vi.total_blocks;
837 buf->f_bfree = vi.free_blocks;
838 buf->f_bavail = vi.free_blocks;
839 buf->f_files = vi.total_dir_entries;
840 buf->f_ffree = vi.available_dir_entries;
841 buf->f_namelen = 12;
842 return 0;
843
844 /* We cannot say how much disk space is left on a mounted
845 NetWare Server, because free space is distributed over
846 volumes, and the current user might have disk quotas. So
847 free space is not that simple to determine. Our decision
848 here is to err conservatively. */
849
850dflt:;
851 buf->f_type = NCP_SUPER_MAGIC;
852 buf->f_bsize = NCP_BLOCK_SIZE;
853 buf->f_blocks = 0;
854 buf->f_bfree = 0;
855 buf->f_bavail = 0;
856 buf->f_namelen = 12;
857 return 0;
858}
859
860int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
861{
862 struct inode *inode = d_inode(dentry);
863 int result = 0;
864 __le32 info_mask;
865 struct nw_modify_dos_info info;
866 struct ncp_server *server;
867
868 result = -EIO;
869
870 server = NCP_SERVER(inode);
871 if (!server) /* How this could happen? */
872 goto out;
873
874 result = -EPERM;
875 if (IS_DEADDIR(d_inode(dentry)))
876 goto out;
877
878 /* ageing the dentry to force validation */
879 ncp_age_dentry(server, dentry);
880
881 result = setattr_prepare(dentry, attr);
882 if (result < 0)
883 goto out;
884
885 result = -EPERM;
886 if ((attr->ia_valid & ATTR_UID) && !uid_eq(attr->ia_uid, server->m.uid))
887 goto out;
888
889 if ((attr->ia_valid & ATTR_GID) && !gid_eq(attr->ia_gid, server->m.gid))
890 goto out;
891
892 if (((attr->ia_valid & ATTR_MODE) &&
893 (attr->ia_mode &
894 ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
895 goto out;
896
897 info_mask = 0;
898 memset(&info, 0, sizeof(info));
899
900#if 1
901 if ((attr->ia_valid & ATTR_MODE) != 0)
902 {
903 umode_t newmode = attr->ia_mode;
904
905 info_mask |= DM_ATTRIBUTES;
906
907 if (S_ISDIR(inode->i_mode)) {
908 newmode &= server->m.dir_mode;
909 } else {
910#ifdef CONFIG_NCPFS_EXTRAS
911 if (server->m.flags & NCP_MOUNT_EXTRAS) {
912 /* any non-default execute bit set */
913 if (newmode & ~server->m.file_mode & S_IXUGO)
914 info.attributes |= aSHARED | aSYSTEM;
915 /* read for group/world and not in default file_mode */
916 else if (newmode & ~server->m.file_mode & S_IRUGO)
917 info.attributes |= aSHARED;
918 } else
919#endif
920 newmode &= server->m.file_mode;
921 }
922 if (newmode & S_IWUGO)
923 info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
924 else
925 info.attributes |= (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
926
927#ifdef CONFIG_NCPFS_NFS_NS
928 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
929 result = ncp_modify_nfs_info(server,
930 NCP_FINFO(inode)->volNumber,
931 NCP_FINFO(inode)->dirEntNum,
932 attr->ia_mode, 0);
933 if (result != 0)
934 goto out;
935 info.attributes &= ~(aSHARED | aSYSTEM);
936 {
937 /* mark partial success */
938 struct iattr tmpattr;
939
940 tmpattr.ia_valid = ATTR_MODE;
941 tmpattr.ia_mode = attr->ia_mode;
942
943 setattr_copy(inode, &tmpattr);
944 mark_inode_dirty(inode);
945 }
946 }
947#endif
948 }
949#endif
950
951 /* Do SIZE before attributes, otherwise mtime together with size does not work...
952 */
953 if ((attr->ia_valid & ATTR_SIZE) != 0) {
954 int written;
955
956 ncp_dbg(1, "trying to change size to %llu\n", attr->ia_size);
957
958 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
959 result = -EACCES;
960 goto out;
961 }
962 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
963 attr->ia_size, 0, "", &written);
964
965 /* According to ndir, the changes only take effect after
966 closing the file */
967 ncp_inode_close(inode);
968 result = ncp_make_closed(inode);
969 if (result)
970 goto out;
971
972 if (attr->ia_size != i_size_read(inode)) {
973 truncate_setsize(inode, attr->ia_size);
974 mark_inode_dirty(inode);
975 }
976 }
977 if ((attr->ia_valid & ATTR_CTIME) != 0) {
978 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
979 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
980 &info.creationTime, &info.creationDate);
981 }
982 if ((attr->ia_valid & ATTR_MTIME) != 0) {
983 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
984 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
985 &info.modifyTime, &info.modifyDate);
986 }
987 if ((attr->ia_valid & ATTR_ATIME) != 0) {
988 __le16 dummy;
989 info_mask |= (DM_LAST_ACCESS_DATE);
990 ncp_date_unix2dos(attr->ia_atime.tv_sec,
991 &dummy, &info.lastAccessDate);
992 }
993 if (info_mask != 0) {
994 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
995 inode, info_mask, &info);
996 if (result != 0) {
997 if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
998 /* NetWare seems not to allow this. I
999 do not know why. So, just tell the
1000 user everything went fine. This is
1001 a terrible hack, but I do not know
1002 how to do this correctly. */
1003 result = 0;
1004 } else
1005 goto out;
1006 }
1007#ifdef CONFIG_NCPFS_STRONG
1008 if ((!result) && (info_mask & DM_ATTRIBUTES))
1009 NCP_FINFO(inode)->nwattr = info.attributes;
1010#endif
1011 }
1012 if (result)
1013 goto out;
1014
1015 setattr_copy(inode, attr);
1016 mark_inode_dirty(inode);
1017
1018out:
1019 if (result > 0)
1020 result = -EACCES;
1021 return result;
1022}
1023
1024static struct dentry *ncp_mount(struct file_system_type *fs_type,
1025 int flags, const char *dev_name, void *data)
1026{
1027 return mount_nodev(fs_type, flags, data, ncp_fill_super);
1028}
1029
1030static struct file_system_type ncp_fs_type = {
1031 .owner = THIS_MODULE,
1032 .name = "ncpfs",
1033 .mount = ncp_mount,
1034 .kill_sb = kill_anon_super,
1035 .fs_flags = FS_BINARY_MOUNTDATA,
1036};
1037MODULE_ALIAS_FS("ncpfs");
1038
1039static int __init init_ncp_fs(void)
1040{
1041 int err;
1042 ncp_dbg(1, "called\n");
1043
1044 err = init_inodecache();
1045 if (err)
1046 goto out1;
1047 err = register_filesystem(&ncp_fs_type);
1048 if (err)
1049 goto out;
1050 return 0;
1051out:
1052 destroy_inodecache();
1053out1:
1054 return err;
1055}
1056
1057static void __exit exit_ncp_fs(void)
1058{
1059 ncp_dbg(1, "called\n");
1060 unregister_filesystem(&ncp_fs_type);
1061 destroy_inodecache();
1062}
1063
1064module_init(init_ncp_fs)
1065module_exit(exit_ncp_fs)
1066MODULE_LICENSE("GPL");
diff --git a/fs/ncpfs/ioctl.c b/fs/ncpfs/ioctl.c
deleted file mode 100644
index d378b98cd7b6..000000000000
--- a/fs/ncpfs/ioctl.c
+++ /dev/null
@@ -1,923 +0,0 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ioctl.c
4 *
5 * Copyright (C) 1995, 1996 by Volker Lendecke
6 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
7 * Modified 1998, 1999 Wolfram Pienkoss for NLS
8 *
9 */
10
11#include <linux/capability.h>
12#include <linux/compat.h>
13#include <linux/errno.h>
14#include <linux/fs.h>
15#include <linux/ioctl.h>
16#include <linux/time.h>
17#include <linux/mm.h>
18#include <linux/mount.h>
19#include <linux/slab.h>
20#include <linux/highuid.h>
21#include <linux/vmalloc.h>
22#include <linux/sched.h>
23#include <linux/cred.h>
24
25#include <linux/uaccess.h>
26
27#include "ncp_fs.h"
28
29/* maximum limit for ncp_objectname_ioctl */
30#define NCP_OBJECT_NAME_MAX_LEN 4096
31/* maximum limit for ncp_privatedata_ioctl */
32#define NCP_PRIVATE_DATA_MAX_LEN 8192
33/* maximum negotiable packet size */
34#define NCP_PACKET_SIZE_INTERNAL 65536
35
36static int
37ncp_get_fs_info(struct ncp_server * server, struct inode *inode,
38 struct ncp_fs_info __user *arg)
39{
40 struct ncp_fs_info info;
41
42 if (copy_from_user(&info, arg, sizeof(info)))
43 return -EFAULT;
44
45 if (info.version != NCP_GET_FS_INFO_VERSION) {
46 ncp_dbg(1, "info.version invalid: %d\n", info.version);
47 return -EINVAL;
48 }
49 /* TODO: info.addr = server->m.serv_addr; */
50 SET_UID(info.mounted_uid, from_kuid_munged(current_user_ns(), server->m.mounted_uid));
51 info.connection = server->connection;
52 info.buffer_size = server->buffer_size;
53 info.volume_number = NCP_FINFO(inode)->volNumber;
54 info.directory_id = NCP_FINFO(inode)->DosDirNum;
55
56 if (copy_to_user(arg, &info, sizeof(info)))
57 return -EFAULT;
58 return 0;
59}
60
61static int
62ncp_get_fs_info_v2(struct ncp_server * server, struct inode *inode,
63 struct ncp_fs_info_v2 __user * arg)
64{
65 struct ncp_fs_info_v2 info2;
66
67 if (copy_from_user(&info2, arg, sizeof(info2)))
68 return -EFAULT;
69
70 if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
71 ncp_dbg(1, "info.version invalid: %d\n", info2.version);
72 return -EINVAL;
73 }
74 info2.mounted_uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid);
75 info2.connection = server->connection;
76 info2.buffer_size = server->buffer_size;
77 info2.volume_number = NCP_FINFO(inode)->volNumber;
78 info2.directory_id = NCP_FINFO(inode)->DosDirNum;
79 info2.dummy1 = info2.dummy2 = info2.dummy3 = 0;
80
81 if (copy_to_user(arg, &info2, sizeof(info2)))
82 return -EFAULT;
83 return 0;
84}
85
86#ifdef CONFIG_COMPAT
87struct compat_ncp_objectname_ioctl
88{
89 s32 auth_type;
90 u32 object_name_len;
91 compat_caddr_t object_name; /* a userspace data, in most cases user name */
92};
93
94struct compat_ncp_fs_info_v2 {
95 s32 version;
96 u32 mounted_uid;
97 u32 connection;
98 u32 buffer_size;
99
100 u32 volume_number;
101 u32 directory_id;
102
103 u32 dummy1;
104 u32 dummy2;
105 u32 dummy3;
106};
107
108struct compat_ncp_ioctl_request {
109 u32 function;
110 u32 size;
111 compat_caddr_t data;
112};
113
114struct compat_ncp_privatedata_ioctl
115{
116 u32 len;
117 compat_caddr_t data; /* ~1000 for NDS */
118};
119
120#define NCP_IOC_GET_FS_INFO_V2_32 _IOWR('n', 4, struct compat_ncp_fs_info_v2)
121#define NCP_IOC_NCPREQUEST_32 _IOR('n', 1, struct compat_ncp_ioctl_request)
122#define NCP_IOC_GETOBJECTNAME_32 _IOWR('n', 9, struct compat_ncp_objectname_ioctl)
123#define NCP_IOC_SETOBJECTNAME_32 _IOR('n', 9, struct compat_ncp_objectname_ioctl)
124#define NCP_IOC_GETPRIVATEDATA_32 _IOWR('n', 10, struct compat_ncp_privatedata_ioctl)
125#define NCP_IOC_SETPRIVATEDATA_32 _IOR('n', 10, struct compat_ncp_privatedata_ioctl)
126
127static int
128ncp_get_compat_fs_info_v2(struct ncp_server * server, struct inode *inode,
129 struct compat_ncp_fs_info_v2 __user * arg)
130{
131 struct compat_ncp_fs_info_v2 info2;
132
133 if (copy_from_user(&info2, arg, sizeof(info2)))
134 return -EFAULT;
135
136 if (info2.version != NCP_GET_FS_INFO_VERSION_V2) {
137 ncp_dbg(1, "info.version invalid: %d\n", info2.version);
138 return -EINVAL;
139 }
140 info2.mounted_uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid);
141 info2.connection = server->connection;
142 info2.buffer_size = server->buffer_size;
143 info2.volume_number = NCP_FINFO(inode)->volNumber;
144 info2.directory_id = NCP_FINFO(inode)->DosDirNum;
145 info2.dummy1 = info2.dummy2 = info2.dummy3 = 0;
146
147 if (copy_to_user(arg, &info2, sizeof(info2)))
148 return -EFAULT;
149 return 0;
150}
151#endif
152
153#define NCP_IOC_GETMOUNTUID16 _IOW('n', 2, u16)
154#define NCP_IOC_GETMOUNTUID32 _IOW('n', 2, u32)
155#define NCP_IOC_GETMOUNTUID64 _IOW('n', 2, u64)
156
157#ifdef CONFIG_NCPFS_NLS
158/* Here we are select the iocharset and the codepage for NLS.
159 * Thanks Petr Vandrovec for idea and many hints.
160 */
161static int
162ncp_set_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
163{
164 struct ncp_nls_ioctl user;
165 struct nls_table *codepage;
166 struct nls_table *iocharset;
167 struct nls_table *oldset_io;
168 struct nls_table *oldset_cp;
169 int utf8;
170 int err;
171
172 if (copy_from_user(&user, arg, sizeof(user)))
173 return -EFAULT;
174
175 codepage = NULL;
176 user.codepage[NCP_IOCSNAME_LEN] = 0;
177 if (!user.codepage[0] || !strcmp(user.codepage, "default"))
178 codepage = load_nls_default();
179 else {
180 codepage = load_nls(user.codepage);
181 if (!codepage) {
182 return -EBADRQC;
183 }
184 }
185
186 iocharset = NULL;
187 user.iocharset[NCP_IOCSNAME_LEN] = 0;
188 if (!user.iocharset[0] || !strcmp(user.iocharset, "default")) {
189 iocharset = load_nls_default();
190 utf8 = 0;
191 } else if (!strcmp(user.iocharset, "utf8")) {
192 iocharset = load_nls_default();
193 utf8 = 1;
194 } else {
195 iocharset = load_nls(user.iocharset);
196 if (!iocharset) {
197 unload_nls(codepage);
198 return -EBADRQC;
199 }
200 utf8 = 0;
201 }
202
203 mutex_lock(&server->root_setup_lock);
204 if (server->root_setuped) {
205 oldset_cp = codepage;
206 oldset_io = iocharset;
207 err = -EBUSY;
208 } else {
209 if (utf8)
210 NCP_SET_FLAG(server, NCP_FLAG_UTF8);
211 else
212 NCP_CLR_FLAG(server, NCP_FLAG_UTF8);
213 oldset_cp = server->nls_vol;
214 server->nls_vol = codepage;
215 oldset_io = server->nls_io;
216 server->nls_io = iocharset;
217 err = 0;
218 }
219 mutex_unlock(&server->root_setup_lock);
220 unload_nls(oldset_cp);
221 unload_nls(oldset_io);
222
223 return err;
224}
225
226static int
227ncp_get_charsets(struct ncp_server* server, struct ncp_nls_ioctl __user *arg)
228{
229 struct ncp_nls_ioctl user;
230 int len;
231
232 memset(&user, 0, sizeof(user));
233 mutex_lock(&server->root_setup_lock);
234 if (server->nls_vol && server->nls_vol->charset) {
235 len = strlen(server->nls_vol->charset);
236 if (len > NCP_IOCSNAME_LEN)
237 len = NCP_IOCSNAME_LEN;
238 strncpy(user.codepage, server->nls_vol->charset, len);
239 user.codepage[len] = 0;
240 }
241
242 if (NCP_IS_FLAG(server, NCP_FLAG_UTF8))
243 strcpy(user.iocharset, "utf8");
244 else if (server->nls_io && server->nls_io->charset) {
245 len = strlen(server->nls_io->charset);
246 if (len > NCP_IOCSNAME_LEN)
247 len = NCP_IOCSNAME_LEN;
248 strncpy(user.iocharset, server->nls_io->charset, len);
249 user.iocharset[len] = 0;
250 }
251 mutex_unlock(&server->root_setup_lock);
252
253 if (copy_to_user(arg, &user, sizeof(user)))
254 return -EFAULT;
255 return 0;
256}
257#endif /* CONFIG_NCPFS_NLS */
258
259static long __ncp_ioctl(struct inode *inode, unsigned int cmd, unsigned long arg)
260{
261 struct ncp_server *server = NCP_SERVER(inode);
262 int result;
263 struct ncp_ioctl_request request;
264 char* bouncebuffer;
265 void __user *argp = (void __user *)arg;
266
267 switch (cmd) {
268#ifdef CONFIG_COMPAT
269 case NCP_IOC_NCPREQUEST_32:
270#endif
271 case NCP_IOC_NCPREQUEST:
272#ifdef CONFIG_COMPAT
273 if (cmd == NCP_IOC_NCPREQUEST_32) {
274 struct compat_ncp_ioctl_request request32;
275 if (copy_from_user(&request32, argp, sizeof(request32)))
276 return -EFAULT;
277 request.function = request32.function;
278 request.size = request32.size;
279 request.data = compat_ptr(request32.data);
280 } else
281#endif
282 if (copy_from_user(&request, argp, sizeof(request)))
283 return -EFAULT;
284
285 if ((request.function > 255)
286 || (request.size >
287 NCP_PACKET_SIZE - sizeof(struct ncp_request_header))) {
288 return -EINVAL;
289 }
290 bouncebuffer = vmalloc(NCP_PACKET_SIZE_INTERNAL);
291 if (!bouncebuffer)
292 return -ENOMEM;
293 if (copy_from_user(bouncebuffer, request.data, request.size)) {
294 vfree(bouncebuffer);
295 return -EFAULT;
296 }
297 ncp_lock_server(server);
298
299 /* FIXME: We hack around in the server's structures
300 here to be able to use ncp_request */
301
302 server->has_subfunction = 0;
303 server->current_size = request.size;
304 memcpy(server->packet, bouncebuffer, request.size);
305
306 result = ncp_request2(server, request.function,
307 bouncebuffer, NCP_PACKET_SIZE_INTERNAL);
308 if (result < 0)
309 result = -EIO;
310 else
311 result = server->reply_size;
312 ncp_unlock_server(server);
313 ncp_dbg(1, "copy %d bytes\n", result);
314 if (result >= 0)
315 if (copy_to_user(request.data, bouncebuffer, result))
316 result = -EFAULT;
317 vfree(bouncebuffer);
318 return result;
319
320 case NCP_IOC_CONN_LOGGED_IN:
321
322 if (!(server->m.int_flags & NCP_IMOUNT_LOGGEDIN_POSSIBLE))
323 return -EINVAL;
324 mutex_lock(&server->root_setup_lock);
325 if (server->root_setuped)
326 result = -EBUSY;
327 else {
328 result = ncp_conn_logged_in(inode->i_sb);
329 if (result == 0)
330 server->root_setuped = 1;
331 }
332 mutex_unlock(&server->root_setup_lock);
333 return result;
334
335 case NCP_IOC_GET_FS_INFO:
336 return ncp_get_fs_info(server, inode, argp);
337
338 case NCP_IOC_GET_FS_INFO_V2:
339 return ncp_get_fs_info_v2(server, inode, argp);
340
341#ifdef CONFIG_COMPAT
342 case NCP_IOC_GET_FS_INFO_V2_32:
343 return ncp_get_compat_fs_info_v2(server, inode, argp);
344#endif
345 /* we have too many combinations of CONFIG_COMPAT,
346 * CONFIG_64BIT and CONFIG_UID16, so just handle
347 * any of the possible ioctls */
348 case NCP_IOC_GETMOUNTUID16:
349 {
350 u16 uid;
351
352 SET_UID(uid, from_kuid_munged(current_user_ns(), server->m.mounted_uid));
353 if (put_user(uid, (u16 __user *)argp))
354 return -EFAULT;
355 return 0;
356 }
357 case NCP_IOC_GETMOUNTUID32:
358 {
359 uid_t uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid);
360 if (put_user(uid, (u32 __user *)argp))
361 return -EFAULT;
362 return 0;
363 }
364 case NCP_IOC_GETMOUNTUID64:
365 {
366 uid_t uid = from_kuid_munged(current_user_ns(), server->m.mounted_uid);
367 if (put_user(uid, (u64 __user *)argp))
368 return -EFAULT;
369 return 0;
370 }
371 case NCP_IOC_GETROOT:
372 {
373 struct ncp_setroot_ioctl sr;
374
375 result = -EACCES;
376 mutex_lock(&server->root_setup_lock);
377 if (server->m.mounted_vol[0]) {
378 struct dentry* dentry = inode->i_sb->s_root;
379
380 if (dentry) {
381 struct inode* s_inode = d_inode(dentry);
382
383 if (s_inode) {
384 sr.volNumber = NCP_FINFO(s_inode)->volNumber;
385 sr.dirEntNum = NCP_FINFO(s_inode)->dirEntNum;
386 sr.namespace = server->name_space[sr.volNumber];
387 result = 0;
388 } else
389 ncp_dbg(1, "d_inode(s_root)==NULL\n");
390 } else
391 ncp_dbg(1, "s_root==NULL\n");
392 } else {
393 sr.volNumber = -1;
394 sr.namespace = 0;
395 sr.dirEntNum = 0;
396 result = 0;
397 }
398 mutex_unlock(&server->root_setup_lock);
399 if (!result && copy_to_user(argp, &sr, sizeof(sr)))
400 result = -EFAULT;
401 return result;
402 }
403
404 case NCP_IOC_SETROOT:
405 {
406 struct ncp_setroot_ioctl sr;
407 __u32 vnum;
408 __le32 de;
409 __le32 dosde;
410 struct dentry* dentry;
411
412 if (copy_from_user(&sr, argp, sizeof(sr)))
413 return -EFAULT;
414 mutex_lock(&server->root_setup_lock);
415 if (server->root_setuped)
416 result = -EBUSY;
417 else {
418 if (sr.volNumber < 0) {
419 server->m.mounted_vol[0] = 0;
420 vnum = NCP_NUMBER_OF_VOLUMES;
421 de = 0;
422 dosde = 0;
423 result = 0;
424 } else if (sr.volNumber >= NCP_NUMBER_OF_VOLUMES) {
425 result = -EINVAL;
426 } else if (ncp_mount_subdir(server, sr.volNumber,
427 sr.namespace, sr.dirEntNum,
428 &vnum, &de, &dosde)) {
429 result = -ENOENT;
430 } else
431 result = 0;
432
433 if (result == 0) {
434 dentry = inode->i_sb->s_root;
435 if (dentry) {
436 struct inode* s_inode = d_inode(dentry);
437
438 if (s_inode) {
439 NCP_FINFO(s_inode)->volNumber = vnum;
440 NCP_FINFO(s_inode)->dirEntNum = de;
441 NCP_FINFO(s_inode)->DosDirNum = dosde;
442 server->root_setuped = 1;
443 } else {
444 ncp_dbg(1, "d_inode(s_root)==NULL\n");
445 result = -EIO;
446 }
447 } else {
448 ncp_dbg(1, "s_root==NULL\n");
449 result = -EIO;
450 }
451 }
452 }
453 mutex_unlock(&server->root_setup_lock);
454
455 return result;
456 }
457
458#ifdef CONFIG_NCPFS_PACKET_SIGNING
459 case NCP_IOC_SIGN_INIT:
460 {
461 struct ncp_sign_init sign;
462
463 if (argp)
464 if (copy_from_user(&sign, argp, sizeof(sign)))
465 return -EFAULT;
466 ncp_lock_server(server);
467 mutex_lock(&server->rcv.creq_mutex);
468 if (argp) {
469 if (server->sign_wanted) {
470 memcpy(server->sign_root,sign.sign_root,8);
471 memcpy(server->sign_last,sign.sign_last,16);
472 server->sign_active = 1;
473 }
474 /* ignore when signatures not wanted */
475 } else {
476 server->sign_active = 0;
477 }
478 mutex_unlock(&server->rcv.creq_mutex);
479 ncp_unlock_server(server);
480 return 0;
481 }
482
483 case NCP_IOC_SIGN_WANTED:
484 {
485 int state;
486
487 ncp_lock_server(server);
488 state = server->sign_wanted;
489 ncp_unlock_server(server);
490 if (put_user(state, (int __user *)argp))
491 return -EFAULT;
492 return 0;
493 }
494
495 case NCP_IOC_SET_SIGN_WANTED:
496 {
497 int newstate;
498
499 /* get only low 8 bits... */
500 if (get_user(newstate, (unsigned char __user *)argp))
501 return -EFAULT;
502 result = 0;
503 ncp_lock_server(server);
504 if (server->sign_active) {
505 /* cannot turn signatures OFF when active */
506 if (!newstate)
507 result = -EINVAL;
508 } else {
509 server->sign_wanted = newstate != 0;
510 }
511 ncp_unlock_server(server);
512 return result;
513 }
514
515#endif /* CONFIG_NCPFS_PACKET_SIGNING */
516
517#ifdef CONFIG_NCPFS_IOCTL_LOCKING
518 case NCP_IOC_LOCKUNLOCK:
519 {
520 struct ncp_lock_ioctl rqdata;
521
522 if (copy_from_user(&rqdata, argp, sizeof(rqdata)))
523 return -EFAULT;
524 if (rqdata.origin != 0)
525 return -EINVAL;
526 /* check for cmd */
527 switch (rqdata.cmd) {
528 case NCP_LOCK_EX:
529 case NCP_LOCK_SH:
530 if (rqdata.timeout < 0)
531 return -EINVAL;
532 if (rqdata.timeout == 0)
533 rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT;
534 else if (rqdata.timeout > NCP_LOCK_MAX_TIMEOUT)
535 rqdata.timeout = NCP_LOCK_MAX_TIMEOUT;
536 break;
537 case NCP_LOCK_LOG:
538 rqdata.timeout = NCP_LOCK_DEFAULT_TIMEOUT; /* has no effect */
539 case NCP_LOCK_CLEAR:
540 break;
541 default:
542 return -EINVAL;
543 }
544 /* locking needs both read and write access */
545 if ((result = ncp_make_open(inode, O_RDWR)) != 0)
546 {
547 return result;
548 }
549 result = -EISDIR;
550 if (!S_ISREG(inode->i_mode))
551 goto outrel;
552 if (rqdata.cmd == NCP_LOCK_CLEAR)
553 {
554 result = ncp_ClearPhysicalRecord(NCP_SERVER(inode),
555 NCP_FINFO(inode)->file_handle,
556 rqdata.offset,
557 rqdata.length);
558 if (result > 0) result = 0; /* no such lock */
559 }
560 else
561 {
562 int lockcmd;
563
564 switch (rqdata.cmd)
565 {
566 case NCP_LOCK_EX: lockcmd=1; break;
567 case NCP_LOCK_SH: lockcmd=3; break;
568 default: lockcmd=0; break;
569 }
570 result = ncp_LogPhysicalRecord(NCP_SERVER(inode),
571 NCP_FINFO(inode)->file_handle,
572 lockcmd,
573 rqdata.offset,
574 rqdata.length,
575 rqdata.timeout);
576 if (result > 0) result = -EAGAIN;
577 }
578outrel:
579 ncp_inode_close(inode);
580 return result;
581 }
582#endif /* CONFIG_NCPFS_IOCTL_LOCKING */
583
584#ifdef CONFIG_COMPAT
585 case NCP_IOC_GETOBJECTNAME_32:
586 {
587 struct compat_ncp_objectname_ioctl user;
588 size_t outl;
589
590 if (copy_from_user(&user, argp, sizeof(user)))
591 return -EFAULT;
592 down_read(&server->auth_rwsem);
593 user.auth_type = server->auth.auth_type;
594 outl = user.object_name_len;
595 user.object_name_len = server->auth.object_name_len;
596 if (outl > user.object_name_len)
597 outl = user.object_name_len;
598 result = 0;
599 if (outl) {
600 if (copy_to_user(compat_ptr(user.object_name),
601 server->auth.object_name,
602 outl))
603 result = -EFAULT;
604 }
605 up_read(&server->auth_rwsem);
606 if (!result && copy_to_user(argp, &user, sizeof(user)))
607 result = -EFAULT;
608 return result;
609 }
610#endif
611
612 case NCP_IOC_GETOBJECTNAME:
613 {
614 struct ncp_objectname_ioctl user;
615 size_t outl;
616
617 if (copy_from_user(&user, argp, sizeof(user)))
618 return -EFAULT;
619 down_read(&server->auth_rwsem);
620 user.auth_type = server->auth.auth_type;
621 outl = user.object_name_len;
622 user.object_name_len = server->auth.object_name_len;
623 if (outl > user.object_name_len)
624 outl = user.object_name_len;
625 result = 0;
626 if (outl) {
627 if (copy_to_user(user.object_name,
628 server->auth.object_name,
629 outl))
630 result = -EFAULT;
631 }
632 up_read(&server->auth_rwsem);
633 if (!result && copy_to_user(argp, &user, sizeof(user)))
634 result = -EFAULT;
635 return result;
636 }
637
638#ifdef CONFIG_COMPAT
639 case NCP_IOC_SETOBJECTNAME_32:
640#endif
641 case NCP_IOC_SETOBJECTNAME:
642 {
643 struct ncp_objectname_ioctl user;
644 void* newname;
645 void* oldname;
646 size_t oldnamelen;
647 void* oldprivate;
648 size_t oldprivatelen;
649
650#ifdef CONFIG_COMPAT
651 if (cmd == NCP_IOC_SETOBJECTNAME_32) {
652 struct compat_ncp_objectname_ioctl user32;
653 if (copy_from_user(&user32, argp, sizeof(user32)))
654 return -EFAULT;
655 user.auth_type = user32.auth_type;
656 user.object_name_len = user32.object_name_len;
657 user.object_name = compat_ptr(user32.object_name);
658 } else
659#endif
660 if (copy_from_user(&user, argp, sizeof(user)))
661 return -EFAULT;
662
663 if (user.object_name_len > NCP_OBJECT_NAME_MAX_LEN)
664 return -ENOMEM;
665 if (user.object_name_len) {
666 newname = memdup_user(user.object_name,
667 user.object_name_len);
668 if (IS_ERR(newname))
669 return PTR_ERR(newname);
670 } else {
671 newname = NULL;
672 }
673 down_write(&server->auth_rwsem);
674 oldname = server->auth.object_name;
675 oldnamelen = server->auth.object_name_len;
676 oldprivate = server->priv.data;
677 oldprivatelen = server->priv.len;
678 server->auth.auth_type = user.auth_type;
679 server->auth.object_name_len = user.object_name_len;
680 server->auth.object_name = newname;
681 server->priv.len = 0;
682 server->priv.data = NULL;
683 up_write(&server->auth_rwsem);
684 kfree(oldprivate);
685 kfree(oldname);
686 return 0;
687 }
688
689#ifdef CONFIG_COMPAT
690 case NCP_IOC_GETPRIVATEDATA_32:
691#endif
692 case NCP_IOC_GETPRIVATEDATA:
693 {
694 struct ncp_privatedata_ioctl user;
695 size_t outl;
696
697#ifdef CONFIG_COMPAT
698 if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
699 struct compat_ncp_privatedata_ioctl user32;
700 if (copy_from_user(&user32, argp, sizeof(user32)))
701 return -EFAULT;
702 user.len = user32.len;
703 user.data = compat_ptr(user32.data);
704 } else
705#endif
706 if (copy_from_user(&user, argp, sizeof(user)))
707 return -EFAULT;
708
709 down_read(&server->auth_rwsem);
710 outl = user.len;
711 user.len = server->priv.len;
712 if (outl > user.len) outl = user.len;
713 result = 0;
714 if (outl) {
715 if (copy_to_user(user.data,
716 server->priv.data,
717 outl))
718 result = -EFAULT;
719 }
720 up_read(&server->auth_rwsem);
721 if (result)
722 return result;
723#ifdef CONFIG_COMPAT
724 if (cmd == NCP_IOC_GETPRIVATEDATA_32) {
725 struct compat_ncp_privatedata_ioctl user32;
726 user32.len = user.len;
727 user32.data = (unsigned long) user.data;
728 if (copy_to_user(argp, &user32, sizeof(user32)))
729 return -EFAULT;
730 } else
731#endif
732 if (copy_to_user(argp, &user, sizeof(user)))
733 return -EFAULT;
734
735 return 0;
736 }
737
738#ifdef CONFIG_COMPAT
739 case NCP_IOC_SETPRIVATEDATA_32:
740#endif
741 case NCP_IOC_SETPRIVATEDATA:
742 {
743 struct ncp_privatedata_ioctl user;
744 void* new;
745 void* old;
746 size_t oldlen;
747
748#ifdef CONFIG_COMPAT
749 if (cmd == NCP_IOC_SETPRIVATEDATA_32) {
750 struct compat_ncp_privatedata_ioctl user32;
751 if (copy_from_user(&user32, argp, sizeof(user32)))
752 return -EFAULT;
753 user.len = user32.len;
754 user.data = compat_ptr(user32.data);
755 } else
756#endif
757 if (copy_from_user(&user, argp, sizeof(user)))
758 return -EFAULT;
759
760 if (user.len > NCP_PRIVATE_DATA_MAX_LEN)
761 return -ENOMEM;
762 if (user.len) {
763 new = memdup_user(user.data, user.len);
764 if (IS_ERR(new))
765 return PTR_ERR(new);
766 } else {
767 new = NULL;
768 }
769 down_write(&server->auth_rwsem);
770 old = server->priv.data;
771 oldlen = server->priv.len;
772 server->priv.len = user.len;
773 server->priv.data = new;
774 up_write(&server->auth_rwsem);
775 kfree(old);
776 return 0;
777 }
778
779#ifdef CONFIG_NCPFS_NLS
780 case NCP_IOC_SETCHARSETS:
781 return ncp_set_charsets(server, argp);
782
783 case NCP_IOC_GETCHARSETS:
784 return ncp_get_charsets(server, argp);
785
786#endif /* CONFIG_NCPFS_NLS */
787
788 case NCP_IOC_SETDENTRYTTL:
789 {
790 u_int32_t user;
791
792 if (copy_from_user(&user, argp, sizeof(user)))
793 return -EFAULT;
794 /* 20 secs at most... */
795 if (user > 20000)
796 return -EINVAL;
797 user = (user * HZ) / 1000;
798 atomic_set(&server->dentry_ttl, user);
799 return 0;
800 }
801
802 case NCP_IOC_GETDENTRYTTL:
803 {
804 u_int32_t user = (atomic_read(&server->dentry_ttl) * 1000) / HZ;
805 if (copy_to_user(argp, &user, sizeof(user)))
806 return -EFAULT;
807 return 0;
808 }
809
810 }
811 return -EINVAL;
812}
813
814long ncp_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
815{
816 struct inode *inode = file_inode(filp);
817 struct ncp_server *server = NCP_SERVER(inode);
818 kuid_t uid = current_uid();
819 int need_drop_write = 0;
820 long ret;
821
822 switch (cmd) {
823 case NCP_IOC_SETCHARSETS:
824 case NCP_IOC_CONN_LOGGED_IN:
825 case NCP_IOC_SETROOT:
826 if (!capable(CAP_SYS_ADMIN)) {
827 ret = -EPERM;
828 goto out;
829 }
830 break;
831 }
832 if (!uid_eq(server->m.mounted_uid, uid)) {
833 switch (cmd) {
834 /*
835 * Only mount owner can issue these ioctls. Information
836 * necessary to authenticate to other NDS servers are
837 * stored here.
838 */
839 case NCP_IOC_GETOBJECTNAME:
840 case NCP_IOC_SETOBJECTNAME:
841 case NCP_IOC_GETPRIVATEDATA:
842 case NCP_IOC_SETPRIVATEDATA:
843#ifdef CONFIG_COMPAT
844 case NCP_IOC_GETOBJECTNAME_32:
845 case NCP_IOC_SETOBJECTNAME_32:
846 case NCP_IOC_GETPRIVATEDATA_32:
847 case NCP_IOC_SETPRIVATEDATA_32:
848#endif
849 ret = -EACCES;
850 goto out;
851 /*
852 * These require write access on the inode if user id
853 * does not match. Note that they do not write to the
854 * file... But old code did mnt_want_write, so I keep
855 * it as is. Of course not for mountpoint owner, as
856 * that breaks read-only mounts altogether as ncpmount
857 * needs working NCP_IOC_NCPREQUEST and
858 * NCP_IOC_GET_FS_INFO. Some of these codes (setdentryttl,
859 * signinit, setsignwanted) should be probably restricted
860 * to owner only, or even more to CAP_SYS_ADMIN).
861 */
862 case NCP_IOC_GET_FS_INFO:
863 case NCP_IOC_GET_FS_INFO_V2:
864 case NCP_IOC_NCPREQUEST:
865 case NCP_IOC_SETDENTRYTTL:
866 case NCP_IOC_SIGN_INIT:
867 case NCP_IOC_LOCKUNLOCK:
868 case NCP_IOC_SET_SIGN_WANTED:
869#ifdef CONFIG_COMPAT
870 case NCP_IOC_GET_FS_INFO_V2_32:
871 case NCP_IOC_NCPREQUEST_32:
872#endif
873 ret = mnt_want_write_file(filp);
874 if (ret)
875 goto out;
876 need_drop_write = 1;
877 ret = inode_permission(inode, MAY_WRITE);
878 if (ret)
879 goto outDropWrite;
880 break;
881 /*
882 * Read access required.
883 */
884 case NCP_IOC_GETMOUNTUID16:
885 case NCP_IOC_GETMOUNTUID32:
886 case NCP_IOC_GETMOUNTUID64:
887 case NCP_IOC_GETROOT:
888 case NCP_IOC_SIGN_WANTED:
889 ret = inode_permission(inode, MAY_READ);
890 if (ret)
891 goto out;
892 break;
893 /*
894 * Anybody can read these.
895 */
896 case NCP_IOC_GETCHARSETS:
897 case NCP_IOC_GETDENTRYTTL:
898 default:
899 /* Three codes below are protected by CAP_SYS_ADMIN above. */
900 case NCP_IOC_SETCHARSETS:
901 case NCP_IOC_CONN_LOGGED_IN:
902 case NCP_IOC_SETROOT:
903 break;
904 }
905 }
906 ret = __ncp_ioctl(inode, cmd, arg);
907outDropWrite:
908 if (need_drop_write)
909 mnt_drop_write_file(filp);
910out:
911 return ret;
912}
913
914#ifdef CONFIG_COMPAT
915long ncp_compat_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
916{
917 long ret;
918
919 arg = (unsigned long) compat_ptr(arg);
920 ret = ncp_ioctl(file, cmd, arg);
921 return ret;
922}
923#endif
diff --git a/fs/ncpfs/mmap.c b/fs/ncpfs/mmap.c
deleted file mode 100644
index a5c5cf2ff007..000000000000
--- a/fs/ncpfs/mmap.c
+++ /dev/null
@@ -1,125 +0,0 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * mmap.c
4 *
5 * Copyright (C) 1995, 1996 by Volker Lendecke
6 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
7 *
8 */
9
10#include <linux/stat.h>
11#include <linux/time.h>
12#include <linux/kernel.h>
13#include <linux/gfp.h>
14#include <linux/mm.h>
15#include <linux/shm.h>
16#include <linux/errno.h>
17#include <linux/mman.h>
18#include <linux/string.h>
19#include <linux/fcntl.h>
20#include <linux/memcontrol.h>
21
22#include <linux/uaccess.h>
23
24#include "ncp_fs.h"
25
26/*
27 * Fill in the supplied page for mmap
28 * XXX: how are we excluding truncate/invalidate here? Maybe need to lock
29 * page?
30 */
31static int ncp_file_mmap_fault(struct vm_fault *vmf)
32{
33 struct inode *inode = file_inode(vmf->vma->vm_file);
34 char *pg_addr;
35 unsigned int already_read;
36 unsigned int count;
37 int bufsize;
38 int pos; /* XXX: loff_t ? */
39
40 /*
41 * ncpfs has nothing against high pages as long
42 * as recvmsg and memset works on it
43 */
44 vmf->page = alloc_page(GFP_HIGHUSER);
45 if (!vmf->page)
46 return VM_FAULT_OOM;
47 pg_addr = kmap(vmf->page);
48 pos = vmf->pgoff << PAGE_SHIFT;
49
50 count = PAGE_SIZE;
51 /* what we can read in one go */
52 bufsize = NCP_SERVER(inode)->buffer_size;
53
54 already_read = 0;
55 if (ncp_make_open(inode, O_RDONLY) >= 0) {
56 while (already_read < count) {
57 int read_this_time;
58 int to_read;
59
60 to_read = bufsize - (pos % bufsize);
61
62 to_read = min_t(unsigned int, to_read, count - already_read);
63
64 if (ncp_read_kernel(NCP_SERVER(inode),
65 NCP_FINFO(inode)->file_handle,
66 pos, to_read,
67 pg_addr + already_read,
68 &read_this_time) != 0) {
69 read_this_time = 0;
70 }
71 pos += read_this_time;
72 already_read += read_this_time;
73
74 if (read_this_time < to_read) {
75 break;
76 }
77 }
78 ncp_inode_close(inode);
79
80 }
81
82 if (already_read < PAGE_SIZE)
83 memset(pg_addr + already_read, 0, PAGE_SIZE - already_read);
84 flush_dcache_page(vmf->page);
85 kunmap(vmf->page);
86
87 /*
88 * If I understand ncp_read_kernel() properly, the above always
89 * fetches from the network, here the analogue of disk.
90 * -- nyc
91 */
92 count_vm_event(PGMAJFAULT);
93 count_memcg_event_mm(vmf->vma->vm_mm, PGMAJFAULT);
94 return VM_FAULT_MAJOR;
95}
96
97static const struct vm_operations_struct ncp_file_mmap =
98{
99 .fault = ncp_file_mmap_fault,
100};
101
102
103/* This is used for a general mmap of a ncp file */
104int ncp_mmap(struct file *file, struct vm_area_struct *vma)
105{
106 struct inode *inode = file_inode(file);
107
108 ncp_dbg(1, "called\n");
109
110 if (!ncp_conn_valid(NCP_SERVER(inode)))
111 return -EIO;
112
113 /* only PAGE_COW or read-only supported now */
114 if (vma->vm_flags & VM_SHARED)
115 return -EINVAL;
116 /* we do not support files bigger than 4GB... We eventually
117 supports just 4GB... */
118 if (vma_pages(vma) + vma->vm_pgoff
119 > (1U << (32 - PAGE_SHIFT)))
120 return -EFBIG;
121
122 vma->vm_ops = &ncp_file_mmap;
123 file_accessed(file);
124 return 0;
125}
diff --git a/fs/ncpfs/ncp_fs.h b/fs/ncpfs/ncp_fs.h
deleted file mode 100644
index bdd262b6c198..000000000000
--- a/fs/ncpfs/ncp_fs.h
+++ /dev/null
@@ -1,101 +0,0 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#include <linux/ncp_fs.h>
3#include "ncp_fs_i.h"
4#include "ncp_fs_sb.h"
5
6#undef NCPFS_PARANOIA
7#ifdef NCPFS_PARANOIA
8#define ncp_vdbg(fmt, ...) \
9 pr_debug(fmt, ##__VA_ARGS__)
10#else
11#define ncp_vdbg(fmt, ...) \
12do { \
13 if (0) \
14 pr_debug(fmt, ##__VA_ARGS__); \
15} while (0)
16#endif
17
18#ifndef DEBUG_NCP
19#define DEBUG_NCP 0
20#endif
21
22#if DEBUG_NCP > 0 && !defined(DEBUG)
23#define DEBUG
24#endif
25
26#define ncp_dbg(level, fmt, ...) \
27do { \
28 if (level <= DEBUG_NCP) \
29 pr_debug(fmt, ##__VA_ARGS__); \
30} while (0)
31
32#define NCP_MAX_RPC_TIMEOUT (6*HZ)
33
34
35struct ncp_entry_info {
36 struct nw_info_struct i;
37 ino_t ino;
38 int opened;
39 int access;
40 unsigned int volume;
41 __u8 file_handle[6];
42};
43
44static inline struct ncp_server *NCP_SBP(const struct super_block *sb)
45{
46 return sb->s_fs_info;
47}
48
49#define NCP_SERVER(inode) NCP_SBP((inode)->i_sb)
50static inline struct ncp_inode_info *NCP_FINFO(const struct inode *inode)
51{
52 return container_of(inode, struct ncp_inode_info, vfs_inode);
53}
54
55/* linux/fs/ncpfs/inode.c */
56int ncp_notify_change(struct dentry *, struct iattr *);
57struct inode *ncp_iget(struct super_block *, struct ncp_entry_info *);
58void ncp_update_inode(struct inode *, struct ncp_entry_info *);
59void ncp_update_inode2(struct inode *, struct ncp_entry_info *);
60
61/* linux/fs/ncpfs/dir.c */
62extern const struct inode_operations ncp_dir_inode_operations;
63extern const struct file_operations ncp_dir_operations;
64extern const struct dentry_operations ncp_dentry_operations;
65int ncp_conn_logged_in(struct super_block *);
66int ncp_date_dos2unix(__le16 time, __le16 date);
67void ncp_date_unix2dos(int unix_date, __le16 * time, __le16 * date);
68
69/* linux/fs/ncpfs/ioctl.c */
70long ncp_ioctl(struct file *, unsigned int, unsigned long);
71long ncp_compat_ioctl(struct file *, unsigned int, unsigned long);
72
73/* linux/fs/ncpfs/sock.c */
74int ncp_request2(struct ncp_server *server, int function,
75 void* reply, int max_reply_size);
76static inline int ncp_request(struct ncp_server *server, int function) {
77 return ncp_request2(server, function, server->packet, server->packet_size);
78}
79int ncp_connect(struct ncp_server *server);
80int ncp_disconnect(struct ncp_server *server);
81void ncp_lock_server(struct ncp_server *server);
82void ncp_unlock_server(struct ncp_server *server);
83
84/* linux/fs/ncpfs/symlink.c */
85#if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
86extern const struct address_space_operations ncp_symlink_aops;
87int ncp_symlink(struct inode*, struct dentry*, const char*);
88#endif
89
90/* linux/fs/ncpfs/file.c */
91extern const struct inode_operations ncp_file_inode_operations;
92extern const struct file_operations ncp_file_operations;
93int ncp_make_open(struct inode *, int);
94
95/* linux/fs/ncpfs/mmap.c */
96int ncp_mmap(struct file *, struct vm_area_struct *);
97
98/* linux/fs/ncpfs/ncplib_kernel.c */
99int ncp_make_closed(struct inode *);
100
101#include "ncplib_kernel.h"
diff --git a/fs/ncpfs/ncp_fs_i.h b/fs/ncpfs/ncp_fs_i.h
deleted file mode 100644
index 3432bafb53a5..000000000000
--- a/fs/ncpfs/ncp_fs_i.h
+++ /dev/null
@@ -1,31 +0,0 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * ncp_fs_i.h
4 *
5 * Copyright (C) 1995 Volker Lendecke
6 *
7 */
8
9#ifndef _LINUX_NCP_FS_I
10#define _LINUX_NCP_FS_I
11
12/*
13 * This is the ncpfs part of the inode structure. This must contain
14 * all the information we need to work with an inode after creation.
15 */
16struct ncp_inode_info {
17 __le32 dirEntNum;
18 __le32 DosDirNum;
19 __u8 volNumber;
20 __le32 nwattr;
21 struct mutex open_mutex;
22 atomic_t opened;
23 int access;
24 int flags;
25#define NCPI_KLUDGE_SYMLINK 0x0001
26#define NCPI_DIR_CACHE 0x0002
27 __u8 file_handle[6];
28 struct inode vfs_inode;
29};
30
31#endif /* _LINUX_NCP_FS_I */
diff --git a/fs/ncpfs/ncp_fs_sb.h b/fs/ncpfs/ncp_fs_sb.h
deleted file mode 100644
index f06cde4adf71..000000000000
--- a/fs/ncpfs/ncp_fs_sb.h
+++ /dev/null
@@ -1,174 +0,0 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * ncp_fs_sb.h
4 *
5 * Copyright (C) 1995, 1996 by Volker Lendecke
6 *
7 */
8
9#ifndef _NCP_FS_SB
10#define _NCP_FS_SB
11
12#include <linux/types.h>
13#include <linux/ncp_mount.h>
14#include <linux/net.h>
15#include <linux/mutex.h>
16#include <linux/backing-dev.h>
17#include <linux/workqueue.h>
18
19#define NCP_DEFAULT_OPTIONS 0 /* 2 for packet signatures */
20
21struct sock;
22
23struct ncp_mount_data_kernel {
24 unsigned long flags; /* NCP_MOUNT_* flags */
25 unsigned int int_flags; /* internal flags */
26#define NCP_IMOUNT_LOGGEDIN_POSSIBLE 0x0001
27 kuid_t mounted_uid; /* Who may umount() this filesystem? */
28 struct pid *wdog_pid; /* Who cares for our watchdog packets? */
29 unsigned int ncp_fd; /* The socket to the ncp port */
30 unsigned int time_out; /* How long should I wait after
31 sending a NCP request? */
32 unsigned int retry_count; /* And how often should I retry? */
33 unsigned char mounted_vol[NCP_VOLNAME_LEN + 1];
34 kuid_t uid;
35 kgid_t gid;
36 umode_t file_mode;
37 umode_t dir_mode;
38 int info_fd;
39};
40
41struct ncp_server {
42 struct rcu_head rcu;
43 struct ncp_mount_data_kernel m; /* Nearly all of the mount data is of
44 interest for us later, so we store
45 it completely. */
46
47 __u8 name_space[NCP_NUMBER_OF_VOLUMES + 2];
48
49 struct socket *ncp_sock;/* ncp socket */
50 struct socket *info_sock;
51
52 u8 sequence;
53 u8 task;
54 u16 connection; /* Remote connection number */
55
56 u8 completion; /* Status message from server */
57 u8 conn_status; /* Bit 4 = 1 ==> Server going down, no
58 requests allowed anymore.
59 Bit 0 = 1 ==> Server is down. */
60
61 int buffer_size; /* Negotiated bufsize */
62
63 int reply_size; /* Size of last reply */
64
65 int packet_size;
66 unsigned char *packet; /* Here we prepare requests and
67 receive replies */
68 unsigned char *txbuf; /* Storage for current request */
69 unsigned char *rxbuf; /* Storage for reply to current request */
70
71 int lock; /* To prevent mismatch in protocols. */
72 struct mutex mutex;
73
74 int current_size; /* for packet preparation */
75 int has_subfunction;
76 int ncp_reply_size;
77
78 int root_setuped;
79 struct mutex root_setup_lock;
80
81 /* info for packet signing */
82 int sign_wanted; /* 1=Server needs signed packets */
83 int sign_active; /* 0=don't do signing, 1=do */
84 char sign_root[8]; /* generated from password and encr. key */
85 char sign_last[16];
86
87 /* Authentication info: NDS or BINDERY, username */
88 struct {
89 int auth_type;
90 size_t object_name_len;
91 void* object_name;
92 int object_type;
93 } auth;
94 /* Password info */
95 struct {
96 size_t len;
97 void* data;
98 } priv;
99 struct rw_semaphore auth_rwsem;
100
101 /* nls info: codepage for volume and charset for I/O */
102 struct nls_table *nls_vol;
103 struct nls_table *nls_io;
104
105 /* maximum age in jiffies */
106 atomic_t dentry_ttl;
107
108 /* miscellaneous */
109 unsigned int flags;
110
111 spinlock_t requests_lock; /* Lock accesses to tx.requests, tx.creq and rcv.creq when STREAM mode */
112
113 void (*data_ready)(struct sock* sk);
114 void (*error_report)(struct sock* sk);
115 void (*write_space)(struct sock* sk); /* STREAM mode only */
116 struct {
117 struct work_struct tq; /* STREAM/DGRAM: data/error ready */
118 struct ncp_request_reply* creq; /* STREAM/DGRAM: awaiting reply from this request */
119 struct mutex creq_mutex; /* DGRAM only: lock accesses to rcv.creq */
120
121 unsigned int state; /* STREAM only: receiver state */
122 struct {
123 __u32 magic __packed;
124 __u32 len __packed;
125 __u16 type __packed;
126 __u16 p1 __packed;
127 __u16 p2 __packed;
128 __u16 p3 __packed;
129 __u16 type2 __packed;
130 } buf; /* STREAM only: temporary buffer */
131 unsigned char* ptr; /* STREAM only: pointer to data */
132 size_t len; /* STREAM only: length of data to receive */
133 } rcv;
134 struct {
135 struct list_head requests; /* STREAM only: queued requests */
136 struct work_struct tq; /* STREAM only: transmitter ready */
137 struct ncp_request_reply* creq; /* STREAM only: currently transmitted entry */
138 } tx;
139 struct timer_list timeout_tm; /* DGRAM only: timeout timer */
140 struct work_struct timeout_tq; /* DGRAM only: associated queue, we run timers from process context */
141 int timeout_last; /* DGRAM only: current timeout length */
142 int timeout_retries; /* DGRAM only: retries left */
143 struct {
144 size_t len;
145 __u8 data[128];
146 } unexpected_packet;
147};
148
149extern void ncp_tcp_rcv_proc(struct work_struct *work);
150extern void ncp_tcp_tx_proc(struct work_struct *work);
151extern void ncpdgram_rcv_proc(struct work_struct *work);
152extern void ncpdgram_timeout_proc(struct work_struct *work);
153extern void ncpdgram_timeout_call(struct timer_list *t);
154extern void ncp_tcp_data_ready(struct sock* sk);
155extern void ncp_tcp_write_space(struct sock* sk);
156extern void ncp_tcp_error_report(struct sock* sk);
157
158#define NCP_FLAG_UTF8 1
159
160#define NCP_CLR_FLAG(server, flag) ((server)->flags &= ~(flag))
161#define NCP_SET_FLAG(server, flag) ((server)->flags |= (flag))
162#define NCP_IS_FLAG(server, flag) ((server)->flags & (flag))
163
164static inline int ncp_conn_valid(struct ncp_server *server)
165{
166 return ((server->conn_status & 0x11) == 0);
167}
168
169static inline void ncp_invalidate_conn(struct ncp_server *server)
170{
171 server->conn_status |= 0x01;
172}
173
174#endif
diff --git a/fs/ncpfs/ncplib_kernel.c b/fs/ncpfs/ncplib_kernel.c
deleted file mode 100644
index 804adfebba2f..000000000000
--- a/fs/ncpfs/ncplib_kernel.c
+++ /dev/null
@@ -1,1322 +0,0 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ncplib_kernel.c
4 *
5 * Copyright (C) 1995, 1996 by Volker Lendecke
6 * Modified for big endian by J.F. Chadima and David S. Miller
7 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
8 * Modified 1999 Wolfram Pienkoss for NLS
9 * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
10 *
11 */
12
13#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
14
15#include "ncp_fs.h"
16
17static inline void assert_server_locked(struct ncp_server *server)
18{
19 if (server->lock == 0) {
20 ncp_dbg(1, "server not locked!\n");
21 }
22}
23
24static void ncp_add_byte(struct ncp_server *server, __u8 x)
25{
26 assert_server_locked(server);
27 *(__u8 *) (&(server->packet[server->current_size])) = x;
28 server->current_size += 1;
29 return;
30}
31
32static void ncp_add_word(struct ncp_server *server, __le16 x)
33{
34 assert_server_locked(server);
35 put_unaligned(x, (__le16 *) (&(server->packet[server->current_size])));
36 server->current_size += 2;
37 return;
38}
39
40static void ncp_add_be16(struct ncp_server *server, __u16 x)
41{
42 assert_server_locked(server);
43 put_unaligned(cpu_to_be16(x), (__be16 *) (&(server->packet[server->current_size])));
44 server->current_size += 2;
45}
46
47static void ncp_add_dword(struct ncp_server *server, __le32 x)
48{
49 assert_server_locked(server);
50 put_unaligned(x, (__le32 *) (&(server->packet[server->current_size])));
51 server->current_size += 4;
52 return;
53}
54
55static void ncp_add_be32(struct ncp_server *server, __u32 x)
56{
57 assert_server_locked(server);
58 put_unaligned(cpu_to_be32(x), (__be32 *)(&(server->packet[server->current_size])));
59 server->current_size += 4;
60}
61
62static inline void ncp_add_dword_lh(struct ncp_server *server, __u32 x) {
63 ncp_add_dword(server, cpu_to_le32(x));
64}
65
66static void ncp_add_mem(struct ncp_server *server, const void *source, int size)
67{
68 assert_server_locked(server);
69 memcpy(&(server->packet[server->current_size]), source, size);
70 server->current_size += size;
71 return;
72}
73
74static void ncp_add_pstring(struct ncp_server *server, const char *s)
75{
76 int len = strlen(s);
77 assert_server_locked(server);
78 if (len > 255) {
79 ncp_dbg(1, "string too long: %s\n", s);
80 len = 255;
81 }
82 ncp_add_byte(server, len);
83 ncp_add_mem(server, s, len);
84 return;
85}
86
87static inline void ncp_init_request(struct ncp_server *server)
88{
89 ncp_lock_server(server);
90
91 server->current_size = sizeof(struct ncp_request_header);
92 server->has_subfunction = 0;
93}
94
95static inline void ncp_init_request_s(struct ncp_server *server, int subfunction)
96{
97 ncp_lock_server(server);
98
99 server->current_size = sizeof(struct ncp_request_header) + 2;
100 ncp_add_byte(server, subfunction);
101
102 server->has_subfunction = 1;
103}
104
105static inline char *
106ncp_reply_data(struct ncp_server *server, int offset)
107{
108 return &(server->packet[sizeof(struct ncp_reply_header) + offset]);
109}
110
111static inline u8 BVAL(const void *data)
112{
113 return *(const u8 *)data;
114}
115
116static u8 ncp_reply_byte(struct ncp_server *server, int offset)
117{
118 return *(const u8 *)ncp_reply_data(server, offset);
119}
120
121static inline u16 WVAL_LH(const void *data)
122{
123 return get_unaligned_le16(data);
124}
125
126static u16
127ncp_reply_le16(struct ncp_server *server, int offset)
128{
129 return get_unaligned_le16(ncp_reply_data(server, offset));
130}
131
132static u16
133ncp_reply_be16(struct ncp_server *server, int offset)
134{
135 return get_unaligned_be16(ncp_reply_data(server, offset));
136}
137
138static inline u32 DVAL_LH(const void *data)
139{
140 return get_unaligned_le32(data);
141}
142
143static __le32
144ncp_reply_dword(struct ncp_server *server, int offset)
145{
146 return get_unaligned((__le32 *)ncp_reply_data(server, offset));
147}
148
149static inline __u32 ncp_reply_dword_lh(struct ncp_server* server, int offset) {
150 return le32_to_cpu(ncp_reply_dword(server, offset));
151}
152
153int
154ncp_negotiate_buffersize(struct ncp_server *server, int size, int *target)
155{
156 int result;
157
158 ncp_init_request(server);
159 ncp_add_be16(server, size);
160
161 if ((result = ncp_request(server, 33)) != 0) {
162 ncp_unlock_server(server);
163 return result;
164 }
165 *target = min_t(unsigned int, ncp_reply_be16(server, 0), size);
166
167 ncp_unlock_server(server);
168 return 0;
169}
170
171
172/* options:
173 * bit 0 ipx checksum
174 * bit 1 packet signing
175 */
176int
177ncp_negotiate_size_and_options(struct ncp_server *server,
178 int size, int options, int *ret_size, int *ret_options) {
179 int result;
180
181 /* there is minimum */
182 if (size < NCP_BLOCK_SIZE) size = NCP_BLOCK_SIZE;
183
184 ncp_init_request(server);
185 ncp_add_be16(server, size);
186 ncp_add_byte(server, options);
187
188 if ((result = ncp_request(server, 0x61)) != 0)
189 {
190 ncp_unlock_server(server);
191 return result;
192 }
193
194 /* NCP over UDP returns 0 (!!!) */
195 result = ncp_reply_be16(server, 0);
196 if (result >= NCP_BLOCK_SIZE)
197 size = min(result, size);
198 *ret_size = size;
199 *ret_options = ncp_reply_byte(server, 4);
200
201 ncp_unlock_server(server);
202 return 0;
203}
204
205int ncp_get_volume_info_with_number(struct ncp_server* server,
206 int n, struct ncp_volume_info* target) {
207 int result;
208 int len;
209
210 ncp_init_request_s(server, 44);
211 ncp_add_byte(server, n);
212
213 if ((result = ncp_request(server, 22)) != 0) {
214 goto out;
215 }
216 target->total_blocks = ncp_reply_dword_lh(server, 0);
217 target->free_blocks = ncp_reply_dword_lh(server, 4);
218 target->purgeable_blocks = ncp_reply_dword_lh(server, 8);
219 target->not_yet_purgeable_blocks = ncp_reply_dword_lh(server, 12);
220 target->total_dir_entries = ncp_reply_dword_lh(server, 16);
221 target->available_dir_entries = ncp_reply_dword_lh(server, 20);
222 target->sectors_per_block = ncp_reply_byte(server, 28);
223
224 memset(&(target->volume_name), 0, sizeof(target->volume_name));
225
226 result = -EIO;
227 len = ncp_reply_byte(server, 29);
228 if (len > NCP_VOLNAME_LEN) {
229 ncp_dbg(1, "volume name too long: %d\n", len);
230 goto out;
231 }
232 memcpy(&(target->volume_name), ncp_reply_data(server, 30), len);
233 result = 0;
234out:
235 ncp_unlock_server(server);
236 return result;
237}
238
239int ncp_get_directory_info(struct ncp_server* server, __u8 n,
240 struct ncp_volume_info* target) {
241 int result;
242 int len;
243
244 ncp_init_request_s(server, 45);
245 ncp_add_byte(server, n);
246
247 if ((result = ncp_request(server, 22)) != 0) {
248 goto out;
249 }
250 target->total_blocks = ncp_reply_dword_lh(server, 0);
251 target->free_blocks = ncp_reply_dword_lh(server, 4);
252 target->purgeable_blocks = 0;
253 target->not_yet_purgeable_blocks = 0;
254 target->total_dir_entries = ncp_reply_dword_lh(server, 8);
255 target->available_dir_entries = ncp_reply_dword_lh(server, 12);
256 target->sectors_per_block = ncp_reply_byte(server, 20);
257
258 memset(&(target->volume_name), 0, sizeof(target->volume_name));
259
260 result = -EIO;
261 len = ncp_reply_byte(server, 21);
262 if (len > NCP_VOLNAME_LEN) {
263 ncp_dbg(1, "volume name too long: %d\n", len);
264 goto out;
265 }
266 memcpy(&(target->volume_name), ncp_reply_data(server, 22), len);
267 result = 0;
268out:
269 ncp_unlock_server(server);
270 return result;
271}
272
273int
274ncp_close_file(struct ncp_server *server, const char *file_id)
275{
276 int result;
277
278 ncp_init_request(server);
279 ncp_add_byte(server, 0);
280 ncp_add_mem(server, file_id, 6);
281
282 result = ncp_request(server, 66);
283 ncp_unlock_server(server);
284 return result;
285}
286
287int
288ncp_make_closed(struct inode *inode)
289{
290 int err;
291
292 err = 0;
293 mutex_lock(&NCP_FINFO(inode)->open_mutex);
294 if (atomic_read(&NCP_FINFO(inode)->opened) == 1) {
295 atomic_set(&NCP_FINFO(inode)->opened, 0);
296 err = ncp_close_file(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle);
297
298 if (!err)
299 ncp_vdbg("volnum=%d, dirent=%u, error=%d\n",
300 NCP_FINFO(inode)->volNumber,
301 NCP_FINFO(inode)->dirEntNum, err);
302 }
303 mutex_unlock(&NCP_FINFO(inode)->open_mutex);
304 return err;
305}
306
307static void ncp_add_handle_path(struct ncp_server *server, __u8 vol_num,
308 __le32 dir_base, int have_dir_base,
309 const char *path)
310{
311 ncp_add_byte(server, vol_num);
312 ncp_add_dword(server, dir_base);
313 if (have_dir_base != 0) {
314 ncp_add_byte(server, 1); /* dir_base */
315 } else {
316 ncp_add_byte(server, 0xff); /* no handle */
317 }
318 if (path != NULL) {
319 ncp_add_byte(server, 1); /* 1 component */
320 ncp_add_pstring(server, path);
321 } else {
322 ncp_add_byte(server, 0);
323 }
324}
325
326int ncp_dirhandle_alloc(struct ncp_server* server, __u8 volnum, __le32 dirent,
327 __u8* dirhandle) {
328 int result;
329
330 ncp_init_request(server);
331 ncp_add_byte(server, 12); /* subfunction */
332 ncp_add_byte(server, NW_NS_DOS);
333 ncp_add_byte(server, 0);
334 ncp_add_word(server, 0);
335 ncp_add_handle_path(server, volnum, dirent, 1, NULL);
336 if ((result = ncp_request(server, 87)) == 0) {
337 *dirhandle = ncp_reply_byte(server, 0);
338 }
339 ncp_unlock_server(server);
340 return result;
341}
342
343int ncp_dirhandle_free(struct ncp_server* server, __u8 dirhandle) {
344 int result;
345
346 ncp_init_request_s(server, 20);
347 ncp_add_byte(server, dirhandle);
348 result = ncp_request(server, 22);
349 ncp_unlock_server(server);
350 return result;
351}
352
353void ncp_extract_file_info(const void *structure, struct nw_info_struct *target)
354{
355 const __u8 *name_len;
356 const int info_struct_size = offsetof(struct nw_info_struct, nameLen);
357
358 memcpy(target, structure, info_struct_size);
359 name_len = structure + info_struct_size;
360 target->nameLen = *name_len;
361 memcpy(target->entryName, name_len + 1, *name_len);
362 target->entryName[*name_len] = '\0';
363 target->volNumber = le32_to_cpu(target->volNumber);
364 return;
365}
366
367#ifdef CONFIG_NCPFS_NFS_NS
368static inline void ncp_extract_nfs_info(const unsigned char *structure,
369 struct nw_nfs_info *target)
370{
371 target->mode = DVAL_LH(structure);
372 target->rdev = DVAL_LH(structure + 8);
373}
374#endif
375
376int ncp_obtain_nfs_info(struct ncp_server *server,
377 struct nw_info_struct *target)
378
379{
380 int result = 0;
381#ifdef CONFIG_NCPFS_NFS_NS
382 __u32 volnum = target->volNumber;
383
384 if (ncp_is_nfs_extras(server, volnum)) {
385 ncp_init_request(server);
386 ncp_add_byte(server, 19); /* subfunction */
387 ncp_add_byte(server, server->name_space[volnum]);
388 ncp_add_byte(server, NW_NS_NFS);
389 ncp_add_byte(server, 0);
390 ncp_add_byte(server, volnum);
391 ncp_add_dword(server, target->dirEntNum);
392 /* We must retrieve both nlinks and rdev, otherwise some server versions
393 report zeroes instead of valid data */
394 ncp_add_dword_lh(server, NSIBM_NFS_MODE | NSIBM_NFS_NLINKS | NSIBM_NFS_RDEV);
395
396 if ((result = ncp_request(server, 87)) == 0) {
397 ncp_extract_nfs_info(ncp_reply_data(server, 0), &target->nfs);
398 ncp_dbg(1, "(%s) mode=0%o, rdev=0x%x\n",
399 target->entryName, target->nfs.mode,
400 target->nfs.rdev);
401 } else {
402 target->nfs.mode = 0;
403 target->nfs.rdev = 0;
404 }
405 ncp_unlock_server(server);
406
407 } else
408#endif
409 {
410 target->nfs.mode = 0;
411 target->nfs.rdev = 0;
412 }
413 return result;
414}
415
416/*
417 * Returns information for a (one-component) name relative to
418 * the specified directory.
419 */
420int ncp_obtain_info(struct ncp_server *server, struct inode *dir, const char *path,
421 struct nw_info_struct *target)
422{
423 __u8 volnum = NCP_FINFO(dir)->volNumber;
424 __le32 dirent = NCP_FINFO(dir)->dirEntNum;
425 int result;
426
427 if (target == NULL) {
428 pr_err("%s: invalid call\n", __func__);
429 return -EINVAL;
430 }
431 ncp_init_request(server);
432 ncp_add_byte(server, 6); /* subfunction */
433 ncp_add_byte(server, server->name_space[volnum]);
434 ncp_add_byte(server, server->name_space[volnum]); /* N.B. twice ?? */
435 ncp_add_word(server, cpu_to_le16(0x8006)); /* get all */
436 ncp_add_dword(server, RIM_ALL);
437 ncp_add_handle_path(server, volnum, dirent, 1, path);
438
439 if ((result = ncp_request(server, 87)) != 0)
440 goto out;
441 ncp_extract_file_info(ncp_reply_data(server, 0), target);
442 ncp_unlock_server(server);
443
444 result = ncp_obtain_nfs_info(server, target);
445 return result;
446
447out:
448 ncp_unlock_server(server);
449 return result;
450}
451
452#ifdef CONFIG_NCPFS_NFS_NS
453static int
454ncp_obtain_DOS_dir_base(struct ncp_server *server,
455 __u8 ns, __u8 volnum, __le32 dirent,
456 const char *path, /* At most 1 component */
457 __le32 *DOS_dir_base)
458{
459 int result;
460
461 ncp_init_request(server);
462 ncp_add_byte(server, 6); /* subfunction */
463 ncp_add_byte(server, ns);
464 ncp_add_byte(server, ns);
465 ncp_add_word(server, cpu_to_le16(0x8006)); /* get all */
466 ncp_add_dword(server, RIM_DIRECTORY);
467 ncp_add_handle_path(server, volnum, dirent, 1, path);
468
469 if ((result = ncp_request(server, 87)) == 0)
470 {
471 if (DOS_dir_base) *DOS_dir_base=ncp_reply_dword(server, 0x34);
472 }
473 ncp_unlock_server(server);
474 return result;
475}
476#endif /* CONFIG_NCPFS_NFS_NS */
477
478static inline int
479ncp_get_known_namespace(struct ncp_server *server, __u8 volume)
480{
481#if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS)
482 int result;
483 __u8 *namespace;
484 __u16 no_namespaces;
485
486 ncp_init_request(server);
487 ncp_add_byte(server, 24); /* Subfunction: Get Name Spaces Loaded */
488 ncp_add_word(server, 0);
489 ncp_add_byte(server, volume);
490
491 if ((result = ncp_request(server, 87)) != 0) {
492 ncp_unlock_server(server);
493 return NW_NS_DOS; /* not result ?? */
494 }
495
496 result = NW_NS_DOS;
497 no_namespaces = ncp_reply_le16(server, 0);
498 namespace = ncp_reply_data(server, 2);
499
500 while (no_namespaces > 0) {
501 ncp_dbg(1, "found %d on %d\n", *namespace, volume);
502
503#ifdef CONFIG_NCPFS_NFS_NS
504 if ((*namespace == NW_NS_NFS) && !(server->m.flags&NCP_MOUNT_NO_NFS))
505 {
506 result = NW_NS_NFS;
507 break;
508 }
509#endif /* CONFIG_NCPFS_NFS_NS */
510#ifdef CONFIG_NCPFS_OS2_NS
511 if ((*namespace == NW_NS_OS2) && !(server->m.flags&NCP_MOUNT_NO_OS2))
512 {
513 result = NW_NS_OS2;
514 }
515#endif /* CONFIG_NCPFS_OS2_NS */
516 namespace += 1;
517 no_namespaces -= 1;
518 }
519 ncp_unlock_server(server);
520 return result;
521#else /* neither OS2 nor NFS - only DOS */
522 return NW_NS_DOS;
523#endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */
524}
525
526int
527ncp_update_known_namespace(struct ncp_server *server, __u8 volume, int *ret_ns)
528{
529 int ns = ncp_get_known_namespace(server, volume);
530
531 if (ret_ns)
532 *ret_ns = ns;
533
534 ncp_dbg(1, "namespace[%d] = %d\n", volume, server->name_space[volume]);
535
536 if (server->name_space[volume] == ns)
537 return 0;
538 server->name_space[volume] = ns;
539 return 1;
540}
541
542static int
543ncp_ObtainSpecificDirBase(struct ncp_server *server,
544 __u8 nsSrc, __u8 nsDst, __u8 vol_num, __le32 dir_base,
545 const char *path, /* At most 1 component */
546 __le32 *dirEntNum, __le32 *DosDirNum)
547{
548 int result;
549
550 ncp_init_request(server);
551 ncp_add_byte(server, 6); /* subfunction */
552 ncp_add_byte(server, nsSrc);
553 ncp_add_byte(server, nsDst);
554 ncp_add_word(server, cpu_to_le16(0x8006)); /* get all */
555 ncp_add_dword(server, RIM_ALL);
556 ncp_add_handle_path(server, vol_num, dir_base, 1, path);
557
558 if ((result = ncp_request(server, 87)) != 0)
559 {
560 ncp_unlock_server(server);
561 return result;
562 }
563
564 if (dirEntNum)
565 *dirEntNum = ncp_reply_dword(server, 0x30);
566 if (DosDirNum)
567 *DosDirNum = ncp_reply_dword(server, 0x34);
568 ncp_unlock_server(server);
569 return 0;
570}
571
572int
573ncp_mount_subdir(struct ncp_server *server,
574 __u8 volNumber, __u8 srcNS, __le32 dirEntNum,
575 __u32* volume, __le32* newDirEnt, __le32* newDosEnt)
576{
577 int dstNS;
578 int result;
579
580 ncp_update_known_namespace(server, volNumber, &dstNS);
581 if ((result = ncp_ObtainSpecificDirBase(server, srcNS, dstNS, volNumber,
582 dirEntNum, NULL, newDirEnt, newDosEnt)) != 0)
583 {
584 return result;
585 }
586 *volume = volNumber;
587 server->m.mounted_vol[1] = 0;
588 server->m.mounted_vol[0] = 'X';
589 return 0;
590}
591
592int
593ncp_get_volume_root(struct ncp_server *server,
594 const char *volname, __u32* volume, __le32* dirent, __le32* dosdirent)
595{
596 int result;
597
598 ncp_dbg(1, "looking up vol %s\n", volname);
599
600 ncp_init_request(server);
601 ncp_add_byte(server, 22); /* Subfunction: Generate dir handle */
602 ncp_add_byte(server, 0); /* DOS namespace */
603 ncp_add_byte(server, 0); /* reserved */
604 ncp_add_byte(server, 0); /* reserved */
605 ncp_add_byte(server, 0); /* reserved */
606
607 ncp_add_byte(server, 0); /* faked volume number */
608 ncp_add_dword(server, 0); /* faked dir_base */
609 ncp_add_byte(server, 0xff); /* Don't have a dir_base */
610 ncp_add_byte(server, 1); /* 1 path component */
611 ncp_add_pstring(server, volname);
612
613 if ((result = ncp_request(server, 87)) != 0) {
614 ncp_unlock_server(server);
615 return result;
616 }
617 *dirent = *dosdirent = ncp_reply_dword(server, 4);
618 *volume = ncp_reply_byte(server, 8);
619 ncp_unlock_server(server);
620 return 0;
621}
622
623int
624ncp_lookup_volume(struct ncp_server *server,
625 const char *volname, struct nw_info_struct *target)
626{
627 int result;
628
629 memset(target, 0, sizeof(*target));
630 result = ncp_get_volume_root(server, volname,
631 &target->volNumber, &target->dirEntNum, &target->DosDirNum);
632 if (result) {
633 return result;
634 }
635 ncp_update_known_namespace(server, target->volNumber, NULL);
636 target->nameLen = strlen(volname);
637 memcpy(target->entryName, volname, target->nameLen+1);
638 target->attributes = aDIR;
639 /* set dates to Jan 1, 1986 00:00 */
640 target->creationTime = target->modifyTime = cpu_to_le16(0x0000);
641 target->creationDate = target->modifyDate = target->lastAccessDate = cpu_to_le16(0x0C21);
642 target->nfs.mode = 0;
643 return 0;
644}
645
646int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *server,
647 struct inode *dir,
648 const char *path,
649 __le32 info_mask,
650 const struct nw_modify_dos_info *info)
651{
652 __u8 volnum = NCP_FINFO(dir)->volNumber;
653 __le32 dirent = NCP_FINFO(dir)->dirEntNum;
654 int result;
655
656 ncp_init_request(server);
657 ncp_add_byte(server, 7); /* subfunction */
658 ncp_add_byte(server, server->name_space[volnum]);
659 ncp_add_byte(server, 0); /* reserved */
660 ncp_add_word(server, cpu_to_le16(0x8006)); /* search attribs: all */
661
662 ncp_add_dword(server, info_mask);
663 ncp_add_mem(server, info, sizeof(*info));
664 ncp_add_handle_path(server, volnum, dirent, 1, path);
665
666 result = ncp_request(server, 87);
667 ncp_unlock_server(server);
668 return result;
669}
670
671int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
672 struct inode *dir,
673 __le32 info_mask,
674 const struct nw_modify_dos_info *info)
675{
676 return ncp_modify_file_or_subdir_dos_info_path(server, dir, NULL,
677 info_mask, info);
678}
679
680#ifdef CONFIG_NCPFS_NFS_NS
681int ncp_modify_nfs_info(struct ncp_server *server, __u8 volnum, __le32 dirent,
682 __u32 mode, __u32 rdev)
683
684{
685 int result = 0;
686
687 ncp_init_request(server);
688 if (server->name_space[volnum] == NW_NS_NFS) {
689 ncp_add_byte(server, 25); /* subfunction */
690 ncp_add_byte(server, server->name_space[volnum]);
691 ncp_add_byte(server, NW_NS_NFS);
692 ncp_add_byte(server, volnum);
693 ncp_add_dword(server, dirent);
694 /* we must always operate on both nlinks and rdev, otherwise
695 rdev is not set */
696 ncp_add_dword_lh(server, NSIBM_NFS_MODE | NSIBM_NFS_NLINKS | NSIBM_NFS_RDEV);
697 ncp_add_dword_lh(server, mode);
698 ncp_add_dword_lh(server, 1); /* nlinks */
699 ncp_add_dword_lh(server, rdev);
700 result = ncp_request(server, 87);
701 }
702 ncp_unlock_server(server);
703 return result;
704}
705#endif
706
707
708static int
709ncp_DeleteNSEntry(struct ncp_server *server,
710 __u8 have_dir_base, __u8 volnum, __le32 dirent,
711 const char* name, __u8 ns, __le16 attr)
712{
713 int result;
714
715 ncp_init_request(server);
716 ncp_add_byte(server, 8); /* subfunction */
717 ncp_add_byte(server, ns);
718 ncp_add_byte(server, 0); /* reserved */
719 ncp_add_word(server, attr); /* search attribs: all */
720 ncp_add_handle_path(server, volnum, dirent, have_dir_base, name);
721
722 result = ncp_request(server, 87);
723 ncp_unlock_server(server);
724 return result;
725}
726
727int
728ncp_del_file_or_subdir2(struct ncp_server *server,
729 struct dentry *dentry)
730{
731 struct inode *inode = d_inode(dentry);
732 __u8 volnum;
733 __le32 dirent;
734
735 if (!inode) {
736 return 0xFF; /* Any error */
737 }
738 volnum = NCP_FINFO(inode)->volNumber;
739 dirent = NCP_FINFO(inode)->DosDirNum;
740 return ncp_DeleteNSEntry(server, 1, volnum, dirent, NULL, NW_NS_DOS, cpu_to_le16(0x8006));
741}
742
743int
744ncp_del_file_or_subdir(struct ncp_server *server,
745 struct inode *dir, const char *name)
746{
747 __u8 volnum = NCP_FINFO(dir)->volNumber;
748 __le32 dirent = NCP_FINFO(dir)->dirEntNum;
749 int name_space;
750
751 name_space = server->name_space[volnum];
752#ifdef CONFIG_NCPFS_NFS_NS
753 if (name_space == NW_NS_NFS)
754 {
755 int result;
756
757 result=ncp_obtain_DOS_dir_base(server, name_space, volnum, dirent, name, &dirent);
758 if (result) return result;
759 name = NULL;
760 name_space = NW_NS_DOS;
761 }
762#endif /* CONFIG_NCPFS_NFS_NS */
763 return ncp_DeleteNSEntry(server, 1, volnum, dirent, name, name_space, cpu_to_le16(0x8006));
764}
765
766static inline void ConvertToNWfromDWORD(__u16 v0, __u16 v1, __u8 ret[6])
767{
768 __le16 *dest = (__le16 *) ret;
769 dest[1] = cpu_to_le16(v0);
770 dest[2] = cpu_to_le16(v1);
771 dest[0] = cpu_to_le16(v0 + 1);
772 return;
773}
774
775/* If both dir and name are NULL, then in target there's already a
776 looked-up entry that wants to be opened. */
777int ncp_open_create_file_or_subdir(struct ncp_server *server,
778 struct inode *dir, const char *name,
779 int open_create_mode,
780 __le32 create_attributes,
781 __le16 desired_acc_rights,
782 struct ncp_entry_info *target)
783{
784 __le16 search_attribs = cpu_to_le16(0x0006);
785 __u8 volnum;
786 __le32 dirent;
787 int result;
788
789 volnum = NCP_FINFO(dir)->volNumber;
790 dirent = NCP_FINFO(dir)->dirEntNum;
791
792 if ((create_attributes & aDIR) != 0) {
793 search_attribs |= cpu_to_le16(0x8000);
794 }
795 ncp_init_request(server);
796 ncp_add_byte(server, 1); /* subfunction */
797 ncp_add_byte(server, server->name_space[volnum]);
798 ncp_add_byte(server, open_create_mode);
799 ncp_add_word(server, search_attribs);
800 ncp_add_dword(server, RIM_ALL);
801 ncp_add_dword(server, create_attributes);
802 /* The desired acc rights seem to be the inherited rights mask
803 for directories */
804 ncp_add_word(server, desired_acc_rights);
805 ncp_add_handle_path(server, volnum, dirent, 1, name);
806
807 if ((result = ncp_request(server, 87)) != 0)
808 goto out;
809 if (!(create_attributes & aDIR))
810 target->opened = 1;
811
812 /* in target there's a new finfo to fill */
813 ncp_extract_file_info(ncp_reply_data(server, 6), &(target->i));
814 target->volume = target->i.volNumber;
815 ConvertToNWfromDWORD(ncp_reply_le16(server, 0),
816 ncp_reply_le16(server, 2),
817 target->file_handle);
818
819 ncp_unlock_server(server);
820
821 (void)ncp_obtain_nfs_info(server, &(target->i));
822 return 0;
823
824out:
825 ncp_unlock_server(server);
826 return result;
827}
828
829int
830ncp_initialize_search(struct ncp_server *server, struct inode *dir,
831 struct nw_search_sequence *target)
832{
833 __u8 volnum = NCP_FINFO(dir)->volNumber;
834 __le32 dirent = NCP_FINFO(dir)->dirEntNum;
835 int result;
836
837 ncp_init_request(server);
838 ncp_add_byte(server, 2); /* subfunction */
839 ncp_add_byte(server, server->name_space[volnum]);
840 ncp_add_byte(server, 0); /* reserved */
841 ncp_add_handle_path(server, volnum, dirent, 1, NULL);
842
843 result = ncp_request(server, 87);
844 if (result)
845 goto out;
846 memcpy(target, ncp_reply_data(server, 0), sizeof(*target));
847
848out:
849 ncp_unlock_server(server);
850 return result;
851}
852
853int ncp_search_for_fileset(struct ncp_server *server,
854 struct nw_search_sequence *seq,
855 int* more,
856 int* cnt,
857 char* buffer,
858 size_t bufsize,
859 char** rbuf,
860 size_t* rsize)
861{
862 int result;
863
864 ncp_init_request(server);
865 ncp_add_byte(server, 20);
866 ncp_add_byte(server, server->name_space[seq->volNumber]);
867 ncp_add_byte(server, 0); /* datastream */
868 ncp_add_word(server, cpu_to_le16(0x8006));
869 ncp_add_dword(server, RIM_ALL);
870 ncp_add_word(server, cpu_to_le16(32767)); /* max returned items */
871 ncp_add_mem(server, seq, 9);
872#ifdef CONFIG_NCPFS_NFS_NS
873 if (server->name_space[seq->volNumber] == NW_NS_NFS) {
874 ncp_add_byte(server, 0); /* 0 byte pattern */
875 } else
876#endif
877 {
878 ncp_add_byte(server, 2); /* 2 byte pattern */
879 ncp_add_byte(server, 0xff); /* following is a wildcard */
880 ncp_add_byte(server, '*');
881 }
882 result = ncp_request2(server, 87, buffer, bufsize);
883 if (result) {
884 ncp_unlock_server(server);
885 return result;
886 }
887 if (server->ncp_reply_size < 12) {
888 ncp_unlock_server(server);
889 return 0xFF;
890 }
891 *rsize = server->ncp_reply_size - 12;
892 ncp_unlock_server(server);
893 buffer = buffer + sizeof(struct ncp_reply_header);
894 *rbuf = buffer + 12;
895 *cnt = WVAL_LH(buffer + 10);
896 *more = BVAL(buffer + 9);
897 memcpy(seq, buffer, 9);
898 return 0;
899}
900
901static int
902ncp_RenameNSEntry(struct ncp_server *server,
903 struct inode *old_dir, const char *old_name, __le16 old_type,
904 struct inode *new_dir, const char *new_name)
905{
906 int result = -EINVAL;
907
908 if ((old_dir == NULL) || (old_name == NULL) ||
909 (new_dir == NULL) || (new_name == NULL))
910 goto out;
911
912 ncp_init_request(server);
913 ncp_add_byte(server, 4); /* subfunction */
914 ncp_add_byte(server, server->name_space[NCP_FINFO(old_dir)->volNumber]);
915 ncp_add_byte(server, 1); /* rename flag */
916 ncp_add_word(server, old_type); /* search attributes */
917
918 /* source Handle Path */
919 ncp_add_byte(server, NCP_FINFO(old_dir)->volNumber);
920 ncp_add_dword(server, NCP_FINFO(old_dir)->dirEntNum);
921 ncp_add_byte(server, 1);
922 ncp_add_byte(server, 1); /* 1 source component */
923
924 /* dest Handle Path */
925 ncp_add_byte(server, NCP_FINFO(new_dir)->volNumber);
926 ncp_add_dword(server, NCP_FINFO(new_dir)->dirEntNum);
927 ncp_add_byte(server, 1);
928 ncp_add_byte(server, 1); /* 1 destination component */
929
930 /* source path string */
931 ncp_add_pstring(server, old_name);
932 /* dest path string */
933 ncp_add_pstring(server, new_name);
934
935 result = ncp_request(server, 87);
936 ncp_unlock_server(server);
937out:
938 return result;
939}
940
941int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
942 struct inode *old_dir, const char *old_name,
943 struct inode *new_dir, const char *new_name)
944{
945 int result;
946 __le16 old_type = cpu_to_le16(0x06);
947
948/* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */
949 result = ncp_RenameNSEntry(server, old_dir, old_name, old_type,
950 new_dir, new_name);
951 if (result == 0xFF) /* File Not Found, try directory */
952 {
953 old_type = cpu_to_le16(0x16);
954 result = ncp_RenameNSEntry(server, old_dir, old_name, old_type,
955 new_dir, new_name);
956 }
957 if (result != 0x92) return result; /* All except NO_FILES_RENAMED */
958 result = ncp_del_file_or_subdir(server, new_dir, new_name);
959 if (result != 0) return -EACCES;
960 result = ncp_RenameNSEntry(server, old_dir, old_name, old_type,
961 new_dir, new_name);
962 return result;
963}
964
965
966/* We have to transfer to/from user space */
967int
968ncp_read_kernel(struct ncp_server *server, const char *file_id,
969 __u32 offset, __u16 to_read, char *target, int *bytes_read)
970{
971 const char *source;
972 int result;
973
974 ncp_init_request(server);
975 ncp_add_byte(server, 0);
976 ncp_add_mem(server, file_id, 6);
977 ncp_add_be32(server, offset);
978 ncp_add_be16(server, to_read);
979
980 if ((result = ncp_request(server, 72)) != 0) {
981 goto out;
982 }
983 *bytes_read = ncp_reply_be16(server, 0);
984 source = ncp_reply_data(server, 2 + (offset & 1));
985
986 memcpy(target, source, *bytes_read);
987out:
988 ncp_unlock_server(server);
989 return result;
990}
991
992/* There is a problem... egrep and some other silly tools do:
993 x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768);
994 read(<ncpfs fd>, x, 32768);
995 Now copying read result by copy_to_user causes pagefault. This pagefault
996 could not be handled because of server was locked due to read. So we have
997 to use temporary buffer. So ncp_unlock_server must be done before
998 copy_to_user (and for write, copy_from_user must be done before
999 ncp_init_request... same applies for send raw packet ioctl). Because of
1000 file is normally read in bigger chunks, caller provides kmalloced
1001 (vmalloced) chunk of memory with size >= to_read...
1002 */
1003int
1004ncp_read_bounce(struct ncp_server *server, const char *file_id,
1005 __u32 offset, __u16 to_read, struct iov_iter *to,
1006 int *bytes_read, void *bounce, __u32 bufsize)
1007{
1008 int result;
1009
1010 ncp_init_request(server);
1011 ncp_add_byte(server, 0);
1012 ncp_add_mem(server, file_id, 6);
1013 ncp_add_be32(server, offset);
1014 ncp_add_be16(server, to_read);
1015 result = ncp_request2(server, 72, bounce, bufsize);
1016 ncp_unlock_server(server);
1017 if (!result) {
1018 int len = get_unaligned_be16((char *)bounce +
1019 sizeof(struct ncp_reply_header));
1020 result = -EIO;
1021 if (len <= to_read) {
1022 char* source;
1023
1024 source = (char*)bounce +
1025 sizeof(struct ncp_reply_header) + 2 +
1026 (offset & 1);
1027 *bytes_read = len;
1028 result = 0;
1029 if (copy_to_iter(source, len, to) != len)
1030 result = -EFAULT;
1031 }
1032 }
1033 return result;
1034}
1035
1036int
1037ncp_write_kernel(struct ncp_server *server, const char *file_id,
1038 __u32 offset, __u16 to_write,
1039 const char *source, int *bytes_written)
1040{
1041 int result;
1042
1043 ncp_init_request(server);
1044 ncp_add_byte(server, 0);
1045 ncp_add_mem(server, file_id, 6);
1046 ncp_add_be32(server, offset);
1047 ncp_add_be16(server, to_write);
1048 ncp_add_mem(server, source, to_write);
1049
1050 if ((result = ncp_request(server, 73)) == 0)
1051 *bytes_written = to_write;
1052 ncp_unlock_server(server);
1053 return result;
1054}
1055
1056#ifdef CONFIG_NCPFS_IOCTL_LOCKING
1057int
1058ncp_LogPhysicalRecord(struct ncp_server *server, const char *file_id,
1059 __u8 locktype, __u32 offset, __u32 length, __u16 timeout)
1060{
1061 int result;
1062
1063 ncp_init_request(server);
1064 ncp_add_byte(server, locktype);
1065 ncp_add_mem(server, file_id, 6);
1066 ncp_add_be32(server, offset);
1067 ncp_add_be32(server, length);
1068 ncp_add_be16(server, timeout);
1069
1070 if ((result = ncp_request(server, 0x1A)) != 0)
1071 {
1072 ncp_unlock_server(server);
1073 return result;
1074 }
1075 ncp_unlock_server(server);
1076 return 0;
1077}
1078
1079int
1080ncp_ClearPhysicalRecord(struct ncp_server *server, const char *file_id,
1081 __u32 offset, __u32 length)
1082{
1083 int result;
1084
1085 ncp_init_request(server);
1086 ncp_add_byte(server, 0); /* who knows... lanalyzer says that */
1087 ncp_add_mem(server, file_id, 6);
1088 ncp_add_be32(server, offset);
1089 ncp_add_be32(server, length);
1090
1091 if ((result = ncp_request(server, 0x1E)) != 0)
1092 {
1093 ncp_unlock_server(server);
1094 return result;
1095 }
1096 ncp_unlock_server(server);
1097 return 0;
1098}
1099#endif /* CONFIG_NCPFS_IOCTL_LOCKING */
1100
1101#ifdef CONFIG_NCPFS_NLS
1102/* This are the NLS conversion routines with inspirations and code parts
1103 * from the vfat file system and hints from Petr Vandrovec.
1104 */
1105
1106int
1107ncp__io2vol(struct ncp_server *server, unsigned char *vname, unsigned int *vlen,
1108 const unsigned char *iname, unsigned int ilen, int cc)
1109{
1110 struct nls_table *in = server->nls_io;
1111 struct nls_table *out = server->nls_vol;
1112 unsigned char *vname_start;
1113 unsigned char *vname_end;
1114 const unsigned char *iname_end;
1115
1116 iname_end = iname + ilen;
1117 vname_start = vname;
1118 vname_end = vname + *vlen - 1;
1119
1120 while (iname < iname_end) {
1121 int chl;
1122 wchar_t ec;
1123
1124 if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) {
1125 int k;
1126 unicode_t u;
1127
1128 k = utf8_to_utf32(iname, iname_end - iname, &u);
1129 if (k < 0 || u > MAX_WCHAR_T)
1130 return -EINVAL;
1131 iname += k;
1132 ec = u;
1133 } else {
1134 if (*iname == NCP_ESC) {
1135 int k;
1136
1137 if (iname_end - iname < 5)
1138 goto nospec;
1139
1140 ec = 0;
1141 for (k = 1; k < 5; k++) {
1142 unsigned char nc;
1143
1144 nc = iname[k] - '0';
1145 if (nc >= 10) {
1146 nc -= 'A' - '0' - 10;
1147 if ((nc < 10) || (nc > 15)) {
1148 goto nospec;
1149 }
1150 }
1151 ec = (ec << 4) | nc;
1152 }
1153 iname += 5;
1154 } else {
1155nospec:;
1156 if ( (chl = in->char2uni(iname, iname_end - iname, &ec)) < 0)
1157 return chl;
1158 iname += chl;
1159 }
1160 }
1161
1162 /* unitoupper should be here! */
1163
1164 chl = out->uni2char(ec, vname, vname_end - vname);
1165 if (chl < 0)
1166 return chl;
1167
1168 /* this is wrong... */
1169 if (cc) {
1170 int chi;
1171
1172 for (chi = 0; chi < chl; chi++){
1173 vname[chi] = ncp_toupper(out, vname[chi]);
1174 }
1175 }
1176 vname += chl;
1177 }
1178
1179 *vname = 0;
1180 *vlen = vname - vname_start;
1181 return 0;
1182}
1183
1184int
1185ncp__vol2io(struct ncp_server *server, unsigned char *iname, unsigned int *ilen,
1186 const unsigned char *vname, unsigned int vlen, int cc)
1187{
1188 struct nls_table *in = server->nls_vol;
1189 struct nls_table *out = server->nls_io;
1190 const unsigned char *vname_end;
1191 unsigned char *iname_start;
1192 unsigned char *iname_end;
1193 unsigned char *vname_cc;
1194 int err;
1195
1196 vname_cc = NULL;
1197
1198 if (cc) {
1199 int i;
1200
1201 /* this is wrong! */
1202 vname_cc = kmalloc(vlen, GFP_KERNEL);
1203 if (!vname_cc)
1204 return -ENOMEM;
1205 for (i = 0; i < vlen; i++)
1206 vname_cc[i] = ncp_tolower(in, vname[i]);
1207 vname = vname_cc;
1208 }
1209
1210 iname_start = iname;
1211 iname_end = iname + *ilen - 1;
1212 vname_end = vname + vlen;
1213
1214 while (vname < vname_end) {
1215 wchar_t ec;
1216 int chl;
1217
1218 if ( (chl = in->char2uni(vname, vname_end - vname, &ec)) < 0) {
1219 err = chl;
1220 goto quit;
1221 }
1222 vname += chl;
1223
1224 /* unitolower should be here! */
1225
1226 if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) {
1227 int k;
1228
1229 k = utf32_to_utf8(ec, iname, iname_end - iname);
1230 if (k < 0) {
1231 err = -ENAMETOOLONG;
1232 goto quit;
1233 }
1234 iname += k;
1235 } else {
1236 if ( (chl = out->uni2char(ec, iname, iname_end - iname)) >= 0) {
1237 iname += chl;
1238 } else {
1239 int k;
1240
1241 if (iname_end - iname < 5) {
1242 err = -ENAMETOOLONG;
1243 goto quit;
1244 }
1245 *iname = NCP_ESC;
1246 for (k = 4; k > 0; k--) {
1247 unsigned char v;
1248
1249 v = (ec & 0xF) + '0';
1250 if (v > '9') {
1251 v += 'A' - '9' - 1;
1252 }
1253 iname[k] = v;
1254 ec >>= 4;
1255 }
1256 iname += 5;
1257 }
1258 }
1259 }
1260
1261 *iname = 0;
1262 *ilen = iname - iname_start;
1263 err = 0;
1264quit:;
1265 if (cc)
1266 kfree(vname_cc);
1267 return err;
1268}
1269
1270#else
1271
1272int
1273ncp__io2vol(unsigned char *vname, unsigned int *vlen,
1274 const unsigned char *iname, unsigned int ilen, int cc)
1275{
1276 int i;
1277
1278 if (*vlen <= ilen)
1279 return -ENAMETOOLONG;
1280
1281 if (cc)
1282 for (i = 0; i < ilen; i++) {
1283 *vname = toupper(*iname);
1284 vname++;
1285 iname++;
1286 }
1287 else {
1288 memmove(vname, iname, ilen);
1289 vname += ilen;
1290 }
1291
1292 *vlen = ilen;
1293 *vname = 0;
1294 return 0;
1295}
1296
1297int
1298ncp__vol2io(unsigned char *iname, unsigned int *ilen,
1299 const unsigned char *vname, unsigned int vlen, int cc)
1300{
1301 int i;
1302
1303 if (*ilen <= vlen)
1304 return -ENAMETOOLONG;
1305
1306 if (cc)
1307 for (i = 0; i < vlen; i++) {
1308 *iname = tolower(*vname);
1309 iname++;
1310 vname++;
1311 }
1312 else {
1313 memmove(iname, vname, vlen);
1314 iname += vlen;
1315 }
1316
1317 *ilen = vlen;
1318 *iname = 0;
1319 return 0;
1320}
1321
1322#endif
diff --git a/fs/ncpfs/ncplib_kernel.h b/fs/ncpfs/ncplib_kernel.h
deleted file mode 100644
index aaae8aa9bf7d..000000000000
--- a/fs/ncpfs/ncplib_kernel.h
+++ /dev/null
@@ -1,215 +0,0 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * ncplib_kernel.h
4 *
5 * Copyright (C) 1995, 1996 by Volker Lendecke
6 * Modified for big endian by J.F. Chadima and David S. Miller
7 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
8 * Modified 1998, 1999 Wolfram Pienkoss for NLS
9 * Modified 1999 Wolfram Pienkoss for directory caching
10 *
11 */
12
13#ifndef _NCPLIB_H
14#define _NCPLIB_H
15
16
17#include <linux/fs.h>
18#include <linux/types.h>
19#include <linux/errno.h>
20#include <linux/slab.h>
21#include <linux/stat.h>
22#include <linux/fcntl.h>
23#include <linux/pagemap.h>
24
25#include <linux/uaccess.h>
26#include <asm/byteorder.h>
27#include <asm/unaligned.h>
28#include <asm/string.h>
29
30#ifdef CONFIG_NCPFS_NLS
31#include <linux/nls.h>
32#else
33#include <linux/ctype.h>
34#endif /* CONFIG_NCPFS_NLS */
35
36#define NCP_MIN_SYMLINK_SIZE 8
37#define NCP_MAX_SYMLINK_SIZE 512
38
39#define NCP_BLOCK_SHIFT 9
40#define NCP_BLOCK_SIZE (1 << (NCP_BLOCK_SHIFT))
41
42int ncp_negotiate_buffersize(struct ncp_server *, int, int *);
43int ncp_negotiate_size_and_options(struct ncp_server *server, int size,
44 int options, int *ret_size, int *ret_options);
45
46int ncp_get_volume_info_with_number(struct ncp_server* server, int n,
47 struct ncp_volume_info *target);
48
49int ncp_get_directory_info(struct ncp_server* server, __u8 dirhandle,
50 struct ncp_volume_info* target);
51
52int ncp_close_file(struct ncp_server *, const char *);
53static inline int ncp_read_bounce_size(__u32 size) {
54 return sizeof(struct ncp_reply_header) + 2 + 2 + size + 8;
55};
56int ncp_read_bounce(struct ncp_server *, const char *, __u32, __u16,
57 struct iov_iter *, int *, void *bounce, __u32 bouncelen);
58int ncp_read_kernel(struct ncp_server *, const char *, __u32, __u16,
59 char *, int *);
60int ncp_write_kernel(struct ncp_server *, const char *, __u32, __u16,
61 const char *, int *);
62
63static inline void ncp_inode_close(struct inode *inode) {
64 atomic_dec(&NCP_FINFO(inode)->opened);
65}
66
67void ncp_extract_file_info(const void* src, struct nw_info_struct* target);
68int ncp_obtain_info(struct ncp_server *server, struct inode *, const char *,
69 struct nw_info_struct *target);
70int ncp_obtain_nfs_info(struct ncp_server *server, struct nw_info_struct *target);
71int ncp_update_known_namespace(struct ncp_server *server, __u8 volume, int *ret_ns);
72int ncp_get_volume_root(struct ncp_server *server, const char *volname,
73 __u32 *volume, __le32 *dirent, __le32 *dosdirent);
74int ncp_lookup_volume(struct ncp_server *, const char *, struct nw_info_struct *);
75int ncp_modify_file_or_subdir_dos_info(struct ncp_server *, struct inode *,
76 __le32, const struct nw_modify_dos_info *info);
77int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *, struct inode *,
78 const char* path, __le32, const struct nw_modify_dos_info *info);
79int ncp_modify_nfs_info(struct ncp_server *, __u8 volnum, __le32 dirent,
80 __u32 mode, __u32 rdev);
81
82int ncp_del_file_or_subdir2(struct ncp_server *, struct dentry*);
83int ncp_del_file_or_subdir(struct ncp_server *, struct inode *, const char *);
84int ncp_open_create_file_or_subdir(struct ncp_server *, struct inode *, const char *,
85 int, __le32, __le16, struct ncp_entry_info *);
86
87int ncp_initialize_search(struct ncp_server *, struct inode *,
88 struct nw_search_sequence *target);
89int ncp_search_for_fileset(struct ncp_server *server,
90 struct nw_search_sequence *seq,
91 int* more, int* cnt,
92 char* buffer, size_t bufsize,
93 char** rbuf, size_t* rsize);
94
95int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
96 struct inode *, const char *, struct inode *, const char *);
97
98
99int
100ncp_LogPhysicalRecord(struct ncp_server *server,
101 const char *file_id, __u8 locktype,
102 __u32 offset, __u32 length, __u16 timeout);
103
104#ifdef CONFIG_NCPFS_IOCTL_LOCKING
105int
106ncp_ClearPhysicalRecord(struct ncp_server *server,
107 const char *file_id,
108 __u32 offset, __u32 length);
109#endif /* CONFIG_NCPFS_IOCTL_LOCKING */
110
111int
112ncp_mount_subdir(struct ncp_server *, __u8, __u8, __le32,
113 __u32* volume, __le32* dirent, __le32* dosdirent);
114int ncp_dirhandle_alloc(struct ncp_server *, __u8 vol, __le32 dirent, __u8 *dirhandle);
115int ncp_dirhandle_free(struct ncp_server *, __u8 dirhandle);
116
117int ncp_create_new(struct inode *dir, struct dentry *dentry,
118 umode_t mode, dev_t rdev, __le32 attributes);
119
120static inline int ncp_is_nfs_extras(struct ncp_server* server, unsigned int volnum) {
121#ifdef CONFIG_NCPFS_NFS_NS
122 return (server->m.flags & NCP_MOUNT_NFS_EXTRAS) &&
123 (server->name_space[volnum] == NW_NS_NFS);
124#else
125 return 0;
126#endif
127}
128
129#ifdef CONFIG_NCPFS_NLS
130
131int ncp__io2vol(struct ncp_server *, unsigned char *, unsigned int *,
132 const unsigned char *, unsigned int, int);
133int ncp__vol2io(struct ncp_server *, unsigned char *, unsigned int *,
134 const unsigned char *, unsigned int, int);
135
136#define NCP_ESC ':'
137#define NCP_IO_TABLE(sb) (NCP_SBP(sb)->nls_io)
138#define ncp_tolower(t, c) nls_tolower(t, c)
139#define ncp_toupper(t, c) nls_toupper(t, c)
140#define ncp_strnicmp(t, s1, s2, len) \
141 nls_strnicmp(t, s1, s2, len)
142#define ncp_io2vol(S,m,i,n,k,U) ncp__io2vol(S,m,i,n,k,U)
143#define ncp_vol2io(S,m,i,n,k,U) ncp__vol2io(S,m,i,n,k,U)
144
145#else
146
147int ncp__io2vol(unsigned char *, unsigned int *,
148 const unsigned char *, unsigned int, int);
149int ncp__vol2io(unsigned char *, unsigned int *,
150 const unsigned char *, unsigned int, int);
151
152#define NCP_IO_TABLE(sb) NULL
153#define ncp_tolower(t, c) tolower(c)
154#define ncp_toupper(t, c) toupper(c)
155#define ncp_io2vol(S,m,i,n,k,U) ncp__io2vol(m,i,n,k,U)
156#define ncp_vol2io(S,m,i,n,k,U) ncp__vol2io(m,i,n,k,U)
157
158
159static inline int ncp_strnicmp(const struct nls_table *t,
160 const unsigned char *s1, const unsigned char *s2, int len)
161{
162 while (len--) {
163 if (tolower(*s1++) != tolower(*s2++))
164 return 1;
165 }
166
167 return 0;
168}
169
170#endif /* CONFIG_NCPFS_NLS */
171
172#define NCP_GET_AGE(dentry) (jiffies - (dentry)->d_time)
173#define NCP_MAX_AGE(server) atomic_read(&(server)->dentry_ttl)
174#define NCP_TEST_AGE(server,dentry) (NCP_GET_AGE(dentry) < NCP_MAX_AGE(server))
175
176static inline void
177ncp_age_dentry(struct ncp_server* server, struct dentry* dentry)
178{
179 dentry->d_time = jiffies - NCP_MAX_AGE(server);
180}
181
182static inline void
183ncp_new_dentry(struct dentry* dentry)
184{
185 dentry->d_time = jiffies;
186}
187
188struct ncp_cache_head {
189 time_t mtime;
190 unsigned long time; /* cache age */
191 unsigned long end; /* last valid fpos in cache */
192 int eof;
193};
194
195#define NCP_DIRCACHE_SIZE ((int)(PAGE_SIZE/sizeof(struct dentry *)))
196union ncp_dir_cache {
197 struct ncp_cache_head head;
198 struct dentry *dentry[NCP_DIRCACHE_SIZE];
199};
200
201#define NCP_FIRSTCACHE_SIZE ((int)((NCP_DIRCACHE_SIZE * \
202 sizeof(struct dentry *) - sizeof(struct ncp_cache_head)) / \
203 sizeof(struct dentry *)))
204
205#define NCP_DIRCACHE_START (NCP_DIRCACHE_SIZE - NCP_FIRSTCACHE_SIZE)
206
207struct ncp_cache_control {
208 struct ncp_cache_head head;
209 struct page *page;
210 union ncp_dir_cache *cache;
211 unsigned long fpos, ofs;
212 int filled, valid, idx;
213};
214
215#endif /* _NCPLIB_H */
diff --git a/fs/ncpfs/ncpsign_kernel.c b/fs/ncpfs/ncpsign_kernel.c
deleted file mode 100644
index 8085b1a3ba47..000000000000
--- a/fs/ncpfs/ncpsign_kernel.c
+++ /dev/null
@@ -1,128 +0,0 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * ncpsign_kernel.c
4 *
5 * Arne de Bruijn (arne@knoware.nl), 1997
6 *
7 */
8
9
10#ifdef CONFIG_NCPFS_PACKET_SIGNING
11
12#include <linux/string.h>
13#include <linux/ncp.h>
14#include <linux/bitops.h>
15#include "ncp_fs.h"
16#include "ncpsign_kernel.h"
17
18/* i386: 32-bit, little endian, handles mis-alignment */
19#ifdef __i386__
20#define GET_LE32(p) (*(const int *)(p))
21#define PUT_LE32(p,v) { *(int *)(p)=v; }
22#else
23/* from include/ncplib.h */
24#define BVAL(buf,pos) (((const __u8 *)(buf))[pos])
25#define PVAL(buf,pos) ((unsigned)BVAL(buf,pos))
26#define BSET(buf,pos,val) (((__u8 *)(buf))[pos] = (val))
27
28static inline __u16
29WVAL_LH(const __u8 * buf, int pos)
30{
31 return PVAL(buf, pos) | PVAL(buf, pos + 1) << 8;
32}
33static inline __u32
34DVAL_LH(const __u8 * buf, int pos)
35{
36 return WVAL_LH(buf, pos) | WVAL_LH(buf, pos + 2) << 16;
37}
38static inline void
39WSET_LH(__u8 * buf, int pos, __u16 val)
40{
41 BSET(buf, pos, val & 0xff);
42 BSET(buf, pos + 1, val >> 8);
43}
44static inline void
45DSET_LH(__u8 * buf, int pos, __u32 val)
46{
47 WSET_LH(buf, pos, val & 0xffff);
48 WSET_LH(buf, pos + 2, val >> 16);
49}
50
51#define GET_LE32(p) DVAL_LH(p,0)
52#define PUT_LE32(p,v) DSET_LH(p,0,v)
53#endif
54
55static void nwsign(char *r_data1, char *r_data2, char *outdata) {
56 int i;
57 unsigned int w0,w1,w2,w3;
58 static int rbit[4]={0, 2, 1, 3};
59#ifdef __i386__
60 unsigned int *data2=(unsigned int *)r_data2;
61#else
62 unsigned int data2[16];
63 for (i=0;i<16;i++)
64 data2[i]=GET_LE32(r_data2+(i<<2));
65#endif
66 w0=GET_LE32(r_data1);
67 w1=GET_LE32(r_data1+4);
68 w2=GET_LE32(r_data1+8);
69 w3=GET_LE32(r_data1+12);
70 for (i=0;i<16;i+=4) {
71 w0=rol32(w0 + ((w1 & w2) | ((~w1) & w3)) + data2[i+0],3);
72 w3=rol32(w3 + ((w0 & w1) | ((~w0) & w2)) + data2[i+1],7);
73 w2=rol32(w2 + ((w3 & w0) | ((~w3) & w1)) + data2[i+2],11);
74 w1=rol32(w1 + ((w2 & w3) | ((~w2) & w0)) + data2[i+3],19);
75 }
76 for (i=0;i<4;i++) {
77 w0=rol32(w0 + (((w2 | w3) & w1) | (w2 & w3)) + 0x5a827999 + data2[i+0],3);
78 w3=rol32(w3 + (((w1 | w2) & w0) | (w1 & w2)) + 0x5a827999 + data2[i+4],5);
79 w2=rol32(w2 + (((w0 | w1) & w3) | (w0 & w1)) + 0x5a827999 + data2[i+8],9);
80 w1=rol32(w1 + (((w3 | w0) & w2) | (w3 & w0)) + 0x5a827999 + data2[i+12],13);
81 }
82 for (i=0;i<4;i++) {
83 w0=rol32(w0 + ((w1 ^ w2) ^ w3) + 0x6ed9eba1 + data2[rbit[i]+0],3);
84 w3=rol32(w3 + ((w0 ^ w1) ^ w2) + 0x6ed9eba1 + data2[rbit[i]+8],9);
85 w2=rol32(w2 + ((w3 ^ w0) ^ w1) + 0x6ed9eba1 + data2[rbit[i]+4],11);
86 w1=rol32(w1 + ((w2 ^ w3) ^ w0) + 0x6ed9eba1 + data2[rbit[i]+12],15);
87 }
88 PUT_LE32(outdata,(w0+GET_LE32(r_data1)) & 0xffffffff);
89 PUT_LE32(outdata+4,(w1+GET_LE32(r_data1+4)) & 0xffffffff);
90 PUT_LE32(outdata+8,(w2+GET_LE32(r_data1+8)) & 0xffffffff);
91 PUT_LE32(outdata+12,(w3+GET_LE32(r_data1+12)) & 0xffffffff);
92}
93
94/* Make a signature for the current packet and add it at the end of the */
95/* packet. */
96void __sign_packet(struct ncp_server *server, const char *packet, size_t size, __u32 totalsize, void *sign_buff) {
97 unsigned char data[64];
98
99 memcpy(data, server->sign_root, 8);
100 *(__u32*)(data + 8) = totalsize;
101 if (size < 52) {
102 memcpy(data + 12, packet, size);
103 memset(data + 12 + size, 0, 52 - size);
104 } else {
105 memcpy(data + 12, packet, 52);
106 }
107 nwsign(server->sign_last, data, server->sign_last);
108 memcpy(sign_buff, server->sign_last, 8);
109}
110
111int sign_verify_reply(struct ncp_server *server, const char *packet, size_t size, __u32 totalsize, const void *sign_buff) {
112 unsigned char data[64];
113 unsigned char hash[16];
114
115 memcpy(data, server->sign_root, 8);
116 *(__u32*)(data + 8) = totalsize;
117 if (size < 52) {
118 memcpy(data + 12, packet, size);
119 memset(data + 12 + size, 0, 52 - size);
120 } else {
121 memcpy(data + 12, packet, 52);
122 }
123 nwsign(server->sign_last, data, hash);
124 return memcmp(sign_buff, hash, 8);
125}
126
127#endif /* CONFIG_NCPFS_PACKET_SIGNING */
128
diff --git a/fs/ncpfs/ncpsign_kernel.h b/fs/ncpfs/ncpsign_kernel.h
deleted file mode 100644
index 57ff0a0650b8..000000000000
--- a/fs/ncpfs/ncpsign_kernel.h
+++ /dev/null
@@ -1,27 +0,0 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2/*
3 * ncpsign_kernel.h
4 *
5 * Arne de Bruijn (arne@knoware.nl), 1997
6 *
7 */
8
9#ifndef _NCPSIGN_KERNEL_H
10#define _NCPSIGN_KERNEL_H
11
12#ifdef CONFIG_NCPFS_PACKET_SIGNING
13void __sign_packet(struct ncp_server *server, const char *data, size_t size, __u32 totalsize, void *sign_buff);
14int sign_verify_reply(struct ncp_server *server, const char *data, size_t size, __u32 totalsize, const void *sign_buff);
15#endif
16
17static inline size_t sign_packet(struct ncp_server *server, const char *data, size_t size, __u32 totalsize, void *sign_buff) {
18#ifdef CONFIG_NCPFS_PACKET_SIGNING
19 if (server->sign_active) {
20 __sign_packet(server, data, size, totalsize, sign_buff);
21 return 8;
22 }
23#endif
24 return 0;
25}
26
27#endif
diff --git a/fs/ncpfs/sock.c b/fs/ncpfs/sock.c
deleted file mode 100644
index efb176b1751a..000000000000
--- a/fs/ncpfs/sock.c
+++ /dev/null
@@ -1,854 +0,0 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * linux/fs/ncpfs/sock.c
4 *
5 * Copyright (C) 1992, 1993 Rick Sladkey
6 *
7 * Modified 1995, 1996 by Volker Lendecke to be usable for ncp
8 * Modified 1997 Peter Waltenberg, Bill Hawes, David Woodhouse for 2.1 dcache
9 *
10 */
11
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
14#include <linux/time.h>
15#include <linux/errno.h>
16#include <linux/socket.h>
17#include <linux/fcntl.h>
18#include <linux/stat.h>
19#include <linux/string.h>
20#include <linux/sched/signal.h>
21#include <linux/uaccess.h>
22#include <linux/in.h>
23#include <linux/net.h>
24#include <linux/mm.h>
25#include <linux/netdevice.h>
26#include <linux/signal.h>
27#include <linux/slab.h>
28#include <net/scm.h>
29#include <net/sock.h>
30#include <linux/ipx.h>
31#include <linux/poll.h>
32#include <linux/file.h>
33
34#include "ncp_fs.h"
35
36#include "ncpsign_kernel.h"
37
38static int _recv(struct socket *sock, void *buf, int size, unsigned flags)
39{
40 struct msghdr msg = {NULL, };
41 struct kvec iov = {buf, size};
42 return kernel_recvmsg(sock, &msg, &iov, 1, size, flags);
43}
44
45static int _send(struct socket *sock, const void *buff, int len)
46{
47 struct msghdr msg = { .msg_flags = 0 };
48 struct kvec vec = {.iov_base = (void *)buff, .iov_len = len};
49 iov_iter_kvec(&msg.msg_iter, WRITE | ITER_KVEC, &vec, 1, len);
50 return sock_sendmsg(sock, &msg);
51}
52
53struct ncp_request_reply {
54 struct list_head req;
55 wait_queue_head_t wq;
56 atomic_t refs;
57 unsigned char* reply_buf;
58 size_t datalen;
59 int result;
60 enum { RQ_DONE, RQ_INPROGRESS, RQ_QUEUED, RQ_IDLE, RQ_ABANDONED } status;
61 struct iov_iter from;
62 struct kvec tx_iov[3];
63 u_int16_t tx_type;
64 u_int32_t sign[6];
65};
66
67static inline struct ncp_request_reply* ncp_alloc_req(void)
68{
69 struct ncp_request_reply *req;
70
71 req = kmalloc(sizeof(struct ncp_request_reply), GFP_KERNEL);
72 if (!req)
73 return NULL;
74
75 init_waitqueue_head(&req->wq);
76 atomic_set(&req->refs, (1));
77 req->status = RQ_IDLE;
78
79 return req;
80}
81
82static void ncp_req_get(struct ncp_request_reply *req)
83{
84 atomic_inc(&req->refs);
85}
86
87static void ncp_req_put(struct ncp_request_reply *req)
88{
89 if (atomic_dec_and_test(&req->refs))
90 kfree(req);
91}
92
93void ncp_tcp_data_ready(struct sock *sk)
94{
95 struct ncp_server *server = sk->sk_user_data;
96
97 server->data_ready(sk);
98 schedule_work(&server->rcv.tq);
99}
100
101void ncp_tcp_error_report(struct sock *sk)
102{
103 struct ncp_server *server = sk->sk_user_data;
104
105 server->error_report(sk);
106 schedule_work(&server->rcv.tq);
107}
108
109void ncp_tcp_write_space(struct sock *sk)
110{
111 struct ncp_server *server = sk->sk_user_data;
112
113 /* We do not need any locking: we first set tx.creq, and then we do sendmsg,
114 not vice versa... */
115 server->write_space(sk);
116 if (server->tx.creq)
117 schedule_work(&server->tx.tq);
118}
119
120void ncpdgram_timeout_call(struct timer_list *t)
121{
122 struct ncp_server *server = from_timer(server, t, timeout_tm);
123
124 schedule_work(&server->timeout_tq);
125}
126
127static inline void ncp_finish_request(struct ncp_server *server, struct ncp_request_reply *req, int result)
128{
129 req->result = result;
130 if (req->status != RQ_ABANDONED)
131 memcpy(req->reply_buf, server->rxbuf, req->datalen);
132 req->status = RQ_DONE;
133 wake_up_all(&req->wq);
134 ncp_req_put(req);
135}
136
137static void __abort_ncp_connection(struct ncp_server *server)
138{
139 struct ncp_request_reply *req;
140
141 ncp_invalidate_conn(server);
142 del_timer(&server->timeout_tm);
143 while (!list_empty(&server->tx.requests)) {
144 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
145
146 list_del_init(&req->req);
147 ncp_finish_request(server, req, -EIO);
148 }
149 req = server->rcv.creq;
150 if (req) {
151 server->rcv.creq = NULL;
152 ncp_finish_request(server, req, -EIO);
153 server->rcv.ptr = NULL;
154 server->rcv.state = 0;
155 }
156 req = server->tx.creq;
157 if (req) {
158 server->tx.creq = NULL;
159 ncp_finish_request(server, req, -EIO);
160 }
161}
162
163static inline int get_conn_number(struct ncp_reply_header *rp)
164{
165 return rp->conn_low | (rp->conn_high << 8);
166}
167
168static inline void __ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
169{
170 /* If req is done, we got signal, but we also received answer... */
171 switch (req->status) {
172 case RQ_IDLE:
173 case RQ_DONE:
174 break;
175 case RQ_QUEUED:
176 list_del_init(&req->req);
177 ncp_finish_request(server, req, err);
178 break;
179 case RQ_INPROGRESS:
180 req->status = RQ_ABANDONED;
181 break;
182 case RQ_ABANDONED:
183 break;
184 }
185}
186
187static inline void ncp_abort_request(struct ncp_server *server, struct ncp_request_reply *req, int err)
188{
189 mutex_lock(&server->rcv.creq_mutex);
190 __ncp_abort_request(server, req, err);
191 mutex_unlock(&server->rcv.creq_mutex);
192}
193
194static inline void __ncptcp_abort(struct ncp_server *server)
195{
196 __abort_ncp_connection(server);
197}
198
199static int ncpdgram_send(struct socket *sock, struct ncp_request_reply *req)
200{
201 struct msghdr msg = { .msg_iter = req->from, .msg_flags = MSG_DONTWAIT };
202 return sock_sendmsg(sock, &msg);
203}
204
205static void __ncptcp_try_send(struct ncp_server *server)
206{
207 struct ncp_request_reply *rq;
208 struct msghdr msg = { .msg_flags = MSG_NOSIGNAL | MSG_DONTWAIT };
209 int result;
210
211 rq = server->tx.creq;
212 if (!rq)
213 return;
214
215 msg.msg_iter = rq->from;
216 result = sock_sendmsg(server->ncp_sock, &msg);
217
218 if (result == -EAGAIN)
219 return;
220
221 if (result < 0) {
222 pr_err("tcp: Send failed: %d\n", result);
223 __ncp_abort_request(server, rq, result);
224 return;
225 }
226 if (!msg_data_left(&msg)) {
227 server->rcv.creq = rq;
228 server->tx.creq = NULL;
229 return;
230 }
231 rq->from = msg.msg_iter;
232}
233
234static inline void ncp_init_header(struct ncp_server *server, struct ncp_request_reply *req, struct ncp_request_header *h)
235{
236 req->status = RQ_INPROGRESS;
237 h->conn_low = server->connection;
238 h->conn_high = server->connection >> 8;
239 h->sequence = ++server->sequence;
240}
241
242static void ncpdgram_start_request(struct ncp_server *server, struct ncp_request_reply *req)
243{
244 size_t signlen, len = req->tx_iov[1].iov_len;
245 struct ncp_request_header *h = req->tx_iov[1].iov_base;
246
247 ncp_init_header(server, req, h);
248 signlen = sign_packet(server,
249 req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
250 len - sizeof(struct ncp_request_header) + 1,
251 cpu_to_le32(len), req->sign);
252 if (signlen) {
253 /* NCP over UDP appends signature */
254 req->tx_iov[2].iov_base = req->sign;
255 req->tx_iov[2].iov_len = signlen;
256 }
257 iov_iter_kvec(&req->from, WRITE | ITER_KVEC,
258 req->tx_iov + 1, signlen ? 2 : 1, len + signlen);
259 server->rcv.creq = req;
260 server->timeout_last = server->m.time_out;
261 server->timeout_retries = server->m.retry_count;
262 ncpdgram_send(server->ncp_sock, req);
263 mod_timer(&server->timeout_tm, jiffies + server->m.time_out);
264}
265
266#define NCP_TCP_XMIT_MAGIC (0x446D6454)
267#define NCP_TCP_XMIT_VERSION (1)
268#define NCP_TCP_RCVD_MAGIC (0x744E6350)
269
270static void ncptcp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
271{
272 size_t signlen, len = req->tx_iov[1].iov_len;
273 struct ncp_request_header *h = req->tx_iov[1].iov_base;
274
275 ncp_init_header(server, req, h);
276 signlen = sign_packet(server, req->tx_iov[1].iov_base + sizeof(struct ncp_request_header) - 1,
277 len - sizeof(struct ncp_request_header) + 1,
278 cpu_to_be32(len + 24), req->sign + 4) + 16;
279
280 req->sign[0] = htonl(NCP_TCP_XMIT_MAGIC);
281 req->sign[1] = htonl(len + signlen);
282 req->sign[2] = htonl(NCP_TCP_XMIT_VERSION);
283 req->sign[3] = htonl(req->datalen + 8);
284 /* NCP over TCP prepends signature */
285 req->tx_iov[0].iov_base = req->sign;
286 req->tx_iov[0].iov_len = signlen;
287 iov_iter_kvec(&req->from, WRITE | ITER_KVEC,
288 req->tx_iov, 2, len + signlen);
289
290 server->tx.creq = req;
291 __ncptcp_try_send(server);
292}
293
294static inline void __ncp_start_request(struct ncp_server *server, struct ncp_request_reply *req)
295{
296 /* we copy the data so that we do not depend on the caller
297 staying alive */
298 memcpy(server->txbuf, req->tx_iov[1].iov_base, req->tx_iov[1].iov_len);
299 req->tx_iov[1].iov_base = server->txbuf;
300
301 if (server->ncp_sock->type == SOCK_STREAM)
302 ncptcp_start_request(server, req);
303 else
304 ncpdgram_start_request(server, req);
305}
306
307static int ncp_add_request(struct ncp_server *server, struct ncp_request_reply *req)
308{
309 mutex_lock(&server->rcv.creq_mutex);
310 if (!ncp_conn_valid(server)) {
311 mutex_unlock(&server->rcv.creq_mutex);
312 pr_err("tcp: Server died\n");
313 return -EIO;
314 }
315 ncp_req_get(req);
316 if (server->tx.creq || server->rcv.creq) {
317 req->status = RQ_QUEUED;
318 list_add_tail(&req->req, &server->tx.requests);
319 mutex_unlock(&server->rcv.creq_mutex);
320 return 0;
321 }
322 __ncp_start_request(server, req);
323 mutex_unlock(&server->rcv.creq_mutex);
324 return 0;
325}
326
327static void __ncp_next_request(struct ncp_server *server)
328{
329 struct ncp_request_reply *req;
330
331 server->rcv.creq = NULL;
332 if (list_empty(&server->tx.requests)) {
333 return;
334 }
335 req = list_entry(server->tx.requests.next, struct ncp_request_reply, req);
336 list_del_init(&req->req);
337 __ncp_start_request(server, req);
338}
339
340static void info_server(struct ncp_server *server, unsigned int id, const void * data, size_t len)
341{
342 if (server->info_sock) {
343 struct msghdr msg = { .msg_flags = MSG_NOSIGNAL };
344 __be32 hdr[2] = {cpu_to_be32(len + 8), cpu_to_be32(id)};
345 struct kvec iov[2] = {
346 {.iov_base = hdr, .iov_len = 8},
347 {.iov_base = (void *)data, .iov_len = len},
348 };
349
350 iov_iter_kvec(&msg.msg_iter, ITER_KVEC | WRITE,
351 iov, 2, len + 8);
352
353 sock_sendmsg(server->info_sock, &msg);
354 }
355}
356
357void ncpdgram_rcv_proc(struct work_struct *work)
358{
359 struct ncp_server *server =
360 container_of(work, struct ncp_server, rcv.tq);
361 struct socket* sock;
362
363 sock = server->ncp_sock;
364
365 while (1) {
366 struct ncp_reply_header reply;
367 int result;
368
369 result = _recv(sock, &reply, sizeof(reply), MSG_PEEK | MSG_DONTWAIT);
370 if (result < 0) {
371 break;
372 }
373 if (result >= sizeof(reply)) {
374 struct ncp_request_reply *req;
375
376 if (reply.type == NCP_WATCHDOG) {
377 unsigned char buf[10];
378
379 if (server->connection != get_conn_number(&reply)) {
380 goto drop;
381 }
382 result = _recv(sock, buf, sizeof(buf), MSG_DONTWAIT);
383 if (result < 0) {
384 ncp_dbg(1, "recv failed with %d\n", result);
385 continue;
386 }
387 if (result < 10) {
388 ncp_dbg(1, "too short (%u) watchdog packet\n", result);
389 continue;
390 }
391 if (buf[9] != '?') {
392 ncp_dbg(1, "bad signature (%02X) in watchdog packet\n", buf[9]);
393 continue;
394 }
395 buf[9] = 'Y';
396 _send(sock, buf, sizeof(buf));
397 continue;
398 }
399 if (reply.type != NCP_POSITIVE_ACK && reply.type != NCP_REPLY) {
400 result = _recv(sock, server->unexpected_packet.data, sizeof(server->unexpected_packet.data), MSG_DONTWAIT);
401 if (result < 0) {
402 continue;
403 }
404 info_server(server, 0, server->unexpected_packet.data, result);
405 continue;
406 }
407 mutex_lock(&server->rcv.creq_mutex);
408 req = server->rcv.creq;
409 if (req && (req->tx_type == NCP_ALLOC_SLOT_REQUEST || (server->sequence == reply.sequence &&
410 server->connection == get_conn_number(&reply)))) {
411 if (reply.type == NCP_POSITIVE_ACK) {
412 server->timeout_retries = server->m.retry_count;
413 server->timeout_last = NCP_MAX_RPC_TIMEOUT;
414 mod_timer(&server->timeout_tm, jiffies + NCP_MAX_RPC_TIMEOUT);
415 } else if (reply.type == NCP_REPLY) {
416 result = _recv(sock, server->rxbuf, req->datalen, MSG_DONTWAIT);
417#ifdef CONFIG_NCPFS_PACKET_SIGNING
418 if (result >= 0 && server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
419 if (result < 8 + 8) {
420 result = -EIO;
421 } else {
422 unsigned int hdrl;
423
424 result -= 8;
425 hdrl = sock->sk->sk_family == AF_INET ? 8 : 6;
426 if (sign_verify_reply(server, server->rxbuf + hdrl, result - hdrl, cpu_to_le32(result), server->rxbuf + result)) {
427 pr_info("Signature violation\n");
428 result = -EIO;
429 }
430 }
431 }
432#endif
433 del_timer(&server->timeout_tm);
434 server->rcv.creq = NULL;
435 ncp_finish_request(server, req, result);
436 __ncp_next_request(server);
437 mutex_unlock(&server->rcv.creq_mutex);
438 continue;
439 }
440 }
441 mutex_unlock(&server->rcv.creq_mutex);
442 }
443drop:;
444 _recv(sock, &reply, sizeof(reply), MSG_DONTWAIT);
445 }
446}
447
448static void __ncpdgram_timeout_proc(struct ncp_server *server)
449{
450 /* If timer is pending, we are processing another request... */
451 if (!timer_pending(&server->timeout_tm)) {
452 struct ncp_request_reply* req;
453
454 req = server->rcv.creq;
455 if (req) {
456 int timeout;
457
458 if (server->m.flags & NCP_MOUNT_SOFT) {
459 if (server->timeout_retries-- == 0) {
460 __ncp_abort_request(server, req, -ETIMEDOUT);
461 return;
462 }
463 }
464 /* Ignore errors */
465 ncpdgram_send(server->ncp_sock, req);
466 timeout = server->timeout_last << 1;
467 if (timeout > NCP_MAX_RPC_TIMEOUT) {
468 timeout = NCP_MAX_RPC_TIMEOUT;
469 }
470 server->timeout_last = timeout;
471 mod_timer(&server->timeout_tm, jiffies + timeout);
472 }
473 }
474}
475
476void ncpdgram_timeout_proc(struct work_struct *work)
477{
478 struct ncp_server *server =
479 container_of(work, struct ncp_server, timeout_tq);
480 mutex_lock(&server->rcv.creq_mutex);
481 __ncpdgram_timeout_proc(server);
482 mutex_unlock(&server->rcv.creq_mutex);
483}
484
485static int do_tcp_rcv(struct ncp_server *server, void *buffer, size_t len)
486{
487 int result;
488
489 if (buffer) {
490 result = _recv(server->ncp_sock, buffer, len, MSG_DONTWAIT);
491 } else {
492 static unsigned char dummy[1024];
493
494 if (len > sizeof(dummy)) {
495 len = sizeof(dummy);
496 }
497 result = _recv(server->ncp_sock, dummy, len, MSG_DONTWAIT);
498 }
499 if (result < 0) {
500 return result;
501 }
502 if (result > len) {
503 pr_err("tcp: bug in recvmsg (%u > %zu)\n", result, len);
504 return -EIO;
505 }
506 return result;
507}
508
509static int __ncptcp_rcv_proc(struct ncp_server *server)
510{
511 /* We have to check the result, so store the complete header */
512 while (1) {
513 int result;
514 struct ncp_request_reply *req;
515 int datalen;
516 int type;
517
518 while (server->rcv.len) {
519 result = do_tcp_rcv(server, server->rcv.ptr, server->rcv.len);
520 if (result == -EAGAIN) {
521 return 0;
522 }
523 if (result <= 0) {
524 req = server->rcv.creq;
525 if (req) {
526 __ncp_abort_request(server, req, -EIO);
527 } else {
528 __ncptcp_abort(server);
529 }
530 if (result < 0) {
531 pr_err("tcp: error in recvmsg: %d\n", result);
532 } else {
533 ncp_dbg(1, "tcp: EOF\n");
534 }
535 return -EIO;
536 }
537 if (server->rcv.ptr) {
538 server->rcv.ptr += result;
539 }
540 server->rcv.len -= result;
541 }
542 switch (server->rcv.state) {
543 case 0:
544 if (server->rcv.buf.magic != htonl(NCP_TCP_RCVD_MAGIC)) {
545 pr_err("tcp: Unexpected reply type %08X\n", ntohl(server->rcv.buf.magic));
546 __ncptcp_abort(server);
547 return -EIO;
548 }
549 datalen = ntohl(server->rcv.buf.len) & 0x0FFFFFFF;
550 if (datalen < 10) {
551 pr_err("tcp: Unexpected reply len %d\n", datalen);
552 __ncptcp_abort(server);
553 return -EIO;
554 }
555#ifdef CONFIG_NCPFS_PACKET_SIGNING
556 if (server->sign_active) {
557 if (datalen < 18) {
558 pr_err("tcp: Unexpected reply len %d\n", datalen);
559 __ncptcp_abort(server);
560 return -EIO;
561 }
562 server->rcv.buf.len = datalen - 8;
563 server->rcv.ptr = (unsigned char*)&server->rcv.buf.p1;
564 server->rcv.len = 8;
565 server->rcv.state = 4;
566 break;
567 }
568#endif
569 type = ntohs(server->rcv.buf.type);
570#ifdef CONFIG_NCPFS_PACKET_SIGNING
571cont:;
572#endif
573 if (type != NCP_REPLY) {
574 if (datalen - 8 <= sizeof(server->unexpected_packet.data)) {
575 *(__u16*)(server->unexpected_packet.data) = htons(type);
576 server->unexpected_packet.len = datalen - 8;
577
578 server->rcv.state = 5;
579 server->rcv.ptr = server->unexpected_packet.data + 2;
580 server->rcv.len = datalen - 10;
581 break;
582 }
583 ncp_dbg(1, "tcp: Unexpected NCP type %02X\n", type);
584skipdata2:;
585 server->rcv.state = 2;
586skipdata:;
587 server->rcv.ptr = NULL;
588 server->rcv.len = datalen - 10;
589 break;
590 }
591 req = server->rcv.creq;
592 if (!req) {
593 ncp_dbg(1, "Reply without appropriate request\n");
594 goto skipdata2;
595 }
596 if (datalen > req->datalen + 8) {
597 pr_err("tcp: Unexpected reply len %d (expected at most %zd)\n", datalen, req->datalen + 8);
598 server->rcv.state = 3;
599 goto skipdata;
600 }
601 req->datalen = datalen - 8;
602 ((struct ncp_reply_header*)server->rxbuf)->type = NCP_REPLY;
603 server->rcv.ptr = server->rxbuf + 2;
604 server->rcv.len = datalen - 10;
605 server->rcv.state = 1;
606 break;
607#ifdef CONFIG_NCPFS_PACKET_SIGNING
608 case 4:
609 datalen = server->rcv.buf.len;
610 type = ntohs(server->rcv.buf.type2);
611 goto cont;
612#endif
613 case 1:
614 req = server->rcv.creq;
615 if (req->tx_type != NCP_ALLOC_SLOT_REQUEST) {
616 if (((struct ncp_reply_header*)server->rxbuf)->sequence != server->sequence) {
617 pr_err("tcp: Bad sequence number\n");
618 __ncp_abort_request(server, req, -EIO);
619 return -EIO;
620 }
621 if ((((struct ncp_reply_header*)server->rxbuf)->conn_low | (((struct ncp_reply_header*)server->rxbuf)->conn_high << 8)) != server->connection) {
622 pr_err("tcp: Connection number mismatch\n");
623 __ncp_abort_request(server, req, -EIO);
624 return -EIO;
625 }
626 }
627#ifdef CONFIG_NCPFS_PACKET_SIGNING
628 if (server->sign_active && req->tx_type != NCP_DEALLOC_SLOT_REQUEST) {
629 if (sign_verify_reply(server, server->rxbuf + 6, req->datalen - 6, cpu_to_be32(req->datalen + 16), &server->rcv.buf.type)) {
630 pr_err("tcp: Signature violation\n");
631 __ncp_abort_request(server, req, -EIO);
632 return -EIO;
633 }
634 }
635#endif
636 ncp_finish_request(server, req, req->datalen);
637 nextreq:;
638 __ncp_next_request(server);
639 case 2:
640 next:;
641 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
642 server->rcv.len = 10;
643 server->rcv.state = 0;
644 break;
645 case 3:
646 ncp_finish_request(server, server->rcv.creq, -EIO);
647 goto nextreq;
648 case 5:
649 info_server(server, 0, server->unexpected_packet.data, server->unexpected_packet.len);
650 goto next;
651 }
652 }
653}
654
655void ncp_tcp_rcv_proc(struct work_struct *work)
656{
657 struct ncp_server *server =
658 container_of(work, struct ncp_server, rcv.tq);
659
660 mutex_lock(&server->rcv.creq_mutex);
661 __ncptcp_rcv_proc(server);
662 mutex_unlock(&server->rcv.creq_mutex);
663}
664
665void ncp_tcp_tx_proc(struct work_struct *work)
666{
667 struct ncp_server *server =
668 container_of(work, struct ncp_server, tx.tq);
669
670 mutex_lock(&server->rcv.creq_mutex);
671 __ncptcp_try_send(server);
672 mutex_unlock(&server->rcv.creq_mutex);
673}
674
675static int do_ncp_rpc_call(struct ncp_server *server, int size,
676 unsigned char* reply_buf, int max_reply_size)
677{
678 int result;
679 struct ncp_request_reply *req;
680
681 req = ncp_alloc_req();
682 if (!req)
683 return -ENOMEM;
684
685 req->reply_buf = reply_buf;
686 req->datalen = max_reply_size;
687 req->tx_iov[1].iov_base = server->packet;
688 req->tx_iov[1].iov_len = size;
689 req->tx_type = *(u_int16_t*)server->packet;
690
691 result = ncp_add_request(server, req);
692 if (result < 0)
693 goto out;
694
695 if (wait_event_interruptible(req->wq, req->status == RQ_DONE)) {
696 ncp_abort_request(server, req, -EINTR);
697 result = -EINTR;
698 goto out;
699 }
700
701 result = req->result;
702
703out:
704 ncp_req_put(req);
705
706 return result;
707}
708
709/*
710 * We need the server to be locked here, so check!
711 */
712
713static int ncp_do_request(struct ncp_server *server, int size,
714 void* reply, int max_reply_size)
715{
716 int result;
717
718 if (server->lock == 0) {
719 pr_err("Server not locked!\n");
720 return -EIO;
721 }
722 if (!ncp_conn_valid(server)) {
723 return -EIO;
724 }
725 {
726 sigset_t old_set;
727 unsigned long mask, flags;
728
729 spin_lock_irqsave(&current->sighand->siglock, flags);
730 old_set = current->blocked;
731 if (current->flags & PF_EXITING)
732 mask = 0;
733 else
734 mask = sigmask(SIGKILL);
735 if (server->m.flags & NCP_MOUNT_INTR) {
736 /* FIXME: This doesn't seem right at all. So, like,
737 we can't handle SIGINT and get whatever to stop?
738 What if we've blocked it ourselves? What about
739 alarms? Why, in fact, are we mucking with the
740 sigmask at all? -- r~ */
741 if (current->sighand->action[SIGINT - 1].sa.sa_handler == SIG_DFL)
742 mask |= sigmask(SIGINT);
743 if (current->sighand->action[SIGQUIT - 1].sa.sa_handler == SIG_DFL)
744 mask |= sigmask(SIGQUIT);
745 }
746 siginitsetinv(&current->blocked, mask);
747 recalc_sigpending();
748 spin_unlock_irqrestore(&current->sighand->siglock, flags);
749
750 result = do_ncp_rpc_call(server, size, reply, max_reply_size);
751
752 spin_lock_irqsave(&current->sighand->siglock, flags);
753 current->blocked = old_set;
754 recalc_sigpending();
755 spin_unlock_irqrestore(&current->sighand->siglock, flags);
756 }
757
758 ncp_dbg(2, "do_ncp_rpc_call returned %d\n", result);
759
760 return result;
761}
762
763/* ncp_do_request assures that at least a complete reply header is
764 * received. It assumes that server->current_size contains the ncp
765 * request size
766 */
767int ncp_request2(struct ncp_server *server, int function,
768 void* rpl, int size)
769{
770 struct ncp_request_header *h;
771 struct ncp_reply_header* reply = rpl;
772 int result;
773
774 h = (struct ncp_request_header *) (server->packet);
775 if (server->has_subfunction != 0) {
776 *(__u16 *) & (h->data[0]) = htons(server->current_size - sizeof(*h) - 2);
777 }
778 h->type = NCP_REQUEST;
779 /*
780 * The server shouldn't know or care what task is making a
781 * request, so we always use the same task number.
782 */
783 h->task = 2; /* (current->pid) & 0xff; */
784 h->function = function;
785
786 result = ncp_do_request(server, server->current_size, reply, size);
787 if (result < 0) {
788 ncp_dbg(1, "ncp_request_error: %d\n", result);
789 goto out;
790 }
791 server->completion = reply->completion_code;
792 server->conn_status = reply->connection_state;
793 server->reply_size = result;
794 server->ncp_reply_size = result - sizeof(struct ncp_reply_header);
795
796 result = reply->completion_code;
797
798 if (result != 0)
799 ncp_vdbg("completion code=%x\n", result);
800out:
801 return result;
802}
803
804int ncp_connect(struct ncp_server *server)
805{
806 struct ncp_request_header *h;
807 int result;
808
809 server->connection = 0xFFFF;
810 server->sequence = 255;
811
812 h = (struct ncp_request_header *) (server->packet);
813 h->type = NCP_ALLOC_SLOT_REQUEST;
814 h->task = 2; /* see above */
815 h->function = 0;
816
817 result = ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
818 if (result < 0)
819 goto out;
820 server->connection = h->conn_low + (h->conn_high * 256);
821 result = 0;
822out:
823 return result;
824}
825
826int ncp_disconnect(struct ncp_server *server)
827{
828 struct ncp_request_header *h;
829
830 h = (struct ncp_request_header *) (server->packet);
831 h->type = NCP_DEALLOC_SLOT_REQUEST;
832 h->task = 2; /* see above */
833 h->function = 0;
834
835 return ncp_do_request(server, sizeof(*h), server->packet, server->packet_size);
836}
837
838void ncp_lock_server(struct ncp_server *server)
839{
840 mutex_lock(&server->mutex);
841 if (server->lock)
842 pr_warn("%s: was locked!\n", __func__);
843 server->lock = 1;
844}
845
846void ncp_unlock_server(struct ncp_server *server)
847{
848 if (!server->lock) {
849 pr_warn("%s: was not locked!\n", __func__);
850 return;
851 }
852 server->lock = 0;
853 mutex_unlock(&server->mutex);
854}
diff --git a/fs/ncpfs/symlink.c b/fs/ncpfs/symlink.c
deleted file mode 100644
index b6e16da4837a..000000000000
--- a/fs/ncpfs/symlink.c
+++ /dev/null
@@ -1,182 +0,0 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * linux/fs/ncpfs/symlink.c
4 *
5 * Code for allowing symbolic links on NCPFS (i.e. NetWare)
6 * Symbolic links are not supported on native NetWare, so we use an
7 * infrequently-used flag (Sh) and store a two-word magic header in
8 * the file to make sure we don't accidentally use a non-link file
9 * as a link.
10 *
11 * When using the NFS namespace, we set the mode to indicate a symlink and
12 * don't bother with the magic numbers.
13 *
14 * from linux/fs/ext2/symlink.c
15 *
16 * Copyright (C) 1998-99, Frank A. Vorstenbosch
17 *
18 * ncpfs symlink handling code
19 * NLS support (c) 1999 Petr Vandrovec
20 * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
21 *
22 */
23
24
25#include <linux/uaccess.h>
26
27#include <linux/errno.h>
28#include <linux/fs.h>
29#include <linux/time.h>
30#include <linux/slab.h>
31#include <linux/mm.h>
32#include <linux/stat.h>
33#include "ncp_fs.h"
34
35/* these magic numbers must appear in the symlink file -- this makes it a bit
36 more resilient against the magic attributes being set on random files. */
37
38#define NCP_SYMLINK_MAGIC0 cpu_to_le32(0x6c6d7973) /* "symlnk->" */
39#define NCP_SYMLINK_MAGIC1 cpu_to_le32(0x3e2d6b6e)
40
41/* ----- read a symbolic link ------------------------------------------ */
42
43static int ncp_symlink_readpage(struct file *file, struct page *page)
44{
45 struct inode *inode = page->mapping->host;
46 int error, length, len;
47 char *link, *rawlink;
48 char *buf = kmap(page);
49
50 error = -ENOMEM;
51 rawlink = kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
52 if (!rawlink)
53 goto fail;
54
55 if (ncp_make_open(inode,O_RDONLY))
56 goto failEIO;
57
58 error=ncp_read_kernel(NCP_SERVER(inode),NCP_FINFO(inode)->file_handle,
59 0,NCP_MAX_SYMLINK_SIZE,rawlink,&length);
60
61 ncp_inode_close(inode);
62 /* Close file handle if no other users... */
63 ncp_make_closed(inode);
64 if (error)
65 goto failEIO;
66
67 if (NCP_FINFO(inode)->flags & NCPI_KLUDGE_SYMLINK) {
68 if (length<NCP_MIN_SYMLINK_SIZE ||
69 ((__le32 *)rawlink)[0]!=NCP_SYMLINK_MAGIC0 ||
70 ((__le32 *)rawlink)[1]!=NCP_SYMLINK_MAGIC1)
71 goto failEIO;
72 link = rawlink + 8;
73 length -= 8;
74 } else {
75 link = rawlink;
76 }
77
78 len = NCP_MAX_SYMLINK_SIZE;
79 error = ncp_vol2io(NCP_SERVER(inode), buf, &len, link, length, 0);
80 kfree(rawlink);
81 if (error)
82 goto fail;
83 SetPageUptodate(page);
84 kunmap(page);
85 unlock_page(page);
86 return 0;
87
88failEIO:
89 error = -EIO;
90 kfree(rawlink);
91fail:
92 SetPageError(page);
93 kunmap(page);
94 unlock_page(page);
95 return error;
96}
97
98/*
99 * symlinks can't do much...
100 */
101const struct address_space_operations ncp_symlink_aops = {
102 .readpage = ncp_symlink_readpage,
103};
104
105/* ----- create a new symbolic link -------------------------------------- */
106
107int ncp_symlink(struct inode *dir, struct dentry *dentry, const char *symname) {
108 struct inode *inode;
109 char *rawlink;
110 int length, err, i, outlen;
111 int kludge;
112 umode_t mode;
113 __le32 attr;
114 unsigned int hdr;
115
116 ncp_dbg(1, "dir=%p, dentry=%p, symname=%s\n", dir, dentry, symname);
117
118 if (ncp_is_nfs_extras(NCP_SERVER(dir), NCP_FINFO(dir)->volNumber))
119 kludge = 0;
120 else
121#ifdef CONFIG_NCPFS_EXTRAS
122 if (NCP_SERVER(dir)->m.flags & NCP_MOUNT_SYMLINKS)
123 kludge = 1;
124 else
125#endif
126 /* EPERM is returned by VFS if symlink procedure does not exist */
127 return -EPERM;
128
129 rawlink = kmalloc(NCP_MAX_SYMLINK_SIZE, GFP_KERNEL);
130 if (!rawlink)
131 return -ENOMEM;
132
133 if (kludge) {
134 mode = 0;
135 attr = aSHARED | aHIDDEN;
136 ((__le32 *)rawlink)[0]=NCP_SYMLINK_MAGIC0;
137 ((__le32 *)rawlink)[1]=NCP_SYMLINK_MAGIC1;
138 hdr = 8;
139 } else {
140 mode = S_IFLNK | S_IRWXUGO;
141 attr = 0;
142 hdr = 0;
143 }
144
145 length = strlen(symname);
146 /* map to/from server charset, do not touch upper/lower case as
147 symlink can point out of ncp filesystem */
148 outlen = NCP_MAX_SYMLINK_SIZE - hdr;
149 err = ncp_io2vol(NCP_SERVER(dir), rawlink + hdr, &outlen, symname, length, 0);
150 if (err)
151 goto failfree;
152
153 outlen += hdr;
154
155 err = -EIO;
156 if (ncp_create_new(dir,dentry,mode,0,attr)) {
157 goto failfree;
158 }
159
160 inode=d_inode(dentry);
161
162 if (ncp_make_open(inode, O_WRONLY))
163 goto failfree;
164
165 if (ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
166 0, outlen, rawlink, &i) || i!=outlen) {
167 goto fail;
168 }
169
170 ncp_inode_close(inode);
171 ncp_make_closed(inode);
172 kfree(rawlink);
173 return 0;
174fail:;
175 ncp_inode_close(inode);
176 ncp_make_closed(inode);
177failfree:;
178 kfree(rawlink);
179 return err;
180}
181
182/* ----- EOF ----- */