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
8 * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
13 #include <linux/config.h>
15 #include "ncplib_kernel.h"
17 static inline void assert_server_locked(struct ncp_server
*server
)
19 if (server
->lock
== 0) {
20 DPRINTK("ncpfs: server not locked!\n");
24 static void ncp_add_byte(struct ncp_server
*server
, __u8 x
)
26 assert_server_locked(server
);
27 *(__u8
*) (&(server
->packet
[server
->current_size
])) = x
;
28 server
->current_size
+= 1;
32 static void ncp_add_word(struct ncp_server
*server
, __le16 x
)
34 assert_server_locked(server
);
35 put_unaligned(x
, (__le16
*) (&(server
->packet
[server
->current_size
])));
36 server
->current_size
+= 2;
40 static void ncp_add_be16(struct ncp_server
*server
, __u16 x
)
42 assert_server_locked(server
);
43 put_unaligned(cpu_to_be16(x
), (__be16
*) (&(server
->packet
[server
->current_size
])));
44 server
->current_size
+= 2;
47 static void ncp_add_dword(struct ncp_server
*server
, __le32 x
)
49 assert_server_locked(server
);
50 put_unaligned(x
, (__le32
*) (&(server
->packet
[server
->current_size
])));
51 server
->current_size
+= 4;
55 static void ncp_add_be32(struct ncp_server
*server
, __u32 x
)
57 assert_server_locked(server
);
58 put_unaligned(cpu_to_be32(x
), (__be32
*)(&(server
->packet
[server
->current_size
])));
59 server
->current_size
+= 4;
62 static inline void ncp_add_dword_lh(struct ncp_server
*server
, __u32 x
) {
63 ncp_add_dword(server
, cpu_to_le32(x
));
66 static void ncp_add_mem(struct ncp_server
*server
, const void *source
, int size
)
68 assert_server_locked(server
);
69 memcpy(&(server
->packet
[server
->current_size
]), source
, size
);
70 server
->current_size
+= size
;
74 static void ncp_add_pstring(struct ncp_server
*server
, const char *s
)
77 assert_server_locked(server
);
79 DPRINTK("ncpfs: string too long: %s\n", s
);
82 ncp_add_byte(server
, len
);
83 ncp_add_mem(server
, s
, len
);
87 static inline void ncp_init_request(struct ncp_server
*server
)
89 ncp_lock_server(server
);
91 server
->current_size
= sizeof(struct ncp_request_header
);
92 server
->has_subfunction
= 0;
95 static inline void ncp_init_request_s(struct ncp_server
*server
, int subfunction
)
97 ncp_lock_server(server
);
99 server
->current_size
= sizeof(struct ncp_request_header
) + 2;
100 ncp_add_byte(server
, subfunction
);
102 server
->has_subfunction
= 1;
106 ncp_reply_data(struct ncp_server
*server
, int offset
)
108 return &(server
->packet
[sizeof(struct ncp_reply_header
) + offset
]);
111 static inline __u8
BVAL(void* data
)
113 return get_unaligned((__u8
*)data
);
117 ncp_reply_byte(struct ncp_server
*server
, int offset
)
119 return get_unaligned((__u8
*) ncp_reply_data(server
, offset
));
122 static inline __u16
WVAL_LH(void* data
)
124 return le16_to_cpu(get_unaligned((__le16
*)data
));
128 ncp_reply_le16(struct ncp_server
*server
, int offset
)
130 return le16_to_cpu(get_unaligned((__le16
*) ncp_reply_data(server
, offset
)));
134 ncp_reply_be16(struct ncp_server
*server
, int offset
)
136 return be16_to_cpu(get_unaligned((__be16
*) ncp_reply_data(server
, offset
)));
139 static inline __u32
DVAL_LH(void* data
)
141 return le32_to_cpu(get_unaligned((__le32
*)data
));
145 ncp_reply_dword(struct ncp_server
*server
, int offset
)
147 return get_unaligned((__le32
*) ncp_reply_data(server
, offset
));
150 static inline __u32
ncp_reply_dword_lh(struct ncp_server
* server
, int offset
) {
151 return le32_to_cpu(ncp_reply_dword(server
, offset
));
155 ncp_negotiate_buffersize(struct ncp_server
*server
, int size
, int *target
)
159 ncp_init_request(server
);
160 ncp_add_be16(server
, size
);
162 if ((result
= ncp_request(server
, 33)) != 0) {
163 ncp_unlock_server(server
);
166 *target
= min_t(unsigned int, ncp_reply_be16(server
, 0), size
);
168 ncp_unlock_server(server
);
175 * bit 1 packet signing
178 ncp_negotiate_size_and_options(struct ncp_server
*server
,
179 int size
, int options
, int *ret_size
, int *ret_options
) {
182 /* there is minimum */
183 if (size
< NCP_BLOCK_SIZE
) size
= NCP_BLOCK_SIZE
;
185 ncp_init_request(server
);
186 ncp_add_be16(server
, size
);
187 ncp_add_byte(server
, options
);
189 if ((result
= ncp_request(server
, 0x61)) != 0)
191 ncp_unlock_server(server
);
195 /* NCP over UDP returns 0 (!!!) */
196 result
= ncp_reply_be16(server
, 0);
197 if (result
>= NCP_BLOCK_SIZE
)
198 size
= min(result
, size
);
200 *ret_options
= ncp_reply_byte(server
, 4);
202 ncp_unlock_server(server
);
206 int ncp_get_volume_info_with_number(struct ncp_server
* server
,
207 int n
, struct ncp_volume_info
* target
) {
211 ncp_init_request_s(server
, 44);
212 ncp_add_byte(server
, n
);
214 if ((result
= ncp_request(server
, 22)) != 0) {
217 target
->total_blocks
= ncp_reply_dword_lh(server
, 0);
218 target
->free_blocks
= ncp_reply_dword_lh(server
, 4);
219 target
->purgeable_blocks
= ncp_reply_dword_lh(server
, 8);
220 target
->not_yet_purgeable_blocks
= ncp_reply_dword_lh(server
, 12);
221 target
->total_dir_entries
= ncp_reply_dword_lh(server
, 16);
222 target
->available_dir_entries
= ncp_reply_dword_lh(server
, 20);
223 target
->sectors_per_block
= ncp_reply_byte(server
, 28);
225 memset(&(target
->volume_name
), 0, sizeof(target
->volume_name
));
228 len
= ncp_reply_byte(server
, 29);
229 if (len
> NCP_VOLNAME_LEN
) {
230 DPRINTK("ncpfs: volume name too long: %d\n", len
);
233 memcpy(&(target
->volume_name
), ncp_reply_data(server
, 30), len
);
236 ncp_unlock_server(server
);
240 int ncp_get_directory_info(struct ncp_server
* server
, __u8 n
,
241 struct ncp_volume_info
* target
) {
245 ncp_init_request_s(server
, 45);
246 ncp_add_byte(server
, n
);
248 if ((result
= ncp_request(server
, 22)) != 0) {
251 target
->total_blocks
= ncp_reply_dword_lh(server
, 0);
252 target
->free_blocks
= ncp_reply_dword_lh(server
, 4);
253 target
->purgeable_blocks
= 0;
254 target
->not_yet_purgeable_blocks
= 0;
255 target
->total_dir_entries
= ncp_reply_dword_lh(server
, 8);
256 target
->available_dir_entries
= ncp_reply_dword_lh(server
, 12);
257 target
->sectors_per_block
= ncp_reply_byte(server
, 20);
259 memset(&(target
->volume_name
), 0, sizeof(target
->volume_name
));
262 len
= ncp_reply_byte(server
, 21);
263 if (len
> NCP_VOLNAME_LEN
) {
264 DPRINTK("ncpfs: volume name too long: %d\n", len
);
267 memcpy(&(target
->volume_name
), ncp_reply_data(server
, 22), len
);
270 ncp_unlock_server(server
);
275 ncp_close_file(struct ncp_server
*server
, const char *file_id
)
279 ncp_init_request(server
);
280 ncp_add_byte(server
, 0);
281 ncp_add_mem(server
, file_id
, 6);
283 result
= ncp_request(server
, 66);
284 ncp_unlock_server(server
);
289 ncp_make_closed(struct inode
*inode
)
294 mutex_lock(&NCP_FINFO(inode
)->open_mutex
);
295 if (atomic_read(&NCP_FINFO(inode
)->opened
) == 1) {
296 atomic_set(&NCP_FINFO(inode
)->opened
, 0);
297 err
= ncp_close_file(NCP_SERVER(inode
), NCP_FINFO(inode
)->file_handle
);
300 PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n",
301 NCP_FINFO(inode
)->volNumber
,
302 NCP_FINFO(inode
)->dirEntNum
, err
);
304 mutex_unlock(&NCP_FINFO(inode
)->open_mutex
);
308 static void ncp_add_handle_path(struct ncp_server
*server
, __u8 vol_num
,
309 __le32 dir_base
, int have_dir_base
,
312 ncp_add_byte(server
, vol_num
);
313 ncp_add_dword(server
, dir_base
);
314 if (have_dir_base
!= 0) {
315 ncp_add_byte(server
, 1); /* dir_base */
317 ncp_add_byte(server
, 0xff); /* no handle */
320 ncp_add_byte(server
, 1); /* 1 component */
321 ncp_add_pstring(server
, path
);
323 ncp_add_byte(server
, 0);
327 int ncp_dirhandle_alloc(struct ncp_server
* server
, __u8 volnum
, __le32 dirent
,
331 ncp_init_request(server
);
332 ncp_add_byte(server
, 12); /* subfunction */
333 ncp_add_byte(server
, NW_NS_DOS
);
334 ncp_add_byte(server
, 0);
335 ncp_add_word(server
, 0);
336 ncp_add_handle_path(server
, volnum
, dirent
, 1, NULL
);
337 if ((result
= ncp_request(server
, 87)) == 0) {
338 *dirhandle
= ncp_reply_byte(server
, 0);
340 ncp_unlock_server(server
);
344 int ncp_dirhandle_free(struct ncp_server
* server
, __u8 dirhandle
) {
347 ncp_init_request_s(server
, 20);
348 ncp_add_byte(server
, dirhandle
);
349 result
= ncp_request(server
, 22);
350 ncp_unlock_server(server
);
354 void ncp_extract_file_info(void *structure
, struct nw_info_struct
*target
)
357 const int info_struct_size
= offsetof(struct nw_info_struct
, nameLen
);
359 memcpy(target
, structure
, info_struct_size
);
360 name_len
= structure
+ info_struct_size
;
361 target
->nameLen
= *name_len
;
362 memcpy(target
->entryName
, name_len
+ 1, *name_len
);
363 target
->entryName
[*name_len
] = '\0';
364 target
->volNumber
= le32_to_cpu(target
->volNumber
);
368 #ifdef CONFIG_NCPFS_NFS_NS
369 static inline void ncp_extract_nfs_info(unsigned char *structure
,
370 struct nw_nfs_info
*target
)
372 target
->mode
= DVAL_LH(structure
);
373 target
->rdev
= DVAL_LH(structure
+ 8);
377 int ncp_obtain_nfs_info(struct ncp_server
*server
,
378 struct nw_info_struct
*target
)
382 #ifdef CONFIG_NCPFS_NFS_NS
383 __u32 volnum
= target
->volNumber
;
385 if (ncp_is_nfs_extras(server
, volnum
)) {
386 ncp_init_request(server
);
387 ncp_add_byte(server
, 19); /* subfunction */
388 ncp_add_byte(server
, server
->name_space
[volnum
]);
389 ncp_add_byte(server
, NW_NS_NFS
);
390 ncp_add_byte(server
, 0);
391 ncp_add_byte(server
, volnum
);
392 ncp_add_dword(server
, target
->dirEntNum
);
393 /* We must retrieve both nlinks and rdev, otherwise some server versions
394 report zeroes instead of valid data */
395 ncp_add_dword_lh(server
, NSIBM_NFS_MODE
| NSIBM_NFS_NLINKS
| NSIBM_NFS_RDEV
);
397 if ((result
= ncp_request(server
, 87)) == 0) {
398 ncp_extract_nfs_info(ncp_reply_data(server
, 0), &target
->nfs
);
400 "ncp_obtain_nfs_info: (%s) mode=0%o, rdev=0x%x\n",
401 target
->entryName
, target
->nfs
.mode
,
404 target
->nfs
.mode
= 0;
405 target
->nfs
.rdev
= 0;
407 ncp_unlock_server(server
);
412 target
->nfs
.mode
= 0;
413 target
->nfs
.rdev
= 0;
419 * Returns information for a (one-component) name relative to
420 * the specified directory.
422 int ncp_obtain_info(struct ncp_server
*server
, struct inode
*dir
, char *path
,
423 struct nw_info_struct
*target
)
425 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
426 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
429 if (target
== NULL
) {
430 printk(KERN_ERR
"ncp_obtain_info: invalid call\n");
433 ncp_init_request(server
);
434 ncp_add_byte(server
, 6); /* subfunction */
435 ncp_add_byte(server
, server
->name_space
[volnum
]);
436 ncp_add_byte(server
, server
->name_space
[volnum
]); /* N.B. twice ?? */
437 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
438 ncp_add_dword(server
, RIM_ALL
);
439 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
441 if ((result
= ncp_request(server
, 87)) != 0)
443 ncp_extract_file_info(ncp_reply_data(server
, 0), target
);
444 ncp_unlock_server(server
);
446 result
= ncp_obtain_nfs_info(server
, target
);
450 ncp_unlock_server(server
);
454 #ifdef CONFIG_NCPFS_NFS_NS
456 ncp_obtain_DOS_dir_base(struct ncp_server
*server
,
457 __u8 volnum
, __le32 dirent
,
458 char *path
, /* At most 1 component */
459 __le32
*DOS_dir_base
)
463 ncp_init_request(server
);
464 ncp_add_byte(server
, 6); /* subfunction */
465 ncp_add_byte(server
, server
->name_space
[volnum
]);
466 ncp_add_byte(server
, server
->name_space
[volnum
]);
467 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
468 ncp_add_dword(server
, RIM_DIRECTORY
);
469 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
471 if ((result
= ncp_request(server
, 87)) == 0)
473 if (DOS_dir_base
) *DOS_dir_base
=ncp_reply_dword(server
, 0x34);
475 ncp_unlock_server(server
);
478 #endif /* CONFIG_NCPFS_NFS_NS */
481 ncp_get_known_namespace(struct ncp_server
*server
, __u8 volume
)
483 #if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS)
488 ncp_init_request(server
);
489 ncp_add_byte(server
, 24); /* Subfunction: Get Name Spaces Loaded */
490 ncp_add_word(server
, 0);
491 ncp_add_byte(server
, volume
);
493 if ((result
= ncp_request(server
, 87)) != 0) {
494 ncp_unlock_server(server
);
495 return NW_NS_DOS
; /* not result ?? */
499 no_namespaces
= ncp_reply_le16(server
, 0);
500 namespace = ncp_reply_data(server
, 2);
502 while (no_namespaces
> 0) {
503 DPRINTK("get_namespaces: found %d on %d\n", *namespace, volume
);
505 #ifdef CONFIG_NCPFS_NFS_NS
506 if ((*namespace == NW_NS_NFS
) && !(server
->m
.flags
&NCP_MOUNT_NO_NFS
))
511 #endif /* CONFIG_NCPFS_NFS_NS */
512 #ifdef CONFIG_NCPFS_OS2_NS
513 if ((*namespace == NW_NS_OS2
) && !(server
->m
.flags
&NCP_MOUNT_NO_OS2
))
517 #endif /* CONFIG_NCPFS_OS2_NS */
521 ncp_unlock_server(server
);
523 #else /* neither OS2 nor NFS - only DOS */
525 #endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */
529 ncp_ObtainSpecificDirBase(struct ncp_server
*server
,
530 __u8 nsSrc
, __u8 nsDst
, __u8 vol_num
, __le32 dir_base
,
531 char *path
, /* At most 1 component */
532 __le32
*dirEntNum
, __le32
*DosDirNum
)
536 ncp_init_request(server
);
537 ncp_add_byte(server
, 6); /* subfunction */
538 ncp_add_byte(server
, nsSrc
);
539 ncp_add_byte(server
, nsDst
);
540 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
541 ncp_add_dword(server
, RIM_ALL
);
542 ncp_add_handle_path(server
, vol_num
, dir_base
, 1, path
);
544 if ((result
= ncp_request(server
, 87)) != 0)
546 ncp_unlock_server(server
);
551 *dirEntNum
= ncp_reply_dword(server
, 0x30);
553 *DosDirNum
= ncp_reply_dword(server
, 0x34);
554 ncp_unlock_server(server
);
559 ncp_mount_subdir(struct ncp_server
*server
,
560 __u8 volNumber
, __u8 srcNS
, __le32 dirEntNum
,
561 __u32
* volume
, __le32
* newDirEnt
, __le32
* newDosEnt
)
566 dstNS
= ncp_get_known_namespace(server
, volNumber
);
567 if ((result
= ncp_ObtainSpecificDirBase(server
, srcNS
, dstNS
, volNumber
,
568 dirEntNum
, NULL
, newDirEnt
, newDosEnt
)) != 0)
572 server
->name_space
[volNumber
] = dstNS
;
574 server
->m
.mounted_vol
[1] = 0;
575 server
->m
.mounted_vol
[0] = 'X';
580 ncp_get_volume_root(struct ncp_server
*server
, const char *volname
,
581 __u32
* volume
, __le32
* dirent
, __le32
* dosdirent
)
586 DPRINTK("ncp_get_volume_root: looking up vol %s\n", volname
);
588 ncp_init_request(server
);
589 ncp_add_byte(server
, 22); /* Subfunction: Generate dir handle */
590 ncp_add_byte(server
, 0); /* DOS namespace */
591 ncp_add_byte(server
, 0); /* reserved */
592 ncp_add_byte(server
, 0); /* reserved */
593 ncp_add_byte(server
, 0); /* reserved */
595 ncp_add_byte(server
, 0); /* faked volume number */
596 ncp_add_dword(server
, 0); /* faked dir_base */
597 ncp_add_byte(server
, 0xff); /* Don't have a dir_base */
598 ncp_add_byte(server
, 1); /* 1 path component */
599 ncp_add_pstring(server
, volname
);
601 if ((result
= ncp_request(server
, 87)) != 0) {
602 ncp_unlock_server(server
);
605 *dirent
= *dosdirent
= ncp_reply_dword(server
, 4);
606 volnum
= ncp_reply_byte(server
, 8);
607 ncp_unlock_server(server
);
610 server
->name_space
[volnum
] = ncp_get_known_namespace(server
, volnum
);
612 DPRINTK("lookup_vol: namespace[%d] = %d\n",
613 volnum
, server
->name_space
[volnum
]);
619 ncp_lookup_volume(struct ncp_server
*server
, const char *volname
,
620 struct nw_info_struct
*target
)
624 memset(target
, 0, sizeof(*target
));
625 result
= ncp_get_volume_root(server
, volname
,
626 &target
->volNumber
, &target
->dirEntNum
, &target
->DosDirNum
);
630 target
->nameLen
= strlen(volname
);
631 memcpy(target
->entryName
, volname
, target
->nameLen
+1);
632 target
->attributes
= aDIR
;
633 /* set dates to Jan 1, 1986 00:00 */
634 target
->creationTime
= target
->modifyTime
= cpu_to_le16(0x0000);
635 target
->creationDate
= target
->modifyDate
= target
->lastAccessDate
= cpu_to_le16(0x0C21);
636 target
->nfs
.mode
= 0;
640 int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server
*server
,
644 const struct nw_modify_dos_info
*info
)
646 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
647 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
650 ncp_init_request(server
);
651 ncp_add_byte(server
, 7); /* subfunction */
652 ncp_add_byte(server
, server
->name_space
[volnum
]);
653 ncp_add_byte(server
, 0); /* reserved */
654 ncp_add_word(server
, cpu_to_le16(0x8006)); /* search attribs: all */
656 ncp_add_dword(server
, info_mask
);
657 ncp_add_mem(server
, info
, sizeof(*info
));
658 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
660 result
= ncp_request(server
, 87);
661 ncp_unlock_server(server
);
665 int ncp_modify_file_or_subdir_dos_info(struct ncp_server
*server
,
668 const struct nw_modify_dos_info
*info
)
670 return ncp_modify_file_or_subdir_dos_info_path(server
, dir
, NULL
,
674 #ifdef CONFIG_NCPFS_NFS_NS
675 int ncp_modify_nfs_info(struct ncp_server
*server
, __u8 volnum
, __le32 dirent
,
676 __u32 mode
, __u32 rdev
)
681 if (server
->name_space
[volnum
] == NW_NS_NFS
) {
682 ncp_init_request(server
);
683 ncp_add_byte(server
, 25); /* subfunction */
684 ncp_add_byte(server
, server
->name_space
[volnum
]);
685 ncp_add_byte(server
, NW_NS_NFS
);
686 ncp_add_byte(server
, volnum
);
687 ncp_add_dword(server
, dirent
);
688 /* we must always operate on both nlinks and rdev, otherwise
690 ncp_add_dword_lh(server
, NSIBM_NFS_MODE
| NSIBM_NFS_NLINKS
| NSIBM_NFS_RDEV
);
691 ncp_add_dword_lh(server
, mode
);
692 ncp_add_dword_lh(server
, 1); /* nlinks */
693 ncp_add_dword_lh(server
, rdev
);
694 result
= ncp_request(server
, 87);
695 ncp_unlock_server(server
);
703 ncp_DeleteNSEntry(struct ncp_server
*server
,
704 __u8 have_dir_base
, __u8 volnum
, __le32 dirent
,
705 char* name
, __u8 ns
, __le16 attr
)
709 ncp_init_request(server
);
710 ncp_add_byte(server
, 8); /* subfunction */
711 ncp_add_byte(server
, ns
);
712 ncp_add_byte(server
, 0); /* reserved */
713 ncp_add_word(server
, attr
); /* search attribs: all */
714 ncp_add_handle_path(server
, volnum
, dirent
, have_dir_base
, name
);
716 result
= ncp_request(server
, 87);
717 ncp_unlock_server(server
);
722 ncp_del_file_or_subdir2(struct ncp_server
*server
,
723 struct dentry
*dentry
)
725 struct inode
*inode
= dentry
->d_inode
;
730 #ifdef CONFIG_NCPFS_DEBUGDENTRY
731 PRINTK("ncpfs: ncpdel2: dentry->d_inode == NULL\n");
733 return 0xFF; /* Any error */
735 volnum
= NCP_FINFO(inode
)->volNumber
;
736 dirent
= NCP_FINFO(inode
)->DosDirNum
;
737 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, NULL
, NW_NS_DOS
, cpu_to_le16(0x8006));
741 ncp_del_file_or_subdir(struct ncp_server
*server
,
742 struct inode
*dir
, char *name
)
744 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
745 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
747 #ifdef CONFIG_NCPFS_NFS_NS
748 if (server
->name_space
[volnum
]==NW_NS_NFS
)
752 result
=ncp_obtain_DOS_dir_base(server
, volnum
, dirent
, name
, &dirent
);
753 if (result
) return result
;
754 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, NULL
, NW_NS_DOS
, cpu_to_le16(0x8006));
757 #endif /* CONFIG_NCPFS_NFS_NS */
758 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, name
, server
->name_space
[volnum
], cpu_to_le16(0x8006));
761 static inline void ConvertToNWfromDWORD(__u16 v0
, __u16 v1
, __u8 ret
[6])
763 __le16
*dest
= (__le16
*) ret
;
764 dest
[1] = cpu_to_le16(v0
);
765 dest
[2] = cpu_to_le16(v1
);
766 dest
[0] = cpu_to_le16(v0
+ 1);
770 /* If both dir and name are NULL, then in target there's already a
771 looked-up entry that wants to be opened. */
772 int ncp_open_create_file_or_subdir(struct ncp_server
*server
,
773 struct inode
*dir
, char *name
,
774 int open_create_mode
,
775 __le32 create_attributes
,
776 __le16 desired_acc_rights
,
777 struct ncp_entry_info
*target
)
779 __le16 search_attribs
= cpu_to_le16(0x0006);
784 volnum
= NCP_FINFO(dir
)->volNumber
;
785 dirent
= NCP_FINFO(dir
)->dirEntNum
;
787 if ((create_attributes
& aDIR
) != 0) {
788 search_attribs
|= cpu_to_le16(0x8000);
790 ncp_init_request(server
);
791 ncp_add_byte(server
, 1); /* subfunction */
792 ncp_add_byte(server
, server
->name_space
[volnum
]);
793 ncp_add_byte(server
, open_create_mode
);
794 ncp_add_word(server
, search_attribs
);
795 ncp_add_dword(server
, RIM_ALL
);
796 ncp_add_dword(server
, create_attributes
);
797 /* The desired acc rights seem to be the inherited rights mask
799 ncp_add_word(server
, desired_acc_rights
);
800 ncp_add_handle_path(server
, volnum
, dirent
, 1, name
);
802 if ((result
= ncp_request(server
, 87)) != 0)
804 if (!(create_attributes
& aDIR
))
807 /* in target there's a new finfo to fill */
808 ncp_extract_file_info(ncp_reply_data(server
, 6), &(target
->i
));
809 target
->volume
= target
->i
.volNumber
;
810 ConvertToNWfromDWORD(ncp_reply_le16(server
, 0),
811 ncp_reply_le16(server
, 2),
812 target
->file_handle
);
814 ncp_unlock_server(server
);
816 (void)ncp_obtain_nfs_info(server
, &(target
->i
));
820 ncp_unlock_server(server
);
825 ncp_initialize_search(struct ncp_server
*server
, struct inode
*dir
,
826 struct nw_search_sequence
*target
)
828 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
829 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
832 ncp_init_request(server
);
833 ncp_add_byte(server
, 2); /* subfunction */
834 ncp_add_byte(server
, server
->name_space
[volnum
]);
835 ncp_add_byte(server
, 0); /* reserved */
836 ncp_add_handle_path(server
, volnum
, dirent
, 1, NULL
);
838 result
= ncp_request(server
, 87);
841 memcpy(target
, ncp_reply_data(server
, 0), sizeof(*target
));
844 ncp_unlock_server(server
);
848 int ncp_search_for_fileset(struct ncp_server
*server
,
849 struct nw_search_sequence
*seq
,
859 ncp_init_request(server
);
860 ncp_add_byte(server
, 20);
861 ncp_add_byte(server
, server
->name_space
[seq
->volNumber
]);
862 ncp_add_byte(server
, 0); /* datastream */
863 ncp_add_word(server
, cpu_to_le16(0x8006));
864 ncp_add_dword(server
, RIM_ALL
);
865 ncp_add_word(server
, cpu_to_le16(32767)); /* max returned items */
866 ncp_add_mem(server
, seq
, 9);
867 #ifdef CONFIG_NCPFS_NFS_NS
868 if (server
->name_space
[seq
->volNumber
] == NW_NS_NFS
) {
869 ncp_add_byte(server
, 0); /* 0 byte pattern */
873 ncp_add_byte(server
, 2); /* 2 byte pattern */
874 ncp_add_byte(server
, 0xff); /* following is a wildcard */
875 ncp_add_byte(server
, '*');
877 result
= ncp_request2(server
, 87, buffer
, bufsize
);
879 ncp_unlock_server(server
);
882 if (server
->ncp_reply_size
< 12) {
883 ncp_unlock_server(server
);
886 *rsize
= server
->ncp_reply_size
- 12;
887 ncp_unlock_server(server
);
888 buffer
= buffer
+ sizeof(struct ncp_reply_header
);
890 *cnt
= WVAL_LH(buffer
+ 10);
891 *more
= BVAL(buffer
+ 9);
892 memcpy(seq
, buffer
, 9);
897 ncp_RenameNSEntry(struct ncp_server
*server
,
898 struct inode
*old_dir
, char *old_name
, __le16 old_type
,
899 struct inode
*new_dir
, char *new_name
)
901 int result
= -EINVAL
;
903 if ((old_dir
== NULL
) || (old_name
== NULL
) ||
904 (new_dir
== NULL
) || (new_name
== NULL
))
907 ncp_init_request(server
);
908 ncp_add_byte(server
, 4); /* subfunction */
909 ncp_add_byte(server
, server
->name_space
[NCP_FINFO(old_dir
)->volNumber
]);
910 ncp_add_byte(server
, 1); /* rename flag */
911 ncp_add_word(server
, old_type
); /* search attributes */
913 /* source Handle Path */
914 ncp_add_byte(server
, NCP_FINFO(old_dir
)->volNumber
);
915 ncp_add_dword(server
, NCP_FINFO(old_dir
)->dirEntNum
);
916 ncp_add_byte(server
, 1);
917 ncp_add_byte(server
, 1); /* 1 source component */
919 /* dest Handle Path */
920 ncp_add_byte(server
, NCP_FINFO(new_dir
)->volNumber
);
921 ncp_add_dword(server
, NCP_FINFO(new_dir
)->dirEntNum
);
922 ncp_add_byte(server
, 1);
923 ncp_add_byte(server
, 1); /* 1 destination component */
925 /* source path string */
926 ncp_add_pstring(server
, old_name
);
927 /* dest path string */
928 ncp_add_pstring(server
, new_name
);
930 result
= ncp_request(server
, 87);
931 ncp_unlock_server(server
);
936 int ncp_ren_or_mov_file_or_subdir(struct ncp_server
*server
,
937 struct inode
*old_dir
, char *old_name
,
938 struct inode
*new_dir
, char *new_name
)
941 __le16 old_type
= cpu_to_le16(0x06);
943 /* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */
944 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
946 if (result
== 0xFF) /* File Not Found, try directory */
948 old_type
= cpu_to_le16(0x16);
949 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
952 if (result
!= 0x92) return result
; /* All except NO_FILES_RENAMED */
953 result
= ncp_del_file_or_subdir(server
, new_dir
, new_name
);
954 if (result
!= 0) return -EACCES
;
955 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
961 /* We have to transfer to/from user space */
963 ncp_read_kernel(struct ncp_server
*server
, const char *file_id
,
964 __u32 offset
, __u16 to_read
, char *target
, int *bytes_read
)
969 ncp_init_request(server
);
970 ncp_add_byte(server
, 0);
971 ncp_add_mem(server
, file_id
, 6);
972 ncp_add_be32(server
, offset
);
973 ncp_add_be16(server
, to_read
);
975 if ((result
= ncp_request(server
, 72)) != 0) {
978 *bytes_read
= ncp_reply_be16(server
, 0);
979 source
= ncp_reply_data(server
, 2 + (offset
& 1));
981 memcpy(target
, source
, *bytes_read
);
983 ncp_unlock_server(server
);
987 /* There is a problem... egrep and some other silly tools do:
988 x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768);
989 read(<ncpfs fd>, x, 32768);
990 Now copying read result by copy_to_user causes pagefault. This pagefault
991 could not be handled because of server was locked due to read. So we have
992 to use temporary buffer. So ncp_unlock_server must be done before
993 copy_to_user (and for write, copy_from_user must be done before
994 ncp_init_request... same applies for send raw packet ioctl). Because of
995 file is normally read in bigger chunks, caller provides kmalloced
996 (vmalloced) chunk of memory with size >= to_read...
999 ncp_read_bounce(struct ncp_server
*server
, const char *file_id
,
1000 __u32 offset
, __u16 to_read
, char __user
*target
, int *bytes_read
,
1001 void* bounce
, __u32 bufsize
)
1005 ncp_init_request(server
);
1006 ncp_add_byte(server
, 0);
1007 ncp_add_mem(server
, file_id
, 6);
1008 ncp_add_be32(server
, offset
);
1009 ncp_add_be16(server
, to_read
);
1010 result
= ncp_request2(server
, 72, bounce
, bufsize
);
1011 ncp_unlock_server(server
);
1013 int len
= be16_to_cpu(get_unaligned((__be16
*)((char*)bounce
+
1014 sizeof(struct ncp_reply_header
))));
1016 if (len
<= to_read
) {
1019 source
= (char*)bounce
+
1020 sizeof(struct ncp_reply_header
) + 2 +
1024 if (copy_to_user(target
, source
, len
))
1032 ncp_write_kernel(struct ncp_server
*server
, const char *file_id
,
1033 __u32 offset
, __u16 to_write
,
1034 const char *source
, int *bytes_written
)
1038 ncp_init_request(server
);
1039 ncp_add_byte(server
, 0);
1040 ncp_add_mem(server
, file_id
, 6);
1041 ncp_add_be32(server
, offset
);
1042 ncp_add_be16(server
, to_write
);
1043 ncp_add_mem(server
, source
, to_write
);
1045 if ((result
= ncp_request(server
, 73)) == 0)
1046 *bytes_written
= to_write
;
1047 ncp_unlock_server(server
);
1051 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
1053 ncp_LogPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
1054 __u8 locktype
, __u32 offset
, __u32 length
, __u16 timeout
)
1058 ncp_init_request(server
);
1059 ncp_add_byte(server
, locktype
);
1060 ncp_add_mem(server
, file_id
, 6);
1061 ncp_add_be32(server
, offset
);
1062 ncp_add_be32(server
, length
);
1063 ncp_add_be16(server
, timeout
);
1065 if ((result
= ncp_request(server
, 0x1A)) != 0)
1067 ncp_unlock_server(server
);
1070 ncp_unlock_server(server
);
1075 ncp_ClearPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
1076 __u32 offset
, __u32 length
)
1080 ncp_init_request(server
);
1081 ncp_add_byte(server
, 0); /* who knows... lanalyzer says that */
1082 ncp_add_mem(server
, file_id
, 6);
1083 ncp_add_be32(server
, offset
);
1084 ncp_add_be32(server
, length
);
1086 if ((result
= ncp_request(server
, 0x1E)) != 0)
1088 ncp_unlock_server(server
);
1091 ncp_unlock_server(server
);
1094 #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
1096 #ifdef CONFIG_NCPFS_NLS
1097 /* This are the NLS conversion routines with inspirations and code parts
1098 * from the vfat file system and hints from Petr Vandrovec.
1102 ncp__io2vol(struct ncp_server
*server
, unsigned char *vname
, unsigned int *vlen
,
1103 const unsigned char *iname
, unsigned int ilen
, int cc
)
1105 struct nls_table
*in
= server
->nls_io
;
1106 struct nls_table
*out
= server
->nls_vol
;
1107 unsigned char *vname_start
;
1108 unsigned char *vname_end
;
1109 const unsigned char *iname_end
;
1111 iname_end
= iname
+ ilen
;
1112 vname_start
= vname
;
1113 vname_end
= vname
+ *vlen
- 1;
1115 while (iname
< iname_end
) {
1119 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1122 k
= utf8_mbtowc(&ec
, iname
, iname_end
- iname
);
1127 if (*iname
== NCP_ESC
) {
1130 if (iname_end
- iname
< 5)
1134 for (k
= 1; k
< 5; k
++) {
1137 nc
= iname
[k
] - '0';
1139 nc
-= 'A' - '0' - 10;
1140 if ((nc
< 10) || (nc
> 15)) {
1144 ec
= (ec
<< 4) | nc
;
1149 if ( (chl
= in
->char2uni(iname
, iname_end
- iname
, &ec
)) < 0)
1155 /* unitoupper should be here! */
1157 chl
= out
->uni2char(ec
, vname
, vname_end
- vname
);
1161 /* this is wrong... */
1165 for (chi
= 0; chi
< chl
; chi
++){
1166 vname
[chi
] = ncp_toupper(out
, vname
[chi
]);
1173 *vlen
= vname
- vname_start
;
1178 ncp__vol2io(struct ncp_server
*server
, unsigned char *iname
, unsigned int *ilen
,
1179 const unsigned char *vname
, unsigned int vlen
, int cc
)
1181 struct nls_table
*in
= server
->nls_vol
;
1182 struct nls_table
*out
= server
->nls_io
;
1183 const unsigned char *vname_end
;
1184 unsigned char *iname_start
;
1185 unsigned char *iname_end
;
1186 unsigned char *vname_cc
;
1194 /* this is wrong! */
1195 vname_cc
= kmalloc(vlen
, GFP_KERNEL
);
1198 for (i
= 0; i
< vlen
; i
++)
1199 vname_cc
[i
] = ncp_tolower(in
, vname
[i
]);
1203 iname_start
= iname
;
1204 iname_end
= iname
+ *ilen
- 1;
1205 vname_end
= vname
+ vlen
;
1207 while (vname
< vname_end
) {
1211 if ( (chl
= in
->char2uni(vname
, vname_end
- vname
, &ec
)) < 0) {
1217 /* unitolower should be here! */
1219 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1222 k
= utf8_wctomb(iname
, ec
, iname_end
- iname
);
1224 err
= -ENAMETOOLONG
;
1229 if ( (chl
= out
->uni2char(ec
, iname
, iname_end
- iname
)) >= 0) {
1234 if (iname_end
- iname
< 5) {
1235 err
= -ENAMETOOLONG
;
1239 for (k
= 4; k
> 0; k
--) {
1242 v
= (ec
& 0xF) + '0';
1255 *ilen
= iname
- iname_start
;
1266 ncp__io2vol(unsigned char *vname
, unsigned int *vlen
,
1267 const unsigned char *iname
, unsigned int ilen
, int cc
)
1272 return -ENAMETOOLONG
;
1275 for (i
= 0; i
< ilen
; i
++) {
1276 *vname
= toupper(*iname
);
1281 memmove(vname
, iname
, ilen
);
1291 ncp__vol2io(unsigned char *iname
, unsigned int *ilen
,
1292 const unsigned char *vname
, unsigned int vlen
, int cc
)
1297 return -ENAMETOOLONG
;
1300 for (i
= 0; i
< vlen
; i
++) {
1301 *iname
= tolower(*vname
);
1306 memmove(iname
, vname
, vlen
);