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
12 #include <linux/config.h>
14 #include "ncplib_kernel.h"
16 static inline int min(int a
, int 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;
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;
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;
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
;
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
;
68 static void ncp_add_pstring(struct ncp_server
*server
, const char *s
)
71 assert_server_locked(server
);
73 DPRINTK("ncpfs: string too long: %s\n", s
);
76 ncp_add_byte(server
, len
);
77 ncp_add_mem(server
, s
, len
);
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;
100 ncp_reply_data(struct ncp_server
*server
, int offset
)
102 return &(server
->packet
[sizeof(struct ncp_reply_header
) + offset
]);
106 ncp_reply_byte(struct ncp_server
*server
, int offset
)
108 return get_unaligned((__u8
*) ncp_reply_data(server
, offset
));
112 ncp_reply_word(struct ncp_server
*server
, int offset
)
114 return get_unaligned((__u16
*) ncp_reply_data(server
, offset
));
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
)
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
);
135 *target
= min(ntohs(ncp_reply_word(server
, 0)), size
);
137 ncp_unlock_server(server
);
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
) {
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
);
164 /* NCP over UDP returns 0 (!!!) */
165 result
= ntohs(ncp_reply_word(server
, 0));
166 if (result
>= NCP_BLOCK_SIZE
) size
=min(result
, size
);
168 *ret_options
= ncp_reply_byte(server
, 4);
170 ncp_unlock_server(server
);
175 ncp_get_volume_info_with_number(struct ncp_server
*server
, int n
,
176 struct ncp_volume_info
*target
)
181 ncp_init_request_s(server
, 44);
182 ncp_add_byte(server
, n
);
184 if ((result
= ncp_request(server
, 22)) != 0) {
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
));
198 len
= ncp_reply_byte(server
, 29);
199 if (len
> NCP_VOLNAME_LEN
) {
200 DPRINTK("ncpfs: volume name too long: %d\n", len
);
203 memcpy(&(target
->volume_name
), ncp_reply_data(server
, 30), len
);
206 ncp_unlock_server(server
);
211 ncp_close_file(struct ncp_server
*server
, const char *file_id
)
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
);
225 ncp_make_closed(struct inode
*inode
)
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
);
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
);
244 static void ncp_add_handle_path(struct ncp_server
*server
, __u8 vol_num
,
245 __u32 dir_base
, int have_dir_base
,
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 */
253 ncp_add_byte(server
, 0xff); /* no handle */
256 ncp_add_byte(server
, 1); /* 1 component */
257 ncp_add_pstring(server
, path
);
259 ncp_add_byte(server
, 0);
263 static void ncp_extract_file_info(void *structure
, struct nw_info_struct
*target
)
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';
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
;
287 if (target
== NULL
) {
288 printk(KERN_ERR
"ncp_obtain_info: invalid call\n");
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)
301 ncp_extract_file_info(ncp_reply_data(server
, 0), target
);
304 ncp_unlock_server(server
);
308 #ifdef CONFIG_NCPFS_NFS_NS
310 ncp_obtain_DOS_dir_base(struct ncp_server
*server
,
311 __u8 volnum
, __u32 dirent
,
312 char *path
, /* At most 1 component */
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
);
332 #endif /* CONFIG_NCPFS_NFS_NS */
335 ncp_get_known_namespace(struct ncp_server
*server
, __u8 volume
)
337 #if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS)
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 ?? */
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
))
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
))
371 #endif /* CONFIG_NCPFS_OS2_NS */
375 ncp_unlock_server(server
);
377 #else /* neither OS2 nor NFS - only DOS */
379 #endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */
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
)
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
);
405 *dirEntNum
= ncp_reply_dword(server
, 0x30);
407 *DosDirNum
= ncp_reply_dword(server
, 0x34);
408 ncp_unlock_server(server
);
413 ncp_mount_subdir(struct ncp_server
*server
, struct nw_info_struct
*i
,
414 __u8 volNumber
, __u8 srcNS
, __u32 dirEntNum
)
421 dstNS
= ncp_get_known_namespace(server
, volNumber
);
422 if ((result
= ncp_ObtainSpecificDirBase(server
, srcNS
, dstNS
, volNumber
,
423 dirEntNum
, NULL
, &newDirEnt
, &newDosEnt
)) != 0)
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';
437 ncp_lookup_volume(struct ncp_server
*server
, char *volname
,
438 struct nw_info_struct
*target
)
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
);
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);
481 int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server
*server
,
485 const struct nw_modify_dos_info
*info
)
487 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
488 __u32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
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
);
506 int ncp_modify_file_or_subdir_dos_info(struct ncp_server
*server
,
509 const struct nw_modify_dos_info
*info
)
511 return ncp_modify_file_or_subdir_dos_info_path(server
, dir
, NULL
,
516 ncp_DeleteNSEntry(struct ncp_server
*server
,
517 __u8 have_dir_base
, __u8 volnum
, __u32 dirent
,
518 char* name
, __u8 ns
, int attr
)
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
);
535 ncp_del_file_or_subdir2(struct ncp_server
*server
,
536 struct dentry
*dentry
)
538 struct inode
*inode
= dentry
->d_inode
;
543 #if CONFIG_NCPFS_DEBUGDENTRY
544 PRINTK("ncpfs: ncpdel2: dentry->d_inode == NULL\n");
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
)
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));
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)));
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
;
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
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)
619 if (!(create_attributes
& aDIR
))
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
);
629 ncp_unlock_server(server
);
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
;
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);
650 memcpy(target
, ncp_reply_data(server
, 0), sizeof(*target
));
653 ncp_unlock_server(server
);
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
)
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 */
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)
684 memcpy(seq
, ncp_reply_data(server
, 0), sizeof(*seq
));
685 ncp_extract_file_info(ncp_reply_data(server
, 10), target
);
688 ncp_unlock_server(server
);
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
))
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
);
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
)
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
,
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
,
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
,
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
)
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) {
774 *bytes_read
= ntohs(ncp_reply_word(server
, 0));
775 source
= ncp_reply_data(server
, 2 + (offset
& 1));
777 memcpy(target
, source
, *bytes_read
);
779 ncp_unlock_server(server
);
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
)
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
);
809 int len
= be16_to_cpu(get_unaligned((__u16
*)((char*)bounce
+
810 sizeof(struct ncp_reply_header
))));
812 if (len
<= to_read
) {
815 source
= (char*)bounce
+
816 sizeof(struct ncp_reply_header
) + 2 +
820 if (copy_to_user(target
, source
, len
))
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
)
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
);
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
)
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
);
866 ncp_unlock_server(server
);
871 ncp_ClearPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
872 __u32 offset
, __u32 length
)
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
);
887 ncp_unlock_server(server
);
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.
898 ncp__tolower(struct nls_table
*t
, unsigned char c
)
900 unsigned char nc
= t
->charset2lower
[c
];
906 ncp__toupper(struct nls_table
*t
, unsigned char c
)
908 unsigned char nc
= t
->charset2upper
[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
;
925 vname_end
= vname
+ *vlen
- 1;
927 while (iname
< iname_end
) {
931 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
934 k
= utf8_mbtowc(&ec
, iname
, iname_end
- iname
);
939 if (*iname
== NCP_ESC
) {
942 if (iname_end
- iname
< 5)
946 for (k
= 1; k
< 5; k
++) {
951 nc
-= 'A' - '0' - 10;
952 if ((nc
< 10) || (nc
> 15)) {
961 if ( (chl
= in
->char2uni(iname
, iname_end
- iname
, &ec
)) < 0)
967 /* unitoupper should be here! */
969 chl
= out
->uni2char(ec
, vname
, vname_end
- vname
);
973 /* this is wrong... */
977 for (chi
= 0; chi
< chl
; chi
++){
978 vname
[chi
] = ncp_toupper(out
, vname
[chi
]);
985 *vlen
= vname
- vname_start
;
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
;
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
]);
1013 iname_start
= iname
;
1014 iname_end
= iname
+ *ilen
- 1;
1015 vname_end
= vname
+ vlen
;
1017 while (vname
< vname_end
) {
1021 if ( (chl
= in
->char2uni(vname
, vname_end
- vname
, &ec
)) < 0) {
1027 /* unitolower should be here! */
1029 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1032 k
= utf8_wctomb(iname
, ec
, iname_end
- iname
);
1034 err
= -ENAMETOOLONG
;
1039 if ( (chl
= out
->uni2char(ec
, iname
, iname_end
- iname
)) >= 0) {
1044 if (iname_end
- iname
< 5) {
1045 err
= -ENAMETOOLONG
;
1049 for (k
= 4; k
> 0; k
--) {
1052 v
= (ec
& 0xF) + '0';
1065 *ilen
= iname
- iname_start
;
1076 ncp__io2vol(unsigned char *vname
, unsigned int *vlen
,
1077 const unsigned char *iname
, unsigned int ilen
, int cc
)
1082 return -ENAMETOOLONG
;
1085 for (i
= 0; i
< ilen
; i
++) {
1086 *vname
= toupper(*iname
);
1091 memmove(vname
, iname
, ilen
);
1101 ncp__vol2io(unsigned char *iname
, unsigned int *ilen
,
1102 const unsigned char *vname
, unsigned int vlen
, int cc
)
1107 return -ENAMETOOLONG
;
1110 for (i
= 0; i
< vlen
; i
++) {
1111 *iname
= tolower(*vname
);
1116 memmove(iname
, vname
, vlen
);
1128 ncp_strnicmp(struct nls_table
*t
, const unsigned char *s1
,
1129 const unsigned char *s2
, int n
)
1134 if (ncp_tolower(t
, s1
[i
]) != ncp_tolower(t
, s2
[i
]))