Merge with Linux 2.4.0-test5-pre3.
[linux-2.6/linux-mips.git] / fs / ncpfs / ncplib_kernel.c
blob9272822a4f5eea5c681a0a01896da4c6a98b1df6
1 /*
2 * ncplib_kernel.c
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 1999 Wolfram Pienkoss for NLS
9 */
12 #include <linux/config.h>
14 #include "ncplib_kernel.h"
16 static inline int min(int a, int b)
18 return a < b ? a : b;
21 static inline void assert_server_locked(struct ncp_server *server)
23 if (server->lock == 0) {
24 DPRINTK("ncpfs: server not locked!\n");
28 static void ncp_add_byte(struct ncp_server *server, __u8 x)
30 assert_server_locked(server);
31 *(__u8 *) (&(server->packet[server->current_size])) = x;
32 server->current_size += 1;
33 return;
36 static void ncp_add_word(struct ncp_server *server, __u16 x)
38 assert_server_locked(server);
39 put_unaligned(x, (__u16 *) (&(server->packet[server->current_size])));
40 server->current_size += 2;
41 return;
44 static void ncp_add_dword(struct ncp_server *server, __u32 x)
46 assert_server_locked(server);
47 put_unaligned(x, (__u32 *) (&(server->packet[server->current_size])));
48 server->current_size += 4;
49 return;
52 static void ncp_add_mem(struct ncp_server *server, const void *source, int size)
54 assert_server_locked(server);
55 memcpy(&(server->packet[server->current_size]), source, size);
56 server->current_size += size;
57 return;
60 static void ncp_add_mem_fromfs(struct ncp_server *server, const char *source, int size)
62 assert_server_locked(server);
63 copy_from_user(&(server->packet[server->current_size]), source, size);
64 server->current_size += size;
65 return;
68 static void ncp_add_pstring(struct ncp_server *server, const char *s)
70 int len = strlen(s);
71 assert_server_locked(server);
72 if (len > 255) {
73 DPRINTK("ncpfs: string too long: %s\n", s);
74 len = 255;
76 ncp_add_byte(server, len);
77 ncp_add_mem(server, s, len);
78 return;
81 static inline void ncp_init_request(struct ncp_server *server)
83 ncp_lock_server(server);
85 server->current_size = sizeof(struct ncp_request_header);
86 server->has_subfunction = 0;
89 static inline void ncp_init_request_s(struct ncp_server *server, int subfunction)
91 ncp_lock_server(server);
93 server->current_size = sizeof(struct ncp_request_header) + 2;
94 ncp_add_byte(server, subfunction);
96 server->has_subfunction = 1;
99 static inline char *
100 ncp_reply_data(struct ncp_server *server, int offset)
102 return &(server->packet[sizeof(struct ncp_reply_header) + offset]);
105 static __u8
106 ncp_reply_byte(struct ncp_server *server, int offset)
108 return get_unaligned((__u8 *) ncp_reply_data(server, offset));
111 static __u16
112 ncp_reply_word(struct ncp_server *server, int offset)
114 return get_unaligned((__u16 *) ncp_reply_data(server, offset));
117 static __u32
118 ncp_reply_dword(struct ncp_server *server, int offset)
120 return get_unaligned((__u32 *) ncp_reply_data(server, offset));
124 ncp_negotiate_buffersize(struct ncp_server *server, int size, int *target)
126 int result;
128 ncp_init_request(server);
129 ncp_add_word(server, htons(size));
131 if ((result = ncp_request(server, 33)) != 0) {
132 ncp_unlock_server(server);
133 return result;
135 *target = min(ntohs(ncp_reply_word(server, 0)), size);
137 ncp_unlock_server(server);
138 return 0;
142 /* options:
143 * bit 0 ipx checksum
144 * bit 1 packet signing
147 ncp_negotiate_size_and_options(struct ncp_server *server,
148 int size, int options, int *ret_size, int *ret_options) {
149 int result;
151 /* there is minimum */
152 if (size < NCP_BLOCK_SIZE) size = NCP_BLOCK_SIZE;
154 ncp_init_request(server);
155 ncp_add_word(server, htons(size));
156 ncp_add_byte(server, options);
158 if ((result = ncp_request(server, 0x61)) != 0)
160 ncp_unlock_server(server);
161 return result;
164 /* NCP over UDP returns 0 (!!!) */
165 result = ntohs(ncp_reply_word(server, 0));
166 if (result >= NCP_BLOCK_SIZE) size=min(result, size);
167 *ret_size = size;
168 *ret_options = ncp_reply_byte(server, 4);
170 ncp_unlock_server(server);
171 return 0;
175 ncp_get_volume_info_with_number(struct ncp_server *server, int n,
176 struct ncp_volume_info *target)
178 int result;
179 int len;
181 ncp_init_request_s(server, 44);
182 ncp_add_byte(server, n);
184 if ((result = ncp_request(server, 22)) != 0) {
185 goto out;
187 target->total_blocks = ncp_reply_dword(server, 0);
188 target->free_blocks = ncp_reply_dword(server, 4);
189 target->purgeable_blocks = ncp_reply_dword(server, 8);
190 target->not_yet_purgeable_blocks = ncp_reply_dword(server, 12);
191 target->total_dir_entries = ncp_reply_dword(server, 16);
192 target->available_dir_entries = ncp_reply_dword(server, 20);
193 target->sectors_per_block = ncp_reply_byte(server, 28);
195 memset(&(target->volume_name), 0, sizeof(target->volume_name));
197 result = -EIO;
198 len = ncp_reply_byte(server, 29);
199 if (len > NCP_VOLNAME_LEN) {
200 DPRINTK("ncpfs: volume name too long: %d\n", len);
201 goto out;
203 memcpy(&(target->volume_name), ncp_reply_data(server, 30), len);
204 result = 0;
205 out:
206 ncp_unlock_server(server);
207 return result;
211 ncp_close_file(struct ncp_server *server, const char *file_id)
213 int result;
215 ncp_init_request(server);
216 ncp_add_byte(server, 0);
217 ncp_add_mem(server, file_id, 6);
219 result = ncp_request(server, 66);
220 ncp_unlock_server(server);
221 return result;
225 ncp_make_closed(struct inode *inode)
227 int err;
229 err = 0;
230 down(&NCP_FINFO(inode)->open_sem);
231 if (atomic_read(&NCP_FINFO(inode)->opened) == 1) {
232 atomic_set(&NCP_FINFO(inode)->opened, 0);
233 err = ncp_close_file(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle);
235 if (!err)
236 PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n",
237 NCP_FINFO(inode)->volNumber,
238 NCP_FINFO(inode)->dirEntNum, err);
240 up(&NCP_FINFO(inode)->open_sem);
241 return err;
244 static void ncp_add_handle_path(struct ncp_server *server, __u8 vol_num,
245 __u32 dir_base, int have_dir_base,
246 const char *path)
248 ncp_add_byte(server, vol_num);
249 ncp_add_dword(server, dir_base);
250 if (have_dir_base != 0) {
251 ncp_add_byte(server, 1); /* dir_base */
252 } else {
253 ncp_add_byte(server, 0xff); /* no handle */
255 if (path != NULL) {
256 ncp_add_byte(server, 1); /* 1 component */
257 ncp_add_pstring(server, path);
258 } else {
259 ncp_add_byte(server, 0);
263 static void ncp_extract_file_info(void *structure, struct nw_info_struct *target)
265 __u8 *name_len;
266 const int info_struct_size = sizeof(struct nw_info_struct) - 257;
268 memcpy(target, structure, info_struct_size);
269 name_len = structure + info_struct_size;
270 target->nameLen = *name_len;
271 memcpy(target->entryName, name_len + 1, *name_len);
272 target->entryName[*name_len] = '\0';
273 return;
277 * Returns information for a (one-component) name relative to
278 * the specified directory.
280 int ncp_obtain_info(struct ncp_server *server, struct inode *dir, char *path,
281 struct nw_info_struct *target)
283 __u8 volnum = NCP_FINFO(dir)->volNumber;
284 __u32 dirent = NCP_FINFO(dir)->dirEntNum;
285 int result;
287 if (target == NULL) {
288 printk(KERN_ERR "ncp_obtain_info: invalid call\n");
289 return -EINVAL;
291 ncp_init_request(server);
292 ncp_add_byte(server, 6); /* subfunction */
293 ncp_add_byte(server, server->name_space[volnum]);
294 ncp_add_byte(server, server->name_space[volnum]); /* N.B. twice ?? */
295 ncp_add_word(server, htons(0x0680)); /* get all */
296 ncp_add_dword(server, RIM_ALL);
297 ncp_add_handle_path(server, volnum, dirent, 1, path);
299 if ((result = ncp_request(server, 87)) != 0)
300 goto out;
301 ncp_extract_file_info(ncp_reply_data(server, 0), target);
303 out:
304 ncp_unlock_server(server);
305 return result;
308 #ifdef CONFIG_NCPFS_NFS_NS
309 static int
310 ncp_obtain_DOS_dir_base(struct ncp_server *server,
311 __u8 volnum, __u32 dirent,
312 char *path, /* At most 1 component */
313 __u32 *DOS_dir_base)
315 int result;
317 ncp_init_request(server);
318 ncp_add_byte(server, 6); /* subfunction */
319 ncp_add_byte(server, server->name_space[volnum]);
320 ncp_add_byte(server, server->name_space[volnum]);
321 ncp_add_word(server, htons(0x0680)); /* get all */
322 ncp_add_dword(server, RIM_DIRECTORY);
323 ncp_add_handle_path(server, volnum, dirent, 1, path);
325 if ((result = ncp_request(server, 87)) == 0)
327 if (DOS_dir_base) *DOS_dir_base=ncp_reply_dword(server, 0x34);
329 ncp_unlock_server(server);
330 return result;
332 #endif /* CONFIG_NCPFS_NFS_NS */
334 static inline int
335 ncp_get_known_namespace(struct ncp_server *server, __u8 volume)
337 #if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS)
338 int result;
339 __u8 *namespace;
340 __u16 no_namespaces;
342 ncp_init_request(server);
343 ncp_add_byte(server, 24); /* Subfunction: Get Name Spaces Loaded */
344 ncp_add_word(server, 0);
345 ncp_add_byte(server, volume);
347 if ((result = ncp_request(server, 87)) != 0) {
348 ncp_unlock_server(server);
349 return NW_NS_DOS; /* not result ?? */
352 result = NW_NS_DOS;
353 no_namespaces = ncp_reply_word(server, 0);
354 namespace = ncp_reply_data(server, 2);
356 while (no_namespaces > 0) {
357 DPRINTK("get_namespaces: found %d on %d\n", *namespace, volume);
359 #ifdef CONFIG_NCPFS_NFS_NS
360 if ((*namespace == NW_NS_NFS) && !(server->m.flags&NCP_MOUNT_NO_NFS))
362 result = NW_NS_NFS;
363 break;
365 #endif /* CONFIG_NCPFS_NFS_NS */
366 #ifdef CONFIG_NCPFS_OS2_NS
367 if ((*namespace == NW_NS_OS2) && !(server->m.flags&NCP_MOUNT_NO_OS2))
369 result = NW_NS_OS2;
371 #endif /* CONFIG_NCPFS_OS2_NS */
372 namespace += 1;
373 no_namespaces -= 1;
375 ncp_unlock_server(server);
376 return result;
377 #else /* neither OS2 nor NFS - only DOS */
378 return NW_NS_DOS;
379 #endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */
382 static int
383 ncp_ObtainSpecificDirBase(struct ncp_server *server,
384 __u8 nsSrc, __u8 nsDst, __u8 vol_num, __u32 dir_base,
385 char *path, /* At most 1 component */
386 __u32 *dirEntNum, __u32 *DosDirNum)
388 int result;
390 ncp_init_request(server);
391 ncp_add_byte(server, 6); /* subfunction */
392 ncp_add_byte(server, nsSrc);
393 ncp_add_byte(server, nsDst);
394 ncp_add_word(server, htons(0x0680)); /* get all */
395 ncp_add_dword(server, RIM_ALL);
396 ncp_add_handle_path(server, vol_num, dir_base, 1, path);
398 if ((result = ncp_request(server, 87)) != 0)
400 ncp_unlock_server(server);
401 return result;
404 if (dirEntNum)
405 *dirEntNum = ncp_reply_dword(server, 0x30);
406 if (DosDirNum)
407 *DosDirNum = ncp_reply_dword(server, 0x34);
408 ncp_unlock_server(server);
409 return 0;
413 ncp_mount_subdir(struct ncp_server *server, struct nw_info_struct *i,
414 __u8 volNumber, __u8 srcNS, __u32 dirEntNum)
416 int dstNS;
417 int result;
418 __u32 newDirEnt;
419 __u32 newDosEnt;
421 dstNS = ncp_get_known_namespace(server, volNumber);
422 if ((result = ncp_ObtainSpecificDirBase(server, srcNS, dstNS, volNumber,
423 dirEntNum, NULL, &newDirEnt, &newDosEnt)) != 0)
425 return result;
427 server->name_space[volNumber] = dstNS;
428 i->volNumber = volNumber;
429 i->dirEntNum = newDirEnt;
430 i->DosDirNum = newDosEnt;
431 server->m.mounted_vol[1] = 0;
432 server->m.mounted_vol[0] = 'X';
433 return 0;
436 int
437 ncp_lookup_volume(struct ncp_server *server, char *volname,
438 struct nw_info_struct *target)
440 int result;
441 int volnum;
443 DPRINTK("ncp_lookup_volume: looking up vol %s\n", volname);
445 ncp_init_request(server);
446 ncp_add_byte(server, 22); /* Subfunction: Generate dir handle */
447 ncp_add_byte(server, 0); /* DOS namespace */
448 ncp_add_byte(server, 0); /* reserved */
449 ncp_add_byte(server, 0); /* reserved */
450 ncp_add_byte(server, 0); /* reserved */
452 ncp_add_byte(server, 0); /* faked volume number */
453 ncp_add_dword(server, 0); /* faked dir_base */
454 ncp_add_byte(server, 0xff); /* Don't have a dir_base */
455 ncp_add_byte(server, 1); /* 1 path component */
456 ncp_add_pstring(server, volname);
458 if ((result = ncp_request(server, 87)) != 0) {
459 ncp_unlock_server(server);
460 return result;
462 memset(target, 0, sizeof(*target));
463 target->DosDirNum = target->dirEntNum = ncp_reply_dword(server, 4);
464 target->volNumber = volnum = ncp_reply_byte(server, 8);
465 ncp_unlock_server(server);
467 server->name_space[volnum] = ncp_get_known_namespace(server, volnum);
469 DPRINTK("lookup_vol: namespace[%d] = %d\n",
470 volnum, server->name_space[volnum]);
472 target->nameLen = strlen(volname);
473 memcpy(target->entryName, volname, target->nameLen+1);
474 target->attributes = aDIR;
475 /* set dates to Jan 1, 1986 00:00 */
476 target->creationTime = target->modifyTime = cpu_to_le16(0x0000);
477 target->creationDate = target->modifyDate = target->lastAccessDate = cpu_to_le16(0x0C21);
478 return 0;
481 int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *server,
482 struct inode *dir,
483 const char *path,
484 __u32 info_mask,
485 const struct nw_modify_dos_info *info)
487 __u8 volnum = NCP_FINFO(dir)->volNumber;
488 __u32 dirent = NCP_FINFO(dir)->dirEntNum;
489 int result;
491 ncp_init_request(server);
492 ncp_add_byte(server, 7); /* subfunction */
493 ncp_add_byte(server, server->name_space[volnum]);
494 ncp_add_byte(server, 0); /* reserved */
495 ncp_add_word(server, htons(0x0680)); /* search attribs: all */
497 ncp_add_dword(server, info_mask);
498 ncp_add_mem(server, info, sizeof(*info));
499 ncp_add_handle_path(server, volnum, dirent, 1, path);
501 result = ncp_request(server, 87);
502 ncp_unlock_server(server);
503 return result;
506 int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server,
507 struct inode *dir,
508 __u32 info_mask,
509 const struct nw_modify_dos_info *info)
511 return ncp_modify_file_or_subdir_dos_info_path(server, dir, NULL,
512 info_mask, info);
515 static int
516 ncp_DeleteNSEntry(struct ncp_server *server,
517 __u8 have_dir_base, __u8 volnum, __u32 dirent,
518 char* name, __u8 ns, int attr)
520 int result;
522 ncp_init_request(server);
523 ncp_add_byte(server, 8); /* subfunction */
524 ncp_add_byte(server, ns);
525 ncp_add_byte(server, 0); /* reserved */
526 ncp_add_word(server, attr); /* search attribs: all */
527 ncp_add_handle_path(server, volnum, dirent, have_dir_base, name);
529 result = ncp_request(server, 87);
530 ncp_unlock_server(server);
531 return result;
535 ncp_del_file_or_subdir2(struct ncp_server *server,
536 struct dentry *dentry)
538 struct inode *inode = dentry->d_inode;
539 __u8 volnum;
540 __u32 dirent;
542 if (!inode) {
543 #if CONFIG_NCPFS_DEBUGDENTRY
544 PRINTK("ncpfs: ncpdel2: dentry->d_inode == NULL\n");
545 #endif
546 return 0xFF; /* Any error */
548 volnum = NCP_FINFO(inode)->volNumber;
549 dirent = NCP_FINFO(inode)->DosDirNum;
550 return ncp_DeleteNSEntry(server, 1, volnum, dirent, NULL, NW_NS_DOS, htons(0x0680));
554 ncp_del_file_or_subdir(struct ncp_server *server,
555 struct inode *dir, char *name)
557 __u8 volnum = NCP_FINFO(dir)->volNumber;
558 __u32 dirent = NCP_FINFO(dir)->dirEntNum;
560 #ifdef CONFIG_NCPFS_NFS_NS
561 if (server->name_space[volnum]==NW_NS_NFS)
563 int result;
565 result=ncp_obtain_DOS_dir_base(server, volnum, dirent, name, &dirent);
566 if (result) return result;
567 return ncp_DeleteNSEntry(server, 1, volnum, dirent, NULL, NW_NS_DOS, htons(0x0680));
569 else
570 #endif /* CONFIG_NCPFS_NFS_NS */
571 return ncp_DeleteNSEntry(server, 1, volnum, dirent, name, server->name_space[volnum], htons(0x0680));
574 static inline void ConvertToNWfromDWORD(__u32 sfd, __u8 ret[6])
576 __u16 *dest = (__u16 *) ret;
577 memcpy(ret + 2, &sfd, 4);
578 dest[0] = cpu_to_le16((le16_to_cpu(dest[1]) + le16_to_cpu(1)));
579 return;
582 /* If both dir and name are NULL, then in target there's already a
583 looked-up entry that wants to be opened. */
584 int ncp_open_create_file_or_subdir(struct ncp_server *server,
585 struct inode *dir, char *name,
586 int open_create_mode,
587 __u32 create_attributes,
588 int desired_acc_rights,
589 struct ncp_entry_info *target)
591 __u16 search_attribs = ntohs(0x0600);
592 __u8 volnum = target->i.volNumber;
593 __u32 dirent = target->i.dirEntNum;
594 int result;
596 if (dir)
598 volnum = NCP_FINFO(dir)->volNumber;
599 dirent = NCP_FINFO(dir)->dirEntNum;
602 if ((create_attributes & aDIR) != 0) {
603 search_attribs |= ntohs(0x0080);
605 ncp_init_request(server);
606 ncp_add_byte(server, 1); /* subfunction */
607 ncp_add_byte(server, server->name_space[volnum]);
608 ncp_add_byte(server, open_create_mode);
609 ncp_add_word(server, search_attribs);
610 ncp_add_dword(server, RIM_ALL);
611 ncp_add_dword(server, create_attributes);
612 /* The desired acc rights seem to be the inherited rights mask
613 for directories */
614 ncp_add_word(server, desired_acc_rights);
615 ncp_add_handle_path(server, volnum, dirent, 1, name);
617 if ((result = ncp_request(server, 87)) != 0)
618 goto out;
619 if (!(create_attributes & aDIR))
620 target->opened = 1;
621 target->server_file_handle = ncp_reply_dword(server, 0);
622 target->open_create_action = ncp_reply_byte(server, 4);
624 /* in target there's a new finfo to fill */
625 ncp_extract_file_info(ncp_reply_data(server, 6), &(target->i));
626 ConvertToNWfromDWORD(target->server_file_handle, target->file_handle);
628 out:
629 ncp_unlock_server(server);
630 return result;
634 ncp_initialize_search(struct ncp_server *server, struct inode *dir,
635 struct nw_search_sequence *target)
637 __u8 volnum = NCP_FINFO(dir)->volNumber;
638 __u32 dirent = NCP_FINFO(dir)->dirEntNum;
639 int result;
641 ncp_init_request(server);
642 ncp_add_byte(server, 2); /* subfunction */
643 ncp_add_byte(server, server->name_space[volnum]);
644 ncp_add_byte(server, 0); /* reserved */
645 ncp_add_handle_path(server, volnum, dirent, 1, NULL);
647 result = ncp_request(server, 87);
648 if (result)
649 goto out;
650 memcpy(target, ncp_reply_data(server, 0), sizeof(*target));
652 out:
653 ncp_unlock_server(server);
654 return result;
657 /* Search for everything */
658 int ncp_search_for_file_or_subdir(struct ncp_server *server,
659 struct nw_search_sequence *seq,
660 struct nw_info_struct *target)
662 int result;
664 ncp_init_request(server);
665 ncp_add_byte(server, 3); /* subfunction */
666 ncp_add_byte(server, server->name_space[seq->volNumber]);
667 ncp_add_byte(server, 0); /* data stream (???) */
668 ncp_add_word(server, htons(0x0680)); /* Search attribs */
669 ncp_add_dword(server, RIM_ALL); /* return info mask */
670 ncp_add_mem(server, seq, 9);
671 #ifdef CONFIG_NCPFS_NFS_NS
672 if (server->name_space[seq->volNumber] == NW_NS_NFS) {
673 ncp_add_byte(server, 0); /* 0 byte pattern */
674 } else
675 #endif
677 ncp_add_byte(server, 2); /* 2 byte pattern */
678 ncp_add_byte(server, 0xff); /* following is a wildcard */
679 ncp_add_byte(server, '*');
682 if ((result = ncp_request(server, 87)) != 0)
683 goto out;
684 memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq));
685 ncp_extract_file_info(ncp_reply_data(server, 10), target);
687 out:
688 ncp_unlock_server(server);
689 return result;
693 ncp_RenameNSEntry(struct ncp_server *server,
694 struct inode *old_dir, char *old_name, int old_type,
695 struct inode *new_dir, char *new_name)
697 int result = -EINVAL;
699 if ((old_dir == NULL) || (old_name == NULL) ||
700 (new_dir == NULL) || (new_name == NULL))
701 goto out;
703 ncp_init_request(server);
704 ncp_add_byte(server, 4); /* subfunction */
705 ncp_add_byte(server, server->name_space[NCP_FINFO(old_dir)->volNumber]);
706 ncp_add_byte(server, 1); /* rename flag */
707 ncp_add_word(server, old_type); /* search attributes */
709 /* source Handle Path */
710 ncp_add_byte(server, NCP_FINFO(old_dir)->volNumber);
711 ncp_add_dword(server, NCP_FINFO(old_dir)->dirEntNum);
712 ncp_add_byte(server, 1);
713 ncp_add_byte(server, 1); /* 1 source component */
715 /* dest Handle Path */
716 ncp_add_byte(server, NCP_FINFO(new_dir)->volNumber);
717 ncp_add_dword(server, NCP_FINFO(new_dir)->dirEntNum);
718 ncp_add_byte(server, 1);
719 ncp_add_byte(server, 1); /* 1 destination component */
721 /* source path string */
722 ncp_add_pstring(server, old_name);
723 /* dest path string */
724 ncp_add_pstring(server, new_name);
726 result = ncp_request(server, 87);
727 ncp_unlock_server(server);
728 out:
729 return result;
732 int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server,
733 struct inode *old_dir, char *old_name,
734 struct inode *new_dir, char *new_name)
736 int result;
737 int old_type = htons(0x0600);
739 /* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */
740 result = ncp_RenameNSEntry(server, old_dir, old_name, old_type,
741 new_dir, new_name);
742 if (result == 0xFF) /* File Not Found, try directory */
744 old_type = htons(0x1600);
745 result = ncp_RenameNSEntry(server, old_dir, old_name, old_type,
746 new_dir, new_name);
748 if (result != 0x92) return result; /* All except NO_FILES_RENAMED */
749 result = ncp_del_file_or_subdir(server, new_dir, new_name);
750 if (result != 0) return -EACCES;
751 result = ncp_RenameNSEntry(server, old_dir, old_name, old_type,
752 new_dir, new_name);
753 return result;
757 /* We have to transfer to/from user space */
759 ncp_read_kernel(struct ncp_server *server, const char *file_id,
760 __u32 offset, __u16 to_read, char *target, int *bytes_read)
762 char *source;
763 int result;
765 ncp_init_request(server);
766 ncp_add_byte(server, 0);
767 ncp_add_mem(server, file_id, 6);
768 ncp_add_dword(server, htonl(offset));
769 ncp_add_word(server, htons(to_read));
771 if ((result = ncp_request(server, 72)) != 0) {
772 goto out;
774 *bytes_read = ntohs(ncp_reply_word(server, 0));
775 source = ncp_reply_data(server, 2 + (offset & 1));
777 memcpy(target, source, *bytes_read);
778 out:
779 ncp_unlock_server(server);
780 return result;
783 /* There is a problem... egrep and some other silly tools do:
784 x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768);
785 read(<ncpfs fd>, x, 32768);
786 Now copying read result by copy_to_user causes pagefault. This pagefault
787 could not be handled because of server was locked due to read. So we have
788 to use temporary buffer. So ncp_unlock_server must be done before
789 copy_to_user (and for write, copy_from_user must be done before
790 ncp_init_request... same applies for send raw packet ioctl). Because of
791 file is normally read in bigger chunks, caller provides kmalloced
792 (vmalloced) chunk of memory with size >= to_read...
795 ncp_read_bounce(struct ncp_server *server, const char *file_id,
796 __u32 offset, __u16 to_read, char *target, int *bytes_read,
797 void* bounce, __u32 bufsize)
799 int result;
801 ncp_init_request(server);
802 ncp_add_byte(server, 0);
803 ncp_add_mem(server, file_id, 6);
804 ncp_add_dword(server, htonl(offset));
805 ncp_add_word(server, htons(to_read));
806 result = ncp_request2(server, 72, bounce, bufsize);
807 ncp_unlock_server(server);
808 if (!result) {
809 int len = be16_to_cpu(get_unaligned((__u16*)((char*)bounce +
810 sizeof(struct ncp_reply_header))));
811 result = -EIO;
812 if (len <= to_read) {
813 char* source;
815 source = (char*)bounce +
816 sizeof(struct ncp_reply_header) + 2 +
817 (offset & 1);
818 *bytes_read = len;
819 result = 0;
820 if (copy_to_user(target, source, len))
821 result = -EFAULT;
824 return result;
828 ncp_write_kernel(struct ncp_server *server, const char *file_id,
829 __u32 offset, __u16 to_write,
830 const char *source, int *bytes_written)
832 int result;
834 ncp_init_request(server);
835 ncp_add_byte(server, 0);
836 ncp_add_mem(server, file_id, 6);
837 ncp_add_dword(server, htonl(offset));
838 ncp_add_word(server, htons(to_write));
839 ncp_add_mem(server, source, to_write);
841 if ((result = ncp_request(server, 73)) == 0)
842 *bytes_written = to_write;
843 ncp_unlock_server(server);
844 return result;
847 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
849 ncp_LogPhysicalRecord(struct ncp_server *server, const char *file_id,
850 __u8 locktype, __u32 offset, __u32 length, __u16 timeout)
852 int result;
854 ncp_init_request(server);
855 ncp_add_byte(server, locktype);
856 ncp_add_mem(server, file_id, 6);
857 ncp_add_dword(server, htonl(offset));
858 ncp_add_dword(server, htonl(length));
859 ncp_add_word(server, htons(timeout));
861 if ((result = ncp_request(server, 0x1A)) != 0)
863 ncp_unlock_server(server);
864 return result;
866 ncp_unlock_server(server);
867 return 0;
871 ncp_ClearPhysicalRecord(struct ncp_server *server, const char *file_id,
872 __u32 offset, __u32 length)
874 int result;
876 ncp_init_request(server);
877 ncp_add_byte(server, 0); /* who knows... lanalyzer says that */
878 ncp_add_mem(server, file_id, 6);
879 ncp_add_dword(server, htonl(offset));
880 ncp_add_dword(server, htonl(length));
882 if ((result = ncp_request(server, 0x1E)) != 0)
884 ncp_unlock_server(server);
885 return result;
887 ncp_unlock_server(server);
888 return 0;
890 #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
892 #ifdef CONFIG_NCPFS_NLS
893 /* This are the NLS conversion routines with inspirations and code parts
894 * from the vfat file system and hints from Petr Vandrovec.
897 inline unsigned char
898 ncp__tolower(struct nls_table *t, unsigned char c)
900 unsigned char nc = t->charset2lower[c];
902 return nc ? nc : c;
905 inline unsigned char
906 ncp__toupper(struct nls_table *t, unsigned char c)
908 unsigned char nc = t->charset2upper[c];
910 return nc ? nc : c;
914 ncp__io2vol(struct ncp_server *server, unsigned char *vname, unsigned int *vlen,
915 const unsigned char *iname, unsigned int ilen, int cc)
917 struct nls_table *in = server->nls_io;
918 struct nls_table *out = server->nls_vol;
919 unsigned char *vname_start;
920 unsigned char *vname_end;
921 const unsigned char *iname_end;
923 iname_end = iname + ilen;
924 vname_start = vname;
925 vname_end = vname + *vlen - 1;
927 while (iname < iname_end) {
928 int chl;
929 wchar_t ec;
931 if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) {
932 int k;
934 k = utf8_mbtowc(&ec, iname, iname_end - iname);
935 if (k < 0)
936 return -EINVAL;
937 iname += k;
938 } else {
939 if (*iname == NCP_ESC) {
940 int k;
942 if (iname_end - iname < 5)
943 goto nospec;
945 ec = 0;
946 for (k = 1; k < 5; k++) {
947 unsigned char nc;
949 nc = iname[k] - '0';
950 if (nc >= 10) {
951 nc -= 'A' - '0' - 10;
952 if ((nc < 10) || (nc > 15)) {
953 goto nospec;
956 ec = (ec << 4) | nc;
958 iname += 5;
959 } else {
960 nospec:;
961 if ( (chl = in->char2uni(iname, iname_end - iname, &ec)) < 0)
962 return chl;
963 iname += chl;
967 /* unitoupper should be here! */
969 chl = out->uni2char(ec, vname, vname_end - vname);
970 if (chl < 0)
971 return chl;
973 /* this is wrong... */
974 if (cc) {
975 int chi;
977 for (chi = 0; chi < chl; chi++){
978 vname[chi] = ncp_toupper(out, vname[chi]);
981 vname += chl;
984 *vname = 0;
985 *vlen = vname - vname_start;
986 return 0;
990 ncp__vol2io(struct ncp_server *server, unsigned char *iname, unsigned int *ilen,
991 const unsigned char *vname, unsigned int vlen, int cc)
993 struct nls_table *in = server->nls_vol;
994 struct nls_table *out = server->nls_io;
995 const unsigned char *vname_end;
996 unsigned char *iname_start;
997 unsigned char *iname_end;
998 unsigned char *vname_cc;
999 int err;
1001 vname_cc = NULL;
1003 if (cc) {
1004 int i;
1006 /* this is wrong! */
1007 vname_cc = kmalloc(vlen, GFP_KERNEL);
1008 for (i = 0; i < vlen; i++)
1009 vname_cc[i] = ncp_tolower(in, vname[i]);
1010 vname = vname_cc;
1013 iname_start = iname;
1014 iname_end = iname + *ilen - 1;
1015 vname_end = vname + vlen;
1017 while (vname < vname_end) {
1018 wchar_t ec;
1019 int chl;
1021 if ( (chl = in->char2uni(vname, vname_end - vname, &ec)) < 0) {
1022 err = chl;
1023 goto quit;
1025 vname += chl;
1027 /* unitolower should be here! */
1029 if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) {
1030 int k;
1032 k = utf8_wctomb(iname, ec, iname_end - iname);
1033 if (k < 0) {
1034 err = -ENAMETOOLONG;
1035 goto quit;
1037 iname += k;
1038 } else {
1039 if ( (chl = out->uni2char(ec, iname, iname_end - iname)) >= 0) {
1040 iname += chl;
1041 } else {
1042 int k;
1044 if (iname_end - iname < 5) {
1045 err = -ENAMETOOLONG;
1046 goto quit;
1048 *iname = NCP_ESC;
1049 for (k = 4; k > 0; k--) {
1050 unsigned char v;
1052 v = (ec & 0xF) + '0';
1053 if (v > '9') {
1054 v += 'A' - '9' - 1;
1056 iname[k] = v;
1057 ec >>= 4;
1059 iname += 5;
1064 *iname = 0;
1065 *ilen = iname - iname_start;
1066 err = 0;
1067 quit:;
1068 if (cc)
1069 kfree(vname_cc);
1070 return err;
1073 #else
1076 ncp__io2vol(unsigned char *vname, unsigned int *vlen,
1077 const unsigned char *iname, unsigned int ilen, int cc)
1079 int i;
1081 if (*vlen <= ilen)
1082 return -ENAMETOOLONG;
1084 if (cc)
1085 for (i = 0; i < ilen; i++) {
1086 *vname = toupper(*iname);
1087 vname++;
1088 iname++;
1090 else {
1091 memmove(vname, iname, ilen);
1092 vname += ilen;
1095 *vlen = ilen;
1096 *vname = 0;
1097 return 0;
1101 ncp__vol2io(unsigned char *iname, unsigned int *ilen,
1102 const unsigned char *vname, unsigned int vlen, int cc)
1104 int i;
1106 if (*ilen <= vlen)
1107 return -ENAMETOOLONG;
1109 if (cc)
1110 for (i = 0; i < vlen; i++) {
1111 *iname = tolower(*vname);
1112 iname++;
1113 vname++;
1115 else {
1116 memmove(iname, vname, vlen);
1117 iname += vlen;
1120 *ilen = vlen;
1121 *iname = 0;
1122 return 0;
1125 #endif
1127 inline int
1128 ncp_strnicmp(struct nls_table *t, const unsigned char *s1,
1129 const unsigned char *s2, int n)
1131 int i;
1133 for (i=0; i<n; i++)
1134 if (ncp_tolower(t, s1[i]) != ncp_tolower(t, s2[i]))
1135 return 1;
1137 return 0;