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 void ncp_init_request_s(struct ncp_server
*server
, int subfunction
)
91 ncp_init_request(server
);
92 ncp_add_word(server
, 0); /* preliminary size */
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 * Called with the superblock locked.
228 ncp_make_closed(struct inode
*inode
)
231 NCP_FINFO(inode
)->opened
= 0;
232 err
= ncp_close_file(NCP_SERVER(inode
), NCP_FINFO(inode
)->file_handle
);
235 PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n",
236 NCP_FINFO(inode
)->volNumber
,
237 NCP_FINFO(inode
)->dirEntNum
, err
);
241 static void ncp_add_handle_path(struct ncp_server
*server
, __u8 vol_num
,
242 __u32 dir_base
, int have_dir_base
,
245 ncp_add_byte(server
, vol_num
);
246 ncp_add_dword(server
, dir_base
);
247 if (have_dir_base
!= 0) {
248 ncp_add_byte(server
, 1); /* dir_base */
250 ncp_add_byte(server
, 0xff); /* no handle */
253 ncp_add_byte(server
, 1); /* 1 component */
254 ncp_add_pstring(server
, path
);
256 ncp_add_byte(server
, 0);
260 static void ncp_extract_file_info(void *structure
, struct nw_info_struct
*target
)
263 const int info_struct_size
= sizeof(struct nw_info_struct
) - 257;
265 memcpy(target
, structure
, info_struct_size
);
266 name_len
= structure
+ info_struct_size
;
267 target
->nameLen
= *name_len
;
268 memcpy(target
->entryName
, name_len
+ 1, *name_len
);
269 target
->entryName
[*name_len
] = '\0';
274 * Returns information for a (one-component) name relative to
275 * the specified directory.
277 int ncp_obtain_info(struct ncp_server
*server
, struct inode
*dir
, char *path
,
278 struct nw_info_struct
*target
)
280 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
281 __u32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
284 if (target
== NULL
) {
285 printk(KERN_ERR
"ncp_obtain_info: invalid call\n");
288 ncp_init_request(server
);
289 ncp_add_byte(server
, 6); /* subfunction */
290 ncp_add_byte(server
, server
->name_space
[volnum
]);
291 ncp_add_byte(server
, server
->name_space
[volnum
]); /* N.B. twice ?? */
292 ncp_add_word(server
, htons(0x0680)); /* get all */
293 ncp_add_dword(server
, RIM_ALL
);
294 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
296 if ((result
= ncp_request(server
, 87)) != 0)
298 ncp_extract_file_info(ncp_reply_data(server
, 0), target
);
301 ncp_unlock_server(server
);
305 #ifdef CONFIG_NCPFS_NFS_NS
307 ncp_obtain_DOS_dir_base(struct ncp_server
*server
,
308 __u8 volnum
, __u32 dirent
,
309 char *path
, /* At most 1 component */
314 ncp_init_request(server
);
315 ncp_add_byte(server
, 6); /* subfunction */
316 ncp_add_byte(server
, server
->name_space
[volnum
]);
317 ncp_add_byte(server
, server
->name_space
[volnum
]);
318 ncp_add_word(server
, htons(0x0680)); /* get all */
319 ncp_add_dword(server
, RIM_DIRECTORY
);
320 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
322 if ((result
= ncp_request(server
, 87)) == 0)
324 if (DOS_dir_base
) *DOS_dir_base
=ncp_reply_dword(server
, 0x34);
326 ncp_unlock_server(server
);
329 #endif /* CONFIG_NCPFS_NFS_NS */
332 ncp_get_known_namespace(struct ncp_server
*server
, __u8 volume
)
334 #if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS)
339 ncp_init_request(server
);
340 ncp_add_byte(server
, 24); /* Subfunction: Get Name Spaces Loaded */
341 ncp_add_word(server
, 0);
342 ncp_add_byte(server
, volume
);
344 if ((result
= ncp_request(server
, 87)) != 0) {
345 ncp_unlock_server(server
);
346 return NW_NS_DOS
; /* not result ?? */
350 no_namespaces
= ncp_reply_word(server
, 0);
351 namespace = ncp_reply_data(server
, 2);
353 while (no_namespaces
> 0) {
354 DPRINTK("get_namespaces: found %d on %d\n", *namespace, volume
);
356 #ifdef CONFIG_NCPFS_NFS_NS
357 if ((*namespace == NW_NS_NFS
) && !(server
->m
.flags
&NCP_MOUNT_NO_NFS
))
362 #endif /* CONFIG_NCPFS_NFS_NS */
363 #ifdef CONFIG_NCPFS_OS2_NS
364 if ((*namespace == NW_NS_OS2
) && !(server
->m
.flags
&NCP_MOUNT_NO_OS2
))
368 #endif /* CONFIG_NCPFS_OS2_NS */
372 ncp_unlock_server(server
);
374 #else /* neither OS2 nor NFS - only DOS */
376 #endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */
380 ncp_ObtainSpecificDirBase(struct ncp_server
*server
,
381 __u8 nsSrc
, __u8 nsDst
, __u8 vol_num
, __u32 dir_base
,
382 char *path
, /* At most 1 component */
383 __u32
*dirEntNum
, __u32
*DosDirNum
)
387 ncp_init_request(server
);
388 ncp_add_byte(server
, 6); /* subfunction */
389 ncp_add_byte(server
, nsSrc
);
390 ncp_add_byte(server
, nsDst
);
391 ncp_add_word(server
, htons(0x0680)); /* get all */
392 ncp_add_dword(server
, RIM_ALL
);
393 ncp_add_handle_path(server
, vol_num
, dir_base
, 1, path
);
395 if ((result
= ncp_request(server
, 87)) != 0)
397 ncp_unlock_server(server
);
402 *dirEntNum
= ncp_reply_dword(server
, 0x30);
404 *DosDirNum
= ncp_reply_dword(server
, 0x34);
405 ncp_unlock_server(server
);
410 ncp_mount_subdir(struct ncp_server
*server
, struct nw_info_struct
*i
,
411 __u8 volNumber
, __u8 srcNS
, __u32 dirEntNum
)
418 dstNS
= ncp_get_known_namespace(server
, volNumber
);
419 if ((result
= ncp_ObtainSpecificDirBase(server
, srcNS
, dstNS
, volNumber
,
420 dirEntNum
, NULL
, &newDirEnt
, &newDosEnt
)) != 0)
424 server
->name_space
[volNumber
] = dstNS
;
425 i
->volNumber
= volNumber
;
426 i
->dirEntNum
= newDirEnt
;
427 i
->DosDirNum
= newDosEnt
;
428 server
->m
.mounted_vol
[1] = 0;
429 server
->m
.mounted_vol
[0] = 'X';
434 ncp_lookup_volume(struct ncp_server
*server
, char *volname
,
435 struct nw_info_struct
*target
)
440 DPRINTK("ncp_lookup_volume: looking up vol %s\n", volname
);
442 ncp_init_request(server
);
443 ncp_add_byte(server
, 22); /* Subfunction: Generate dir handle */
444 ncp_add_byte(server
, 0); /* DOS namespace */
445 ncp_add_byte(server
, 0); /* reserved */
446 ncp_add_byte(server
, 0); /* reserved */
447 ncp_add_byte(server
, 0); /* reserved */
449 ncp_add_byte(server
, 0); /* faked volume number */
450 ncp_add_dword(server
, 0); /* faked dir_base */
451 ncp_add_byte(server
, 0xff); /* Don't have a dir_base */
452 ncp_add_byte(server
, 1); /* 1 path component */
453 ncp_add_pstring(server
, volname
);
455 if ((result
= ncp_request(server
, 87)) != 0) {
456 ncp_unlock_server(server
);
459 memset(target
, 0, sizeof(*target
));
460 target
->DosDirNum
= target
->dirEntNum
= ncp_reply_dword(server
, 4);
461 target
->volNumber
= volnum
= ncp_reply_byte(server
, 8);
462 ncp_unlock_server(server
);
464 server
->name_space
[volnum
] = ncp_get_known_namespace(server
, volnum
);
466 DPRINTK("lookup_vol: namespace[%d] = %d\n",
467 volnum
, server
->name_space
[volnum
]);
469 target
->nameLen
= strlen(volname
);
470 memcpy(target
->entryName
, volname
, target
->nameLen
+1);
471 target
->attributes
= aDIR
;
472 /* set dates to Jan 1, 1986 00:00 */
473 target
->creationTime
= target
->modifyTime
= cpu_to_le16(0x0000);
474 target
->creationDate
= target
->modifyDate
= target
->lastAccessDate
= cpu_to_le16(0x0C21);
478 int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server
*server
,
482 const struct nw_modify_dos_info
*info
)
484 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
485 __u32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
488 ncp_init_request(server
);
489 ncp_add_byte(server
, 7); /* subfunction */
490 ncp_add_byte(server
, server
->name_space
[volnum
]);
491 ncp_add_byte(server
, 0); /* reserved */
492 ncp_add_word(server
, htons(0x0680)); /* search attribs: all */
494 ncp_add_dword(server
, info_mask
);
495 ncp_add_mem(server
, info
, sizeof(*info
));
496 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
498 result
= ncp_request(server
, 87);
499 ncp_unlock_server(server
);
503 int ncp_modify_file_or_subdir_dos_info(struct ncp_server
*server
,
506 const struct nw_modify_dos_info
*info
)
508 return ncp_modify_file_or_subdir_dos_info_path(server
, dir
, NULL
,
513 ncp_DeleteNSEntry(struct ncp_server
*server
,
514 __u8 have_dir_base
, __u8 volnum
, __u32 dirent
,
515 char* name
, __u8 ns
, int attr
)
519 ncp_init_request(server
);
520 ncp_add_byte(server
, 8); /* subfunction */
521 ncp_add_byte(server
, ns
);
522 ncp_add_byte(server
, 0); /* reserved */
523 ncp_add_word(server
, attr
); /* search attribs: all */
524 ncp_add_handle_path(server
, volnum
, dirent
, have_dir_base
, name
);
526 result
= ncp_request(server
, 87);
527 ncp_unlock_server(server
);
532 ncp_del_file_or_subdir2(struct ncp_server
*server
,
533 struct dentry
*dentry
)
535 struct inode
*inode
= dentry
->d_inode
;
540 #if CONFIG_NCPFS_DEBUGDENTRY
541 PRINTK("ncpfs: ncpdel2: dentry->d_inode == NULL\n");
543 return 0xFF; /* Any error */
545 volnum
= NCP_FINFO(inode
)->volNumber
;
546 dirent
= NCP_FINFO(inode
)->DosDirNum
;
547 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, NULL
, NW_NS_DOS
, htons(0x0680));
551 ncp_del_file_or_subdir(struct ncp_server
*server
,
552 struct inode
*dir
, char *name
)
554 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
555 __u32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
557 #ifdef CONFIG_NCPFS_NFS_NS
558 if (server
->name_space
[volnum
]==NW_NS_NFS
)
562 result
=ncp_obtain_DOS_dir_base(server
, volnum
, dirent
, name
, &dirent
);
563 if (result
) return result
;
564 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, NULL
, NW_NS_DOS
, htons(0x0680));
567 #endif /* CONFIG_NCPFS_NFS_NS */
568 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, name
, server
->name_space
[volnum
], htons(0x0680));
571 static inline void ConvertToNWfromDWORD(__u32 sfd
, __u8 ret
[6])
573 __u16
*dest
= (__u16
*) ret
;
574 memcpy(ret
+ 2, &sfd
, 4);
575 dest
[0] = cpu_to_le16((le16_to_cpu(dest
[1]) + le16_to_cpu(1)));
579 /* If both dir and name are NULL, then in target there's already a
580 looked-up entry that wants to be opened. */
581 int ncp_open_create_file_or_subdir(struct ncp_server
*server
,
582 struct inode
*dir
, char *name
,
583 int open_create_mode
,
584 __u32 create_attributes
,
585 int desired_acc_rights
,
586 struct ncp_entry_info
*target
)
588 __u16 search_attribs
= ntohs(0x0600);
589 __u8 volnum
= target
->i
.volNumber
;
590 __u32 dirent
= target
->i
.dirEntNum
;
595 volnum
= NCP_FINFO(dir
)->volNumber
;
596 dirent
= NCP_FINFO(dir
)->dirEntNum
;
599 if ((create_attributes
& aDIR
) != 0) {
600 search_attribs
|= ntohs(0x0080);
602 ncp_init_request(server
);
603 ncp_add_byte(server
, 1); /* subfunction */
604 ncp_add_byte(server
, server
->name_space
[volnum
]);
605 ncp_add_byte(server
, open_create_mode
);
606 ncp_add_word(server
, search_attribs
);
607 ncp_add_dword(server
, RIM_ALL
);
608 ncp_add_dword(server
, create_attributes
);
609 /* The desired acc rights seem to be the inherited rights mask
611 ncp_add_word(server
, desired_acc_rights
);
612 ncp_add_handle_path(server
, volnum
, dirent
, 1, name
);
614 if ((result
= ncp_request(server
, 87)) != 0)
617 target
->server_file_handle
= ncp_reply_dword(server
, 0);
618 target
->open_create_action
= ncp_reply_byte(server
, 4);
620 /* in target there's a new finfo to fill */
621 ncp_extract_file_info(ncp_reply_data(server
, 6), &(target
->i
));
622 ConvertToNWfromDWORD(target
->server_file_handle
, target
->file_handle
);
625 ncp_unlock_server(server
);
630 ncp_initialize_search(struct ncp_server
*server
, struct inode
*dir
,
631 struct nw_search_sequence
*target
)
633 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
634 __u32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
637 ncp_init_request(server
);
638 ncp_add_byte(server
, 2); /* subfunction */
639 ncp_add_byte(server
, server
->name_space
[volnum
]);
640 ncp_add_byte(server
, 0); /* reserved */
641 ncp_add_handle_path(server
, volnum
, dirent
, 1, NULL
);
643 result
= ncp_request(server
, 87);
646 memcpy(target
, ncp_reply_data(server
, 0), sizeof(*target
));
649 ncp_unlock_server(server
);
653 /* Search for everything */
654 int ncp_search_for_file_or_subdir(struct ncp_server
*server
,
655 struct nw_search_sequence
*seq
,
656 struct nw_info_struct
*target
)
660 ncp_init_request(server
);
661 ncp_add_byte(server
, 3); /* subfunction */
662 ncp_add_byte(server
, server
->name_space
[seq
->volNumber
]);
663 ncp_add_byte(server
, 0); /* data stream (???) */
664 ncp_add_word(server
, htons(0x0680)); /* Search attribs */
665 ncp_add_dword(server
, RIM_ALL
); /* return info mask */
666 ncp_add_mem(server
, seq
, 9);
667 #ifdef CONFIG_NCPFS_NFS_NS
668 if (server
->name_space
[seq
->volNumber
] == NW_NS_NFS
) {
669 ncp_add_byte(server
, 0); /* 0 byte pattern */
673 ncp_add_byte(server
, 2); /* 2 byte pattern */
674 ncp_add_byte(server
, 0xff); /* following is a wildcard */
675 ncp_add_byte(server
, '*');
678 if ((result
= ncp_request(server
, 87)) != 0)
680 memcpy(seq
, ncp_reply_data(server
, 0), sizeof(*seq
));
681 ncp_extract_file_info(ncp_reply_data(server
, 10), target
);
684 ncp_unlock_server(server
);
689 ncp_RenameNSEntry(struct ncp_server
*server
,
690 struct inode
*old_dir
, char *old_name
, int old_type
,
691 struct inode
*new_dir
, char *new_name
)
693 int result
= -EINVAL
;
695 if ((old_dir
== NULL
) || (old_name
== NULL
) ||
696 (new_dir
== NULL
) || (new_name
== NULL
))
699 ncp_init_request(server
);
700 ncp_add_byte(server
, 4); /* subfunction */
701 ncp_add_byte(server
, server
->name_space
[NCP_FINFO(old_dir
)->volNumber
]);
702 ncp_add_byte(server
, 1); /* rename flag */
703 ncp_add_word(server
, old_type
); /* search attributes */
705 /* source Handle Path */
706 ncp_add_byte(server
, NCP_FINFO(old_dir
)->volNumber
);
707 ncp_add_dword(server
, NCP_FINFO(old_dir
)->dirEntNum
);
708 ncp_add_byte(server
, 1);
709 ncp_add_byte(server
, 1); /* 1 source component */
711 /* dest Handle Path */
712 ncp_add_byte(server
, NCP_FINFO(new_dir
)->volNumber
);
713 ncp_add_dword(server
, NCP_FINFO(new_dir
)->dirEntNum
);
714 ncp_add_byte(server
, 1);
715 ncp_add_byte(server
, 1); /* 1 destination component */
717 /* source path string */
718 ncp_add_pstring(server
, old_name
);
719 /* dest path string */
720 ncp_add_pstring(server
, new_name
);
722 result
= ncp_request(server
, 87);
723 ncp_unlock_server(server
);
728 int ncp_ren_or_mov_file_or_subdir(struct ncp_server
*server
,
729 struct inode
*old_dir
, char *old_name
,
730 struct inode
*new_dir
, char *new_name
)
733 int old_type
= htons(0x0600);
735 /* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */
736 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
738 if (result
== 0xFF) /* File Not Found, try directory */
740 old_type
= htons(0x1600);
741 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
744 if (result
!= 0x92) return result
; /* All except NO_FILES_RENAMED */
745 result
= ncp_del_file_or_subdir(server
, new_dir
, new_name
);
746 if (result
!= 0) return -EACCES
;
747 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
753 /* We have to transfer to/from user space */
755 ncp_read_kernel(struct ncp_server
*server
, const char *file_id
,
756 __u32 offset
, __u16 to_read
, char *target
, int *bytes_read
)
761 ncp_init_request(server
);
762 ncp_add_byte(server
, 0);
763 ncp_add_mem(server
, file_id
, 6);
764 ncp_add_dword(server
, htonl(offset
));
765 ncp_add_word(server
, htons(to_read
));
767 if ((result
= ncp_request(server
, 72)) != 0) {
770 *bytes_read
= ntohs(ncp_reply_word(server
, 0));
771 source
= ncp_reply_data(server
, 2 + (offset
& 1));
773 memcpy(target
, source
, *bytes_read
);
775 ncp_unlock_server(server
);
779 /* There is a problem... egrep and some other silly tools do:
780 x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768);
781 read(<ncpfs fd>, x, 32768);
782 Now copying read result by copy_to_user causes pagefault. This pagefault
783 could not be handled because of server was locked due to read. So we have
784 to use temporary buffer. So ncp_unlock_server must be done before
785 copy_to_user (and for write, copy_from_user must be done before
786 ncp_init_request... same applies for send raw packet ioctl). Because of
787 file is normally read in bigger chunks, caller provides kmalloced
788 (vmalloced) chunk of memory with size >= to_read...
791 ncp_read_bounce(struct ncp_server
*server
, const char *file_id
,
792 __u32 offset
, __u16 to_read
, char *target
, int *bytes_read
,
793 void* bounce
, __u32 bufsize
)
797 ncp_init_request(server
);
798 ncp_add_byte(server
, 0);
799 ncp_add_mem(server
, file_id
, 6);
800 ncp_add_dword(server
, htonl(offset
));
801 ncp_add_word(server
, htons(to_read
));
802 result
= ncp_request2(server
, 72, bounce
, bufsize
);
803 ncp_unlock_server(server
);
805 int len
= be16_to_cpu(get_unaligned((__u16
*)((char*)bounce
+
806 sizeof(struct ncp_reply_header
))));
808 if (len
<= to_read
) {
811 source
= (char*)bounce
+
812 sizeof(struct ncp_reply_header
) + 2 +
816 if (copy_to_user(target
, source
, len
))
824 ncp_write_kernel(struct ncp_server
*server
, const char *file_id
,
825 __u32 offset
, __u16 to_write
,
826 const char *source
, int *bytes_written
)
830 ncp_init_request(server
);
831 ncp_add_byte(server
, 0);
832 ncp_add_mem(server
, file_id
, 6);
833 ncp_add_dword(server
, htonl(offset
));
834 ncp_add_word(server
, htons(to_write
));
835 ncp_add_mem(server
, source
, to_write
);
837 if ((result
= ncp_request(server
, 73)) == 0)
838 *bytes_written
= to_write
;
839 ncp_unlock_server(server
);
843 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
845 ncp_LogPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
846 __u8 locktype
, __u32 offset
, __u32 length
, __u16 timeout
)
850 ncp_init_request(server
);
851 ncp_add_byte(server
, locktype
);
852 ncp_add_mem(server
, file_id
, 6);
853 ncp_add_dword(server
, htonl(offset
));
854 ncp_add_dword(server
, htonl(length
));
855 ncp_add_word(server
, htons(timeout
));
857 if ((result
= ncp_request(server
, 0x1A)) != 0)
859 ncp_unlock_server(server
);
862 ncp_unlock_server(server
);
867 ncp_ClearPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
868 __u32 offset
, __u32 length
)
872 ncp_init_request(server
);
873 ncp_add_byte(server
, 0); /* who knows... lanalyzer says that */
874 ncp_add_mem(server
, file_id
, 6);
875 ncp_add_dword(server
, htonl(offset
));
876 ncp_add_dword(server
, htonl(length
));
878 if ((result
= ncp_request(server
, 0x1E)) != 0)
880 ncp_unlock_server(server
);
883 ncp_unlock_server(server
);
886 #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
888 #ifdef CONFIG_NCPFS_NLS
889 /* This are the NLS conversion routines with inspirations and code parts
890 * from the vfat file system and hints from Petr Vandrovec.
894 ncp__tolower(struct nls_table
*t
, unsigned char c
)
896 unsigned char nc
= t
->charset2lower
[c
];
902 ncp__toupper(struct nls_table
*t
, unsigned char c
)
904 unsigned char nc
= t
->charset2upper
[c
];
910 ncp__io2vol(struct ncp_server
*server
, unsigned char *vname
, unsigned int *vlen
,
911 const unsigned char *iname
, unsigned int ilen
, int cc
)
913 struct nls_table
*in
= server
->nls_io
;
914 struct nls_table
*out
= server
->nls_vol
;
915 struct nls_unicode uc
;
916 unsigned char nc
, *up
;
917 int i
, k
, maxlen
= *vlen
- 1;
922 for (i
= 0; i
< ilen
;) {
924 return -ENAMETOOLONG
;
926 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
927 k
= utf8_mbtowc(&ec
, iname
, ilen
- i
);
935 if (*iname
== NCP_ESC
) {
940 for (k
= 1; k
< 5; k
++) {
943 if (nc
>= '0' && nc
<= '9') {
947 if (nc
>= 'a' && nc
<= 'f') {
948 ec
|= nc
- ('a' - 10);
951 if (nc
>= 'A' && nc
<= 'F') {
952 ec
|= nc
- ('A' - 10);
962 uc
= in
->charset2uni
[*iname
];
968 up
= out
->page_uni2charset
[uc
.uni2
];
976 *vname
= cc
? ncp_toupper(out
, nc
) : nc
;
986 ncp__vol2io(struct ncp_server
*server
, unsigned char *iname
, unsigned int *ilen
,
987 const unsigned char *vname
, unsigned int vlen
, int cc
)
989 struct nls_table
*in
= server
->nls_vol
;
990 struct nls_table
*out
= server
->nls_io
;
991 struct nls_unicode uc
;
992 unsigned char nc
, *up
;
993 int i
, k
, maxlen
= *ilen
- 1;
998 for (i
= 0; i
< vlen
; i
++) {
1000 return -ENAMETOOLONG
;
1002 uc
= in
->charset2uni
[cc
? ncp_tolower(in
, *vname
) : *vname
];
1004 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1005 k
= utf8_wctomb(iname
, (uc
.uni2
<< 8) + uc
.uni1
,
1008 return -ENAMETOOLONG
;
1012 up
= out
->page_uni2charset
[uc
.uni2
];
1023 if (*ilen
> maxlen
- 5)
1024 return -ENAMETOOLONG
;
1025 ec
= (uc
.uni2
<< 8) + uc
.uni1
;
1027 for (k
= 4; k
> 0; k
--) {
1029 iname
[k
] = nc
> 9 ? nc
+ ('a' - 10)
1047 ncp__io2vol(unsigned char *vname
, unsigned int *vlen
,
1048 const unsigned char *iname
, unsigned int ilen
, int cc
)
1053 return -ENAMETOOLONG
;
1056 for (i
= 0; i
< ilen
; i
++) {
1057 *vname
= toupper(*iname
);
1062 memmove(vname
, iname
, ilen
);
1072 ncp__vol2io(unsigned char *iname
, unsigned int *ilen
,
1073 const unsigned char *vname
, unsigned int vlen
, int cc
)
1078 return -ENAMETOOLONG
;
1081 for (i
= 0; i
< vlen
; i
++) {
1082 *iname
= tolower(*vname
);
1087 memmove(iname
, vname
, vlen
);
1099 ncp_strnicmp(struct nls_table
*t
, const unsigned char *s1
,
1100 const unsigned char *s2
, int n
)
1105 if (ncp_tolower(t
, s1
[i
]) != ncp_tolower(t
, s2
[i
]))