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
14 #include "ncplib_kernel.h"
16 static inline void assert_server_locked(struct ncp_server
*server
)
18 if (server
->lock
== 0) {
19 DPRINTK("ncpfs: server not locked!\n");
23 static void ncp_add_byte(struct ncp_server
*server
, __u8 x
)
25 assert_server_locked(server
);
26 *(__u8
*) (&(server
->packet
[server
->current_size
])) = x
;
27 server
->current_size
+= 1;
31 static void ncp_add_word(struct ncp_server
*server
, __le16 x
)
33 assert_server_locked(server
);
34 put_unaligned(x
, (__le16
*) (&(server
->packet
[server
->current_size
])));
35 server
->current_size
+= 2;
39 static void ncp_add_be16(struct ncp_server
*server
, __u16 x
)
41 assert_server_locked(server
);
42 put_unaligned(cpu_to_be16(x
), (__be16
*) (&(server
->packet
[server
->current_size
])));
43 server
->current_size
+= 2;
46 static void ncp_add_dword(struct ncp_server
*server
, __le32 x
)
48 assert_server_locked(server
);
49 put_unaligned(x
, (__le32
*) (&(server
->packet
[server
->current_size
])));
50 server
->current_size
+= 4;
54 static void ncp_add_be32(struct ncp_server
*server
, __u32 x
)
56 assert_server_locked(server
);
57 put_unaligned(cpu_to_be32(x
), (__be32
*)(&(server
->packet
[server
->current_size
])));
58 server
->current_size
+= 4;
61 static inline void ncp_add_dword_lh(struct ncp_server
*server
, __u32 x
) {
62 ncp_add_dword(server
, cpu_to_le32(x
));
65 static void ncp_add_mem(struct ncp_server
*server
, const void *source
, int size
)
67 assert_server_locked(server
);
68 memcpy(&(server
->packet
[server
->current_size
]), source
, size
);
69 server
->current_size
+= size
;
73 static void ncp_add_pstring(struct ncp_server
*server
, const char *s
)
76 assert_server_locked(server
);
78 DPRINTK("ncpfs: string too long: %s\n", s
);
81 ncp_add_byte(server
, len
);
82 ncp_add_mem(server
, s
, len
);
86 static inline void ncp_init_request(struct ncp_server
*server
)
88 ncp_lock_server(server
);
90 server
->current_size
= sizeof(struct ncp_request_header
);
91 server
->has_subfunction
= 0;
94 static inline void ncp_init_request_s(struct ncp_server
*server
, int subfunction
)
96 ncp_lock_server(server
);
98 server
->current_size
= sizeof(struct ncp_request_header
) + 2;
99 ncp_add_byte(server
, subfunction
);
101 server
->has_subfunction
= 1;
105 ncp_reply_data(struct ncp_server
*server
, int offset
)
107 return &(server
->packet
[sizeof(struct ncp_reply_header
) + offset
]);
110 static inline u8
BVAL(const void *data
)
112 return *(const u8
*)data
;
115 static u8
ncp_reply_byte(struct ncp_server
*server
, int offset
)
117 return *(const u8
*)ncp_reply_data(server
, offset
);
120 static inline u16
WVAL_LH(const void *data
)
122 return get_unaligned_le16(data
);
126 ncp_reply_le16(struct ncp_server
*server
, int offset
)
128 return get_unaligned_le16(ncp_reply_data(server
, offset
));
132 ncp_reply_be16(struct ncp_server
*server
, int offset
)
134 return get_unaligned_be16(ncp_reply_data(server
, offset
));
137 static inline u32
DVAL_LH(const void *data
)
139 return get_unaligned_le32(data
);
143 ncp_reply_dword(struct ncp_server
*server
, int offset
)
145 return get_unaligned((__le32
*)ncp_reply_data(server
, offset
));
148 static inline __u32
ncp_reply_dword_lh(struct ncp_server
* server
, int offset
) {
149 return le32_to_cpu(ncp_reply_dword(server
, offset
));
153 ncp_negotiate_buffersize(struct ncp_server
*server
, int size
, int *target
)
157 ncp_init_request(server
);
158 ncp_add_be16(server
, size
);
160 if ((result
= ncp_request(server
, 33)) != 0) {
161 ncp_unlock_server(server
);
164 *target
= min_t(unsigned int, ncp_reply_be16(server
, 0), size
);
166 ncp_unlock_server(server
);
173 * bit 1 packet signing
176 ncp_negotiate_size_and_options(struct ncp_server
*server
,
177 int size
, int options
, int *ret_size
, int *ret_options
) {
180 /* there is minimum */
181 if (size
< NCP_BLOCK_SIZE
) size
= NCP_BLOCK_SIZE
;
183 ncp_init_request(server
);
184 ncp_add_be16(server
, size
);
185 ncp_add_byte(server
, options
);
187 if ((result
= ncp_request(server
, 0x61)) != 0)
189 ncp_unlock_server(server
);
193 /* NCP over UDP returns 0 (!!!) */
194 result
= ncp_reply_be16(server
, 0);
195 if (result
>= NCP_BLOCK_SIZE
)
196 size
= min(result
, size
);
198 *ret_options
= ncp_reply_byte(server
, 4);
200 ncp_unlock_server(server
);
204 int ncp_get_volume_info_with_number(struct ncp_server
* server
,
205 int n
, struct ncp_volume_info
* target
) {
209 ncp_init_request_s(server
, 44);
210 ncp_add_byte(server
, n
);
212 if ((result
= ncp_request(server
, 22)) != 0) {
215 target
->total_blocks
= ncp_reply_dword_lh(server
, 0);
216 target
->free_blocks
= ncp_reply_dword_lh(server
, 4);
217 target
->purgeable_blocks
= ncp_reply_dword_lh(server
, 8);
218 target
->not_yet_purgeable_blocks
= ncp_reply_dword_lh(server
, 12);
219 target
->total_dir_entries
= ncp_reply_dword_lh(server
, 16);
220 target
->available_dir_entries
= ncp_reply_dword_lh(server
, 20);
221 target
->sectors_per_block
= ncp_reply_byte(server
, 28);
223 memset(&(target
->volume_name
), 0, sizeof(target
->volume_name
));
226 len
= ncp_reply_byte(server
, 29);
227 if (len
> NCP_VOLNAME_LEN
) {
228 DPRINTK("ncpfs: volume name too long: %d\n", len
);
231 memcpy(&(target
->volume_name
), ncp_reply_data(server
, 30), len
);
234 ncp_unlock_server(server
);
238 int ncp_get_directory_info(struct ncp_server
* server
, __u8 n
,
239 struct ncp_volume_info
* target
) {
243 ncp_init_request_s(server
, 45);
244 ncp_add_byte(server
, n
);
246 if ((result
= ncp_request(server
, 22)) != 0) {
249 target
->total_blocks
= ncp_reply_dword_lh(server
, 0);
250 target
->free_blocks
= ncp_reply_dword_lh(server
, 4);
251 target
->purgeable_blocks
= 0;
252 target
->not_yet_purgeable_blocks
= 0;
253 target
->total_dir_entries
= ncp_reply_dword_lh(server
, 8);
254 target
->available_dir_entries
= ncp_reply_dword_lh(server
, 12);
255 target
->sectors_per_block
= ncp_reply_byte(server
, 20);
257 memset(&(target
->volume_name
), 0, sizeof(target
->volume_name
));
260 len
= ncp_reply_byte(server
, 21);
261 if (len
> NCP_VOLNAME_LEN
) {
262 DPRINTK("ncpfs: volume name too long: %d\n", len
);
265 memcpy(&(target
->volume_name
), ncp_reply_data(server
, 22), len
);
268 ncp_unlock_server(server
);
273 ncp_close_file(struct ncp_server
*server
, const char *file_id
)
277 ncp_init_request(server
);
278 ncp_add_byte(server
, 0);
279 ncp_add_mem(server
, file_id
, 6);
281 result
= ncp_request(server
, 66);
282 ncp_unlock_server(server
);
287 ncp_make_closed(struct inode
*inode
)
292 mutex_lock(&NCP_FINFO(inode
)->open_mutex
);
293 if (atomic_read(&NCP_FINFO(inode
)->opened
) == 1) {
294 atomic_set(&NCP_FINFO(inode
)->opened
, 0);
295 err
= ncp_close_file(NCP_SERVER(inode
), NCP_FINFO(inode
)->file_handle
);
298 PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n",
299 NCP_FINFO(inode
)->volNumber
,
300 NCP_FINFO(inode
)->dirEntNum
, err
);
302 mutex_unlock(&NCP_FINFO(inode
)->open_mutex
);
306 static void ncp_add_handle_path(struct ncp_server
*server
, __u8 vol_num
,
307 __le32 dir_base
, int have_dir_base
,
310 ncp_add_byte(server
, vol_num
);
311 ncp_add_dword(server
, dir_base
);
312 if (have_dir_base
!= 0) {
313 ncp_add_byte(server
, 1); /* dir_base */
315 ncp_add_byte(server
, 0xff); /* no handle */
318 ncp_add_byte(server
, 1); /* 1 component */
319 ncp_add_pstring(server
, path
);
321 ncp_add_byte(server
, 0);
325 int ncp_dirhandle_alloc(struct ncp_server
* server
, __u8 volnum
, __le32 dirent
,
329 ncp_init_request(server
);
330 ncp_add_byte(server
, 12); /* subfunction */
331 ncp_add_byte(server
, NW_NS_DOS
);
332 ncp_add_byte(server
, 0);
333 ncp_add_word(server
, 0);
334 ncp_add_handle_path(server
, volnum
, dirent
, 1, NULL
);
335 if ((result
= ncp_request(server
, 87)) == 0) {
336 *dirhandle
= ncp_reply_byte(server
, 0);
338 ncp_unlock_server(server
);
342 int ncp_dirhandle_free(struct ncp_server
* server
, __u8 dirhandle
) {
345 ncp_init_request_s(server
, 20);
346 ncp_add_byte(server
, dirhandle
);
347 result
= ncp_request(server
, 22);
348 ncp_unlock_server(server
);
352 void ncp_extract_file_info(const void *structure
, struct nw_info_struct
*target
)
354 const __u8
*name_len
;
355 const int info_struct_size
= offsetof(struct nw_info_struct
, nameLen
);
357 memcpy(target
, structure
, info_struct_size
);
358 name_len
= structure
+ info_struct_size
;
359 target
->nameLen
= *name_len
;
360 memcpy(target
->entryName
, name_len
+ 1, *name_len
);
361 target
->entryName
[*name_len
] = '\0';
362 target
->volNumber
= le32_to_cpu(target
->volNumber
);
366 #ifdef CONFIG_NCPFS_NFS_NS
367 static inline void ncp_extract_nfs_info(const unsigned char *structure
,
368 struct nw_nfs_info
*target
)
370 target
->mode
= DVAL_LH(structure
);
371 target
->rdev
= DVAL_LH(structure
+ 8);
375 int ncp_obtain_nfs_info(struct ncp_server
*server
,
376 struct nw_info_struct
*target
)
380 #ifdef CONFIG_NCPFS_NFS_NS
381 __u32 volnum
= target
->volNumber
;
383 if (ncp_is_nfs_extras(server
, volnum
)) {
384 ncp_init_request(server
);
385 ncp_add_byte(server
, 19); /* subfunction */
386 ncp_add_byte(server
, server
->name_space
[volnum
]);
387 ncp_add_byte(server
, NW_NS_NFS
);
388 ncp_add_byte(server
, 0);
389 ncp_add_byte(server
, volnum
);
390 ncp_add_dword(server
, target
->dirEntNum
);
391 /* We must retrieve both nlinks and rdev, otherwise some server versions
392 report zeroes instead of valid data */
393 ncp_add_dword_lh(server
, NSIBM_NFS_MODE
| NSIBM_NFS_NLINKS
| NSIBM_NFS_RDEV
);
395 if ((result
= ncp_request(server
, 87)) == 0) {
396 ncp_extract_nfs_info(ncp_reply_data(server
, 0), &target
->nfs
);
398 "ncp_obtain_nfs_info: (%s) mode=0%o, rdev=0x%x\n",
399 target
->entryName
, target
->nfs
.mode
,
402 target
->nfs
.mode
= 0;
403 target
->nfs
.rdev
= 0;
405 ncp_unlock_server(server
);
410 target
->nfs
.mode
= 0;
411 target
->nfs
.rdev
= 0;
417 * Returns information for a (one-component) name relative to
418 * the specified directory.
420 int ncp_obtain_info(struct ncp_server
*server
, struct inode
*dir
, const char *path
,
421 struct nw_info_struct
*target
)
423 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
424 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
427 if (target
== NULL
) {
428 printk(KERN_ERR
"ncp_obtain_info: invalid call\n");
431 ncp_init_request(server
);
432 ncp_add_byte(server
, 6); /* subfunction */
433 ncp_add_byte(server
, server
->name_space
[volnum
]);
434 ncp_add_byte(server
, server
->name_space
[volnum
]); /* N.B. twice ?? */
435 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
436 ncp_add_dword(server
, RIM_ALL
);
437 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
439 if ((result
= ncp_request(server
, 87)) != 0)
441 ncp_extract_file_info(ncp_reply_data(server
, 0), target
);
442 ncp_unlock_server(server
);
444 result
= ncp_obtain_nfs_info(server
, target
);
448 ncp_unlock_server(server
);
452 #ifdef CONFIG_NCPFS_NFS_NS
454 ncp_obtain_DOS_dir_base(struct ncp_server
*server
,
455 __u8 ns
, __u8 volnum
, __le32 dirent
,
456 const char *path
, /* At most 1 component */
457 __le32
*DOS_dir_base
)
461 ncp_init_request(server
);
462 ncp_add_byte(server
, 6); /* subfunction */
463 ncp_add_byte(server
, ns
);
464 ncp_add_byte(server
, ns
);
465 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
466 ncp_add_dword(server
, RIM_DIRECTORY
);
467 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
469 if ((result
= ncp_request(server
, 87)) == 0)
471 if (DOS_dir_base
) *DOS_dir_base
=ncp_reply_dword(server
, 0x34);
473 ncp_unlock_server(server
);
476 #endif /* CONFIG_NCPFS_NFS_NS */
479 ncp_get_known_namespace(struct ncp_server
*server
, __u8 volume
)
481 #if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS)
486 ncp_init_request(server
);
487 ncp_add_byte(server
, 24); /* Subfunction: Get Name Spaces Loaded */
488 ncp_add_word(server
, 0);
489 ncp_add_byte(server
, volume
);
491 if ((result
= ncp_request(server
, 87)) != 0) {
492 ncp_unlock_server(server
);
493 return NW_NS_DOS
; /* not result ?? */
497 no_namespaces
= ncp_reply_le16(server
, 0);
498 namespace = ncp_reply_data(server
, 2);
500 while (no_namespaces
> 0) {
501 DPRINTK("get_namespaces: found %d on %d\n", *namespace, volume
);
503 #ifdef CONFIG_NCPFS_NFS_NS
504 if ((*namespace == NW_NS_NFS
) && !(server
->m
.flags
&NCP_MOUNT_NO_NFS
))
509 #endif /* CONFIG_NCPFS_NFS_NS */
510 #ifdef CONFIG_NCPFS_OS2_NS
511 if ((*namespace == NW_NS_OS2
) && !(server
->m
.flags
&NCP_MOUNT_NO_OS2
))
515 #endif /* CONFIG_NCPFS_OS2_NS */
519 ncp_unlock_server(server
);
521 #else /* neither OS2 nor NFS - only DOS */
523 #endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */
527 ncp_update_known_namespace(struct ncp_server
*server
, __u8 volume
, int *ret_ns
)
529 int ns
= ncp_get_known_namespace(server
, volume
);
534 DPRINTK("lookup_vol: namespace[%d] = %d\n",
535 volume
, server
->name_space
[volume
]);
537 if (server
->name_space
[volume
] == ns
)
539 server
->name_space
[volume
] = ns
;
544 ncp_ObtainSpecificDirBase(struct ncp_server
*server
,
545 __u8 nsSrc
, __u8 nsDst
, __u8 vol_num
, __le32 dir_base
,
546 const char *path
, /* At most 1 component */
547 __le32
*dirEntNum
, __le32
*DosDirNum
)
551 ncp_init_request(server
);
552 ncp_add_byte(server
, 6); /* subfunction */
553 ncp_add_byte(server
, nsSrc
);
554 ncp_add_byte(server
, nsDst
);
555 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
556 ncp_add_dword(server
, RIM_ALL
);
557 ncp_add_handle_path(server
, vol_num
, dir_base
, 1, path
);
559 if ((result
= ncp_request(server
, 87)) != 0)
561 ncp_unlock_server(server
);
566 *dirEntNum
= ncp_reply_dword(server
, 0x30);
568 *DosDirNum
= ncp_reply_dword(server
, 0x34);
569 ncp_unlock_server(server
);
574 ncp_mount_subdir(struct ncp_server
*server
,
575 __u8 volNumber
, __u8 srcNS
, __le32 dirEntNum
,
576 __u32
* volume
, __le32
* newDirEnt
, __le32
* newDosEnt
)
581 ncp_update_known_namespace(server
, volNumber
, &dstNS
);
582 if ((result
= ncp_ObtainSpecificDirBase(server
, srcNS
, dstNS
, volNumber
,
583 dirEntNum
, NULL
, newDirEnt
, newDosEnt
)) != 0)
588 server
->m
.mounted_vol
[1] = 0;
589 server
->m
.mounted_vol
[0] = 'X';
594 ncp_get_volume_root(struct ncp_server
*server
,
595 const char *volname
, __u32
* volume
, __le32
* dirent
, __le32
* dosdirent
)
599 DPRINTK("ncp_get_volume_root: looking up vol %s\n", volname
);
601 ncp_init_request(server
);
602 ncp_add_byte(server
, 22); /* Subfunction: Generate dir handle */
603 ncp_add_byte(server
, 0); /* DOS namespace */
604 ncp_add_byte(server
, 0); /* reserved */
605 ncp_add_byte(server
, 0); /* reserved */
606 ncp_add_byte(server
, 0); /* reserved */
608 ncp_add_byte(server
, 0); /* faked volume number */
609 ncp_add_dword(server
, 0); /* faked dir_base */
610 ncp_add_byte(server
, 0xff); /* Don't have a dir_base */
611 ncp_add_byte(server
, 1); /* 1 path component */
612 ncp_add_pstring(server
, volname
);
614 if ((result
= ncp_request(server
, 87)) != 0) {
615 ncp_unlock_server(server
);
618 *dirent
= *dosdirent
= ncp_reply_dword(server
, 4);
619 *volume
= ncp_reply_byte(server
, 8);
620 ncp_unlock_server(server
);
625 ncp_lookup_volume(struct ncp_server
*server
,
626 const char *volname
, struct nw_info_struct
*target
)
630 memset(target
, 0, sizeof(*target
));
631 result
= ncp_get_volume_root(server
, volname
,
632 &target
->volNumber
, &target
->dirEntNum
, &target
->DosDirNum
);
636 ncp_update_known_namespace(server
, target
->volNumber
, NULL
);
637 target
->nameLen
= strlen(volname
);
638 memcpy(target
->entryName
, volname
, target
->nameLen
+1);
639 target
->attributes
= aDIR
;
640 /* set dates to Jan 1, 1986 00:00 */
641 target
->creationTime
= target
->modifyTime
= cpu_to_le16(0x0000);
642 target
->creationDate
= target
->modifyDate
= target
->lastAccessDate
= cpu_to_le16(0x0C21);
643 target
->nfs
.mode
= 0;
647 int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server
*server
,
651 const struct nw_modify_dos_info
*info
)
653 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
654 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
657 ncp_init_request(server
);
658 ncp_add_byte(server
, 7); /* subfunction */
659 ncp_add_byte(server
, server
->name_space
[volnum
]);
660 ncp_add_byte(server
, 0); /* reserved */
661 ncp_add_word(server
, cpu_to_le16(0x8006)); /* search attribs: all */
663 ncp_add_dword(server
, info_mask
);
664 ncp_add_mem(server
, info
, sizeof(*info
));
665 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
667 result
= ncp_request(server
, 87);
668 ncp_unlock_server(server
);
672 int ncp_modify_file_or_subdir_dos_info(struct ncp_server
*server
,
675 const struct nw_modify_dos_info
*info
)
677 return ncp_modify_file_or_subdir_dos_info_path(server
, dir
, NULL
,
681 #ifdef CONFIG_NCPFS_NFS_NS
682 int ncp_modify_nfs_info(struct ncp_server
*server
, __u8 volnum
, __le32 dirent
,
683 __u32 mode
, __u32 rdev
)
688 ncp_init_request(server
);
689 if (server
->name_space
[volnum
] == NW_NS_NFS
) {
690 ncp_add_byte(server
, 25); /* subfunction */
691 ncp_add_byte(server
, server
->name_space
[volnum
]);
692 ncp_add_byte(server
, NW_NS_NFS
);
693 ncp_add_byte(server
, volnum
);
694 ncp_add_dword(server
, dirent
);
695 /* we must always operate on both nlinks and rdev, otherwise
697 ncp_add_dword_lh(server
, NSIBM_NFS_MODE
| NSIBM_NFS_NLINKS
| NSIBM_NFS_RDEV
);
698 ncp_add_dword_lh(server
, mode
);
699 ncp_add_dword_lh(server
, 1); /* nlinks */
700 ncp_add_dword_lh(server
, rdev
);
701 result
= ncp_request(server
, 87);
703 ncp_unlock_server(server
);
710 ncp_DeleteNSEntry(struct ncp_server
*server
,
711 __u8 have_dir_base
, __u8 volnum
, __le32 dirent
,
712 const char* name
, __u8 ns
, __le16 attr
)
716 ncp_init_request(server
);
717 ncp_add_byte(server
, 8); /* subfunction */
718 ncp_add_byte(server
, ns
);
719 ncp_add_byte(server
, 0); /* reserved */
720 ncp_add_word(server
, attr
); /* search attribs: all */
721 ncp_add_handle_path(server
, volnum
, dirent
, have_dir_base
, name
);
723 result
= ncp_request(server
, 87);
724 ncp_unlock_server(server
);
729 ncp_del_file_or_subdir2(struct ncp_server
*server
,
730 struct dentry
*dentry
)
732 struct inode
*inode
= dentry
->d_inode
;
737 return 0xFF; /* Any error */
739 volnum
= NCP_FINFO(inode
)->volNumber
;
740 dirent
= NCP_FINFO(inode
)->DosDirNum
;
741 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, NULL
, NW_NS_DOS
, cpu_to_le16(0x8006));
745 ncp_del_file_or_subdir(struct ncp_server
*server
,
746 struct inode
*dir
, const char *name
)
748 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
749 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
752 name_space
= server
->name_space
[volnum
];
753 #ifdef CONFIG_NCPFS_NFS_NS
754 if (name_space
== NW_NS_NFS
)
758 result
=ncp_obtain_DOS_dir_base(server
, name_space
, volnum
, dirent
, name
, &dirent
);
759 if (result
) return result
;
761 name_space
= NW_NS_DOS
;
763 #endif /* CONFIG_NCPFS_NFS_NS */
764 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, name
, name_space
, cpu_to_le16(0x8006));
767 static inline void ConvertToNWfromDWORD(__u16 v0
, __u16 v1
, __u8 ret
[6])
769 __le16
*dest
= (__le16
*) ret
;
770 dest
[1] = cpu_to_le16(v0
);
771 dest
[2] = cpu_to_le16(v1
);
772 dest
[0] = cpu_to_le16(v0
+ 1);
776 /* If both dir and name are NULL, then in target there's already a
777 looked-up entry that wants to be opened. */
778 int ncp_open_create_file_or_subdir(struct ncp_server
*server
,
779 struct inode
*dir
, const char *name
,
780 int open_create_mode
,
781 __le32 create_attributes
,
782 __le16 desired_acc_rights
,
783 struct ncp_entry_info
*target
)
785 __le16 search_attribs
= cpu_to_le16(0x0006);
790 volnum
= NCP_FINFO(dir
)->volNumber
;
791 dirent
= NCP_FINFO(dir
)->dirEntNum
;
793 if ((create_attributes
& aDIR
) != 0) {
794 search_attribs
|= cpu_to_le16(0x8000);
796 ncp_init_request(server
);
797 ncp_add_byte(server
, 1); /* subfunction */
798 ncp_add_byte(server
, server
->name_space
[volnum
]);
799 ncp_add_byte(server
, open_create_mode
);
800 ncp_add_word(server
, search_attribs
);
801 ncp_add_dword(server
, RIM_ALL
);
802 ncp_add_dword(server
, create_attributes
);
803 /* The desired acc rights seem to be the inherited rights mask
805 ncp_add_word(server
, desired_acc_rights
);
806 ncp_add_handle_path(server
, volnum
, dirent
, 1, name
);
808 if ((result
= ncp_request(server
, 87)) != 0)
810 if (!(create_attributes
& aDIR
))
813 /* in target there's a new finfo to fill */
814 ncp_extract_file_info(ncp_reply_data(server
, 6), &(target
->i
));
815 target
->volume
= target
->i
.volNumber
;
816 ConvertToNWfromDWORD(ncp_reply_le16(server
, 0),
817 ncp_reply_le16(server
, 2),
818 target
->file_handle
);
820 ncp_unlock_server(server
);
822 (void)ncp_obtain_nfs_info(server
, &(target
->i
));
826 ncp_unlock_server(server
);
831 ncp_initialize_search(struct ncp_server
*server
, struct inode
*dir
,
832 struct nw_search_sequence
*target
)
834 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
835 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
838 ncp_init_request(server
);
839 ncp_add_byte(server
, 2); /* subfunction */
840 ncp_add_byte(server
, server
->name_space
[volnum
]);
841 ncp_add_byte(server
, 0); /* reserved */
842 ncp_add_handle_path(server
, volnum
, dirent
, 1, NULL
);
844 result
= ncp_request(server
, 87);
847 memcpy(target
, ncp_reply_data(server
, 0), sizeof(*target
));
850 ncp_unlock_server(server
);
854 int ncp_search_for_fileset(struct ncp_server
*server
,
855 struct nw_search_sequence
*seq
,
865 ncp_init_request(server
);
866 ncp_add_byte(server
, 20);
867 ncp_add_byte(server
, server
->name_space
[seq
->volNumber
]);
868 ncp_add_byte(server
, 0); /* datastream */
869 ncp_add_word(server
, cpu_to_le16(0x8006));
870 ncp_add_dword(server
, RIM_ALL
);
871 ncp_add_word(server
, cpu_to_le16(32767)); /* max returned items */
872 ncp_add_mem(server
, seq
, 9);
873 #ifdef CONFIG_NCPFS_NFS_NS
874 if (server
->name_space
[seq
->volNumber
] == NW_NS_NFS
) {
875 ncp_add_byte(server
, 0); /* 0 byte pattern */
879 ncp_add_byte(server
, 2); /* 2 byte pattern */
880 ncp_add_byte(server
, 0xff); /* following is a wildcard */
881 ncp_add_byte(server
, '*');
883 result
= ncp_request2(server
, 87, buffer
, bufsize
);
885 ncp_unlock_server(server
);
888 if (server
->ncp_reply_size
< 12) {
889 ncp_unlock_server(server
);
892 *rsize
= server
->ncp_reply_size
- 12;
893 ncp_unlock_server(server
);
894 buffer
= buffer
+ sizeof(struct ncp_reply_header
);
896 *cnt
= WVAL_LH(buffer
+ 10);
897 *more
= BVAL(buffer
+ 9);
898 memcpy(seq
, buffer
, 9);
903 ncp_RenameNSEntry(struct ncp_server
*server
,
904 struct inode
*old_dir
, const char *old_name
, __le16 old_type
,
905 struct inode
*new_dir
, const char *new_name
)
907 int result
= -EINVAL
;
909 if ((old_dir
== NULL
) || (old_name
== NULL
) ||
910 (new_dir
== NULL
) || (new_name
== NULL
))
913 ncp_init_request(server
);
914 ncp_add_byte(server
, 4); /* subfunction */
915 ncp_add_byte(server
, server
->name_space
[NCP_FINFO(old_dir
)->volNumber
]);
916 ncp_add_byte(server
, 1); /* rename flag */
917 ncp_add_word(server
, old_type
); /* search attributes */
919 /* source Handle Path */
920 ncp_add_byte(server
, NCP_FINFO(old_dir
)->volNumber
);
921 ncp_add_dword(server
, NCP_FINFO(old_dir
)->dirEntNum
);
922 ncp_add_byte(server
, 1);
923 ncp_add_byte(server
, 1); /* 1 source component */
925 /* dest Handle Path */
926 ncp_add_byte(server
, NCP_FINFO(new_dir
)->volNumber
);
927 ncp_add_dword(server
, NCP_FINFO(new_dir
)->dirEntNum
);
928 ncp_add_byte(server
, 1);
929 ncp_add_byte(server
, 1); /* 1 destination component */
931 /* source path string */
932 ncp_add_pstring(server
, old_name
);
933 /* dest path string */
934 ncp_add_pstring(server
, new_name
);
936 result
= ncp_request(server
, 87);
937 ncp_unlock_server(server
);
942 int ncp_ren_or_mov_file_or_subdir(struct ncp_server
*server
,
943 struct inode
*old_dir
, const char *old_name
,
944 struct inode
*new_dir
, const char *new_name
)
947 __le16 old_type
= cpu_to_le16(0x06);
949 /* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */
950 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
952 if (result
== 0xFF) /* File Not Found, try directory */
954 old_type
= cpu_to_le16(0x16);
955 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
958 if (result
!= 0x92) return result
; /* All except NO_FILES_RENAMED */
959 result
= ncp_del_file_or_subdir(server
, new_dir
, new_name
);
960 if (result
!= 0) return -EACCES
;
961 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
967 /* We have to transfer to/from user space */
969 ncp_read_kernel(struct ncp_server
*server
, const char *file_id
,
970 __u32 offset
, __u16 to_read
, char *target
, int *bytes_read
)
975 ncp_init_request(server
);
976 ncp_add_byte(server
, 0);
977 ncp_add_mem(server
, file_id
, 6);
978 ncp_add_be32(server
, offset
);
979 ncp_add_be16(server
, to_read
);
981 if ((result
= ncp_request(server
, 72)) != 0) {
984 *bytes_read
= ncp_reply_be16(server
, 0);
985 source
= ncp_reply_data(server
, 2 + (offset
& 1));
987 memcpy(target
, source
, *bytes_read
);
989 ncp_unlock_server(server
);
993 /* There is a problem... egrep and some other silly tools do:
994 x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768);
995 read(<ncpfs fd>, x, 32768);
996 Now copying read result by copy_to_user causes pagefault. This pagefault
997 could not be handled because of server was locked due to read. So we have
998 to use temporary buffer. So ncp_unlock_server must be done before
999 copy_to_user (and for write, copy_from_user must be done before
1000 ncp_init_request... same applies for send raw packet ioctl). Because of
1001 file is normally read in bigger chunks, caller provides kmalloced
1002 (vmalloced) chunk of memory with size >= to_read...
1005 ncp_read_bounce(struct ncp_server
*server
, const char *file_id
,
1006 __u32 offset
, __u16 to_read
, char __user
*target
, int *bytes_read
,
1007 void* bounce
, __u32 bufsize
)
1011 ncp_init_request(server
);
1012 ncp_add_byte(server
, 0);
1013 ncp_add_mem(server
, file_id
, 6);
1014 ncp_add_be32(server
, offset
);
1015 ncp_add_be16(server
, to_read
);
1016 result
= ncp_request2(server
, 72, bounce
, bufsize
);
1017 ncp_unlock_server(server
);
1019 int len
= get_unaligned_be16((char *)bounce
+
1020 sizeof(struct ncp_reply_header
));
1022 if (len
<= to_read
) {
1025 source
= (char*)bounce
+
1026 sizeof(struct ncp_reply_header
) + 2 +
1030 if (copy_to_user(target
, source
, len
))
1038 ncp_write_kernel(struct ncp_server
*server
, const char *file_id
,
1039 __u32 offset
, __u16 to_write
,
1040 const char *source
, int *bytes_written
)
1044 ncp_init_request(server
);
1045 ncp_add_byte(server
, 0);
1046 ncp_add_mem(server
, file_id
, 6);
1047 ncp_add_be32(server
, offset
);
1048 ncp_add_be16(server
, to_write
);
1049 ncp_add_mem(server
, source
, to_write
);
1051 if ((result
= ncp_request(server
, 73)) == 0)
1052 *bytes_written
= to_write
;
1053 ncp_unlock_server(server
);
1057 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
1059 ncp_LogPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
1060 __u8 locktype
, __u32 offset
, __u32 length
, __u16 timeout
)
1064 ncp_init_request(server
);
1065 ncp_add_byte(server
, locktype
);
1066 ncp_add_mem(server
, file_id
, 6);
1067 ncp_add_be32(server
, offset
);
1068 ncp_add_be32(server
, length
);
1069 ncp_add_be16(server
, timeout
);
1071 if ((result
= ncp_request(server
, 0x1A)) != 0)
1073 ncp_unlock_server(server
);
1076 ncp_unlock_server(server
);
1081 ncp_ClearPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
1082 __u32 offset
, __u32 length
)
1086 ncp_init_request(server
);
1087 ncp_add_byte(server
, 0); /* who knows... lanalyzer says that */
1088 ncp_add_mem(server
, file_id
, 6);
1089 ncp_add_be32(server
, offset
);
1090 ncp_add_be32(server
, length
);
1092 if ((result
= ncp_request(server
, 0x1E)) != 0)
1094 ncp_unlock_server(server
);
1097 ncp_unlock_server(server
);
1100 #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
1102 #ifdef CONFIG_NCPFS_NLS
1103 /* This are the NLS conversion routines with inspirations and code parts
1104 * from the vfat file system and hints from Petr Vandrovec.
1108 ncp__io2vol(struct ncp_server
*server
, unsigned char *vname
, unsigned int *vlen
,
1109 const unsigned char *iname
, unsigned int ilen
, int cc
)
1111 struct nls_table
*in
= server
->nls_io
;
1112 struct nls_table
*out
= server
->nls_vol
;
1113 unsigned char *vname_start
;
1114 unsigned char *vname_end
;
1115 const unsigned char *iname_end
;
1117 iname_end
= iname
+ ilen
;
1118 vname_start
= vname
;
1119 vname_end
= vname
+ *vlen
- 1;
1121 while (iname
< iname_end
) {
1125 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1129 k
= utf8_to_utf32(iname
, iname_end
- iname
, &u
);
1130 if (k
< 0 || u
> MAX_WCHAR_T
)
1135 if (*iname
== NCP_ESC
) {
1138 if (iname_end
- iname
< 5)
1142 for (k
= 1; k
< 5; k
++) {
1145 nc
= iname
[k
] - '0';
1147 nc
-= 'A' - '0' - 10;
1148 if ((nc
< 10) || (nc
> 15)) {
1152 ec
= (ec
<< 4) | nc
;
1157 if ( (chl
= in
->char2uni(iname
, iname_end
- iname
, &ec
)) < 0)
1163 /* unitoupper should be here! */
1165 chl
= out
->uni2char(ec
, vname
, vname_end
- vname
);
1169 /* this is wrong... */
1173 for (chi
= 0; chi
< chl
; chi
++){
1174 vname
[chi
] = ncp_toupper(out
, vname
[chi
]);
1181 *vlen
= vname
- vname_start
;
1186 ncp__vol2io(struct ncp_server
*server
, unsigned char *iname
, unsigned int *ilen
,
1187 const unsigned char *vname
, unsigned int vlen
, int cc
)
1189 struct nls_table
*in
= server
->nls_vol
;
1190 struct nls_table
*out
= server
->nls_io
;
1191 const unsigned char *vname_end
;
1192 unsigned char *iname_start
;
1193 unsigned char *iname_end
;
1194 unsigned char *vname_cc
;
1202 /* this is wrong! */
1203 vname_cc
= kmalloc(vlen
, GFP_KERNEL
);
1206 for (i
= 0; i
< vlen
; i
++)
1207 vname_cc
[i
] = ncp_tolower(in
, vname
[i
]);
1211 iname_start
= iname
;
1212 iname_end
= iname
+ *ilen
- 1;
1213 vname_end
= vname
+ vlen
;
1215 while (vname
< vname_end
) {
1219 if ( (chl
= in
->char2uni(vname
, vname_end
- vname
, &ec
)) < 0) {
1225 /* unitolower should be here! */
1227 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1230 k
= utf32_to_utf8(ec
, iname
, iname_end
- iname
);
1232 err
= -ENAMETOOLONG
;
1237 if ( (chl
= out
->uni2char(ec
, iname
, iname_end
- iname
)) >= 0) {
1242 if (iname_end
- iname
< 5) {
1243 err
= -ENAMETOOLONG
;
1247 for (k
= 4; k
> 0; k
--) {
1250 v
= (ec
& 0xF) + '0';
1263 *ilen
= iname
- iname_start
;
1274 ncp__io2vol(unsigned char *vname
, unsigned int *vlen
,
1275 const unsigned char *iname
, unsigned int ilen
, int cc
)
1280 return -ENAMETOOLONG
;
1283 for (i
= 0; i
< ilen
; i
++) {
1284 *vname
= toupper(*iname
);
1289 memmove(vname
, iname
, ilen
);
1299 ncp__vol2io(unsigned char *iname
, unsigned int *ilen
,
1300 const unsigned char *vname
, unsigned int vlen
, int cc
)
1305 return -ENAMETOOLONG
;
1308 for (i
= 0; i
< vlen
; i
++) {
1309 *iname
= tolower(*vname
);
1314 memmove(iname
, vname
, vlen
);