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
12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
16 static inline void assert_server_locked(struct ncp_server
*server
)
18 if (server
->lock
== 0) {
19 ncp_dbg(1, "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 ncp_dbg(1, "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 ncp_dbg(1, "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 ncp_dbg(1, "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 ncp_vdbg("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
);
397 ncp_dbg(1, "(%s) mode=0%o, rdev=0x%x\n",
398 target
->entryName
, target
->nfs
.mode
,
401 target
->nfs
.mode
= 0;
402 target
->nfs
.rdev
= 0;
404 ncp_unlock_server(server
);
409 target
->nfs
.mode
= 0;
410 target
->nfs
.rdev
= 0;
416 * Returns information for a (one-component) name relative to
417 * the specified directory.
419 int ncp_obtain_info(struct ncp_server
*server
, struct inode
*dir
, const char *path
,
420 struct nw_info_struct
*target
)
422 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
423 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
426 if (target
== NULL
) {
427 pr_err("%s: invalid call\n", __func__
);
430 ncp_init_request(server
);
431 ncp_add_byte(server
, 6); /* subfunction */
432 ncp_add_byte(server
, server
->name_space
[volnum
]);
433 ncp_add_byte(server
, server
->name_space
[volnum
]); /* N.B. twice ?? */
434 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
435 ncp_add_dword(server
, RIM_ALL
);
436 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
438 if ((result
= ncp_request(server
, 87)) != 0)
440 ncp_extract_file_info(ncp_reply_data(server
, 0), target
);
441 ncp_unlock_server(server
);
443 result
= ncp_obtain_nfs_info(server
, target
);
447 ncp_unlock_server(server
);
451 #ifdef CONFIG_NCPFS_NFS_NS
453 ncp_obtain_DOS_dir_base(struct ncp_server
*server
,
454 __u8 ns
, __u8 volnum
, __le32 dirent
,
455 const char *path
, /* At most 1 component */
456 __le32
*DOS_dir_base
)
460 ncp_init_request(server
);
461 ncp_add_byte(server
, 6); /* subfunction */
462 ncp_add_byte(server
, ns
);
463 ncp_add_byte(server
, ns
);
464 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
465 ncp_add_dword(server
, RIM_DIRECTORY
);
466 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
468 if ((result
= ncp_request(server
, 87)) == 0)
470 if (DOS_dir_base
) *DOS_dir_base
=ncp_reply_dword(server
, 0x34);
472 ncp_unlock_server(server
);
475 #endif /* CONFIG_NCPFS_NFS_NS */
478 ncp_get_known_namespace(struct ncp_server
*server
, __u8 volume
)
480 #if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS)
485 ncp_init_request(server
);
486 ncp_add_byte(server
, 24); /* Subfunction: Get Name Spaces Loaded */
487 ncp_add_word(server
, 0);
488 ncp_add_byte(server
, volume
);
490 if ((result
= ncp_request(server
, 87)) != 0) {
491 ncp_unlock_server(server
);
492 return NW_NS_DOS
; /* not result ?? */
496 no_namespaces
= ncp_reply_le16(server
, 0);
497 namespace = ncp_reply_data(server
, 2);
499 while (no_namespaces
> 0) {
500 ncp_dbg(1, "found %d on %d\n", *namespace, volume
);
502 #ifdef CONFIG_NCPFS_NFS_NS
503 if ((*namespace == NW_NS_NFS
) && !(server
->m
.flags
&NCP_MOUNT_NO_NFS
))
508 #endif /* CONFIG_NCPFS_NFS_NS */
509 #ifdef CONFIG_NCPFS_OS2_NS
510 if ((*namespace == NW_NS_OS2
) && !(server
->m
.flags
&NCP_MOUNT_NO_OS2
))
514 #endif /* CONFIG_NCPFS_OS2_NS */
518 ncp_unlock_server(server
);
520 #else /* neither OS2 nor NFS - only DOS */
522 #endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */
526 ncp_update_known_namespace(struct ncp_server
*server
, __u8 volume
, int *ret_ns
)
528 int ns
= ncp_get_known_namespace(server
, volume
);
533 ncp_dbg(1, "namespace[%d] = %d\n", volume
, server
->name_space
[volume
]);
535 if (server
->name_space
[volume
] == ns
)
537 server
->name_space
[volume
] = ns
;
542 ncp_ObtainSpecificDirBase(struct ncp_server
*server
,
543 __u8 nsSrc
, __u8 nsDst
, __u8 vol_num
, __le32 dir_base
,
544 const char *path
, /* At most 1 component */
545 __le32
*dirEntNum
, __le32
*DosDirNum
)
549 ncp_init_request(server
);
550 ncp_add_byte(server
, 6); /* subfunction */
551 ncp_add_byte(server
, nsSrc
);
552 ncp_add_byte(server
, nsDst
);
553 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
554 ncp_add_dword(server
, RIM_ALL
);
555 ncp_add_handle_path(server
, vol_num
, dir_base
, 1, path
);
557 if ((result
= ncp_request(server
, 87)) != 0)
559 ncp_unlock_server(server
);
564 *dirEntNum
= ncp_reply_dword(server
, 0x30);
566 *DosDirNum
= ncp_reply_dword(server
, 0x34);
567 ncp_unlock_server(server
);
572 ncp_mount_subdir(struct ncp_server
*server
,
573 __u8 volNumber
, __u8 srcNS
, __le32 dirEntNum
,
574 __u32
* volume
, __le32
* newDirEnt
, __le32
* newDosEnt
)
579 ncp_update_known_namespace(server
, volNumber
, &dstNS
);
580 if ((result
= ncp_ObtainSpecificDirBase(server
, srcNS
, dstNS
, volNumber
,
581 dirEntNum
, NULL
, newDirEnt
, newDosEnt
)) != 0)
586 server
->m
.mounted_vol
[1] = 0;
587 server
->m
.mounted_vol
[0] = 'X';
592 ncp_get_volume_root(struct ncp_server
*server
,
593 const char *volname
, __u32
* volume
, __le32
* dirent
, __le32
* dosdirent
)
597 ncp_dbg(1, "looking up vol %s\n", volname
);
599 ncp_init_request(server
);
600 ncp_add_byte(server
, 22); /* Subfunction: Generate dir handle */
601 ncp_add_byte(server
, 0); /* DOS namespace */
602 ncp_add_byte(server
, 0); /* reserved */
603 ncp_add_byte(server
, 0); /* reserved */
604 ncp_add_byte(server
, 0); /* reserved */
606 ncp_add_byte(server
, 0); /* faked volume number */
607 ncp_add_dword(server
, 0); /* faked dir_base */
608 ncp_add_byte(server
, 0xff); /* Don't have a dir_base */
609 ncp_add_byte(server
, 1); /* 1 path component */
610 ncp_add_pstring(server
, volname
);
612 if ((result
= ncp_request(server
, 87)) != 0) {
613 ncp_unlock_server(server
);
616 *dirent
= *dosdirent
= ncp_reply_dword(server
, 4);
617 *volume
= ncp_reply_byte(server
, 8);
618 ncp_unlock_server(server
);
623 ncp_lookup_volume(struct ncp_server
*server
,
624 const char *volname
, struct nw_info_struct
*target
)
628 memset(target
, 0, sizeof(*target
));
629 result
= ncp_get_volume_root(server
, volname
,
630 &target
->volNumber
, &target
->dirEntNum
, &target
->DosDirNum
);
634 ncp_update_known_namespace(server
, target
->volNumber
, NULL
);
635 target
->nameLen
= strlen(volname
);
636 memcpy(target
->entryName
, volname
, target
->nameLen
+1);
637 target
->attributes
= aDIR
;
638 /* set dates to Jan 1, 1986 00:00 */
639 target
->creationTime
= target
->modifyTime
= cpu_to_le16(0x0000);
640 target
->creationDate
= target
->modifyDate
= target
->lastAccessDate
= cpu_to_le16(0x0C21);
641 target
->nfs
.mode
= 0;
645 int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server
*server
,
649 const struct nw_modify_dos_info
*info
)
651 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
652 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
655 ncp_init_request(server
);
656 ncp_add_byte(server
, 7); /* subfunction */
657 ncp_add_byte(server
, server
->name_space
[volnum
]);
658 ncp_add_byte(server
, 0); /* reserved */
659 ncp_add_word(server
, cpu_to_le16(0x8006)); /* search attribs: all */
661 ncp_add_dword(server
, info_mask
);
662 ncp_add_mem(server
, info
, sizeof(*info
));
663 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
665 result
= ncp_request(server
, 87);
666 ncp_unlock_server(server
);
670 int ncp_modify_file_or_subdir_dos_info(struct ncp_server
*server
,
673 const struct nw_modify_dos_info
*info
)
675 return ncp_modify_file_or_subdir_dos_info_path(server
, dir
, NULL
,
679 #ifdef CONFIG_NCPFS_NFS_NS
680 int ncp_modify_nfs_info(struct ncp_server
*server
, __u8 volnum
, __le32 dirent
,
681 __u32 mode
, __u32 rdev
)
686 ncp_init_request(server
);
687 if (server
->name_space
[volnum
] == NW_NS_NFS
) {
688 ncp_add_byte(server
, 25); /* subfunction */
689 ncp_add_byte(server
, server
->name_space
[volnum
]);
690 ncp_add_byte(server
, NW_NS_NFS
);
691 ncp_add_byte(server
, volnum
);
692 ncp_add_dword(server
, dirent
);
693 /* we must always operate on both nlinks and rdev, otherwise
695 ncp_add_dword_lh(server
, NSIBM_NFS_MODE
| NSIBM_NFS_NLINKS
| NSIBM_NFS_RDEV
);
696 ncp_add_dword_lh(server
, mode
);
697 ncp_add_dword_lh(server
, 1); /* nlinks */
698 ncp_add_dword_lh(server
, rdev
);
699 result
= ncp_request(server
, 87);
701 ncp_unlock_server(server
);
708 ncp_DeleteNSEntry(struct ncp_server
*server
,
709 __u8 have_dir_base
, __u8 volnum
, __le32 dirent
,
710 const char* name
, __u8 ns
, __le16 attr
)
714 ncp_init_request(server
);
715 ncp_add_byte(server
, 8); /* subfunction */
716 ncp_add_byte(server
, ns
);
717 ncp_add_byte(server
, 0); /* reserved */
718 ncp_add_word(server
, attr
); /* search attribs: all */
719 ncp_add_handle_path(server
, volnum
, dirent
, have_dir_base
, name
);
721 result
= ncp_request(server
, 87);
722 ncp_unlock_server(server
);
727 ncp_del_file_or_subdir2(struct ncp_server
*server
,
728 struct dentry
*dentry
)
730 struct inode
*inode
= d_inode(dentry
);
735 return 0xFF; /* Any error */
737 volnum
= NCP_FINFO(inode
)->volNumber
;
738 dirent
= NCP_FINFO(inode
)->DosDirNum
;
739 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, NULL
, NW_NS_DOS
, cpu_to_le16(0x8006));
743 ncp_del_file_or_subdir(struct ncp_server
*server
,
744 struct inode
*dir
, const char *name
)
746 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
747 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
750 name_space
= server
->name_space
[volnum
];
751 #ifdef CONFIG_NCPFS_NFS_NS
752 if (name_space
== NW_NS_NFS
)
756 result
=ncp_obtain_DOS_dir_base(server
, name_space
, volnum
, dirent
, name
, &dirent
);
757 if (result
) return result
;
759 name_space
= NW_NS_DOS
;
761 #endif /* CONFIG_NCPFS_NFS_NS */
762 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, name
, name_space
, cpu_to_le16(0x8006));
765 static inline void ConvertToNWfromDWORD(__u16 v0
, __u16 v1
, __u8 ret
[6])
767 __le16
*dest
= (__le16
*) ret
;
768 dest
[1] = cpu_to_le16(v0
);
769 dest
[2] = cpu_to_le16(v1
);
770 dest
[0] = cpu_to_le16(v0
+ 1);
774 /* If both dir and name are NULL, then in target there's already a
775 looked-up entry that wants to be opened. */
776 int ncp_open_create_file_or_subdir(struct ncp_server
*server
,
777 struct inode
*dir
, const char *name
,
778 int open_create_mode
,
779 __le32 create_attributes
,
780 __le16 desired_acc_rights
,
781 struct ncp_entry_info
*target
)
783 __le16 search_attribs
= cpu_to_le16(0x0006);
788 volnum
= NCP_FINFO(dir
)->volNumber
;
789 dirent
= NCP_FINFO(dir
)->dirEntNum
;
791 if ((create_attributes
& aDIR
) != 0) {
792 search_attribs
|= cpu_to_le16(0x8000);
794 ncp_init_request(server
);
795 ncp_add_byte(server
, 1); /* subfunction */
796 ncp_add_byte(server
, server
->name_space
[volnum
]);
797 ncp_add_byte(server
, open_create_mode
);
798 ncp_add_word(server
, search_attribs
);
799 ncp_add_dword(server
, RIM_ALL
);
800 ncp_add_dword(server
, create_attributes
);
801 /* The desired acc rights seem to be the inherited rights mask
803 ncp_add_word(server
, desired_acc_rights
);
804 ncp_add_handle_path(server
, volnum
, dirent
, 1, name
);
806 if ((result
= ncp_request(server
, 87)) != 0)
808 if (!(create_attributes
& aDIR
))
811 /* in target there's a new finfo to fill */
812 ncp_extract_file_info(ncp_reply_data(server
, 6), &(target
->i
));
813 target
->volume
= target
->i
.volNumber
;
814 ConvertToNWfromDWORD(ncp_reply_le16(server
, 0),
815 ncp_reply_le16(server
, 2),
816 target
->file_handle
);
818 ncp_unlock_server(server
);
820 (void)ncp_obtain_nfs_info(server
, &(target
->i
));
824 ncp_unlock_server(server
);
829 ncp_initialize_search(struct ncp_server
*server
, struct inode
*dir
,
830 struct nw_search_sequence
*target
)
832 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
833 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
836 ncp_init_request(server
);
837 ncp_add_byte(server
, 2); /* subfunction */
838 ncp_add_byte(server
, server
->name_space
[volnum
]);
839 ncp_add_byte(server
, 0); /* reserved */
840 ncp_add_handle_path(server
, volnum
, dirent
, 1, NULL
);
842 result
= ncp_request(server
, 87);
845 memcpy(target
, ncp_reply_data(server
, 0), sizeof(*target
));
848 ncp_unlock_server(server
);
852 int ncp_search_for_fileset(struct ncp_server
*server
,
853 struct nw_search_sequence
*seq
,
863 ncp_init_request(server
);
864 ncp_add_byte(server
, 20);
865 ncp_add_byte(server
, server
->name_space
[seq
->volNumber
]);
866 ncp_add_byte(server
, 0); /* datastream */
867 ncp_add_word(server
, cpu_to_le16(0x8006));
868 ncp_add_dword(server
, RIM_ALL
);
869 ncp_add_word(server
, cpu_to_le16(32767)); /* max returned items */
870 ncp_add_mem(server
, seq
, 9);
871 #ifdef CONFIG_NCPFS_NFS_NS
872 if (server
->name_space
[seq
->volNumber
] == NW_NS_NFS
) {
873 ncp_add_byte(server
, 0); /* 0 byte pattern */
877 ncp_add_byte(server
, 2); /* 2 byte pattern */
878 ncp_add_byte(server
, 0xff); /* following is a wildcard */
879 ncp_add_byte(server
, '*');
881 result
= ncp_request2(server
, 87, buffer
, bufsize
);
883 ncp_unlock_server(server
);
886 if (server
->ncp_reply_size
< 12) {
887 ncp_unlock_server(server
);
890 *rsize
= server
->ncp_reply_size
- 12;
891 ncp_unlock_server(server
);
892 buffer
= buffer
+ sizeof(struct ncp_reply_header
);
894 *cnt
= WVAL_LH(buffer
+ 10);
895 *more
= BVAL(buffer
+ 9);
896 memcpy(seq
, buffer
, 9);
901 ncp_RenameNSEntry(struct ncp_server
*server
,
902 struct inode
*old_dir
, const char *old_name
, __le16 old_type
,
903 struct inode
*new_dir
, const char *new_name
)
905 int result
= -EINVAL
;
907 if ((old_dir
== NULL
) || (old_name
== NULL
) ||
908 (new_dir
== NULL
) || (new_name
== NULL
))
911 ncp_init_request(server
);
912 ncp_add_byte(server
, 4); /* subfunction */
913 ncp_add_byte(server
, server
->name_space
[NCP_FINFO(old_dir
)->volNumber
]);
914 ncp_add_byte(server
, 1); /* rename flag */
915 ncp_add_word(server
, old_type
); /* search attributes */
917 /* source Handle Path */
918 ncp_add_byte(server
, NCP_FINFO(old_dir
)->volNumber
);
919 ncp_add_dword(server
, NCP_FINFO(old_dir
)->dirEntNum
);
920 ncp_add_byte(server
, 1);
921 ncp_add_byte(server
, 1); /* 1 source component */
923 /* dest Handle Path */
924 ncp_add_byte(server
, NCP_FINFO(new_dir
)->volNumber
);
925 ncp_add_dword(server
, NCP_FINFO(new_dir
)->dirEntNum
);
926 ncp_add_byte(server
, 1);
927 ncp_add_byte(server
, 1); /* 1 destination component */
929 /* source path string */
930 ncp_add_pstring(server
, old_name
);
931 /* dest path string */
932 ncp_add_pstring(server
, new_name
);
934 result
= ncp_request(server
, 87);
935 ncp_unlock_server(server
);
940 int ncp_ren_or_mov_file_or_subdir(struct ncp_server
*server
,
941 struct inode
*old_dir
, const char *old_name
,
942 struct inode
*new_dir
, const char *new_name
)
945 __le16 old_type
= cpu_to_le16(0x06);
947 /* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */
948 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
950 if (result
== 0xFF) /* File Not Found, try directory */
952 old_type
= cpu_to_le16(0x16);
953 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
956 if (result
!= 0x92) return result
; /* All except NO_FILES_RENAMED */
957 result
= ncp_del_file_or_subdir(server
, new_dir
, new_name
);
958 if (result
!= 0) return -EACCES
;
959 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
965 /* We have to transfer to/from user space */
967 ncp_read_kernel(struct ncp_server
*server
, const char *file_id
,
968 __u32 offset
, __u16 to_read
, char *target
, int *bytes_read
)
973 ncp_init_request(server
);
974 ncp_add_byte(server
, 0);
975 ncp_add_mem(server
, file_id
, 6);
976 ncp_add_be32(server
, offset
);
977 ncp_add_be16(server
, to_read
);
979 if ((result
= ncp_request(server
, 72)) != 0) {
982 *bytes_read
= ncp_reply_be16(server
, 0);
983 source
= ncp_reply_data(server
, 2 + (offset
& 1));
985 memcpy(target
, source
, *bytes_read
);
987 ncp_unlock_server(server
);
991 /* There is a problem... egrep and some other silly tools do:
992 x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768);
993 read(<ncpfs fd>, x, 32768);
994 Now copying read result by copy_to_user causes pagefault. This pagefault
995 could not be handled because of server was locked due to read. So we have
996 to use temporary buffer. So ncp_unlock_server must be done before
997 copy_to_user (and for write, copy_from_user must be done before
998 ncp_init_request... same applies for send raw packet ioctl). Because of
999 file is normally read in bigger chunks, caller provides kmalloced
1000 (vmalloced) chunk of memory with size >= to_read...
1003 ncp_read_bounce(struct ncp_server
*server
, const char *file_id
,
1004 __u32 offset
, __u16 to_read
, struct iov_iter
*to
,
1005 int *bytes_read
, void *bounce
, __u32 bufsize
)
1009 ncp_init_request(server
);
1010 ncp_add_byte(server
, 0);
1011 ncp_add_mem(server
, file_id
, 6);
1012 ncp_add_be32(server
, offset
);
1013 ncp_add_be16(server
, to_read
);
1014 result
= ncp_request2(server
, 72, bounce
, bufsize
);
1015 ncp_unlock_server(server
);
1017 int len
= get_unaligned_be16((char *)bounce
+
1018 sizeof(struct ncp_reply_header
));
1020 if (len
<= to_read
) {
1023 source
= (char*)bounce
+
1024 sizeof(struct ncp_reply_header
) + 2 +
1028 if (copy_to_iter(source
, len
, to
) != len
)
1036 ncp_write_kernel(struct ncp_server
*server
, const char *file_id
,
1037 __u32 offset
, __u16 to_write
,
1038 const char *source
, int *bytes_written
)
1042 ncp_init_request(server
);
1043 ncp_add_byte(server
, 0);
1044 ncp_add_mem(server
, file_id
, 6);
1045 ncp_add_be32(server
, offset
);
1046 ncp_add_be16(server
, to_write
);
1047 ncp_add_mem(server
, source
, to_write
);
1049 if ((result
= ncp_request(server
, 73)) == 0)
1050 *bytes_written
= to_write
;
1051 ncp_unlock_server(server
);
1055 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
1057 ncp_LogPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
1058 __u8 locktype
, __u32 offset
, __u32 length
, __u16 timeout
)
1062 ncp_init_request(server
);
1063 ncp_add_byte(server
, locktype
);
1064 ncp_add_mem(server
, file_id
, 6);
1065 ncp_add_be32(server
, offset
);
1066 ncp_add_be32(server
, length
);
1067 ncp_add_be16(server
, timeout
);
1069 if ((result
= ncp_request(server
, 0x1A)) != 0)
1071 ncp_unlock_server(server
);
1074 ncp_unlock_server(server
);
1079 ncp_ClearPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
1080 __u32 offset
, __u32 length
)
1084 ncp_init_request(server
);
1085 ncp_add_byte(server
, 0); /* who knows... lanalyzer says that */
1086 ncp_add_mem(server
, file_id
, 6);
1087 ncp_add_be32(server
, offset
);
1088 ncp_add_be32(server
, length
);
1090 if ((result
= ncp_request(server
, 0x1E)) != 0)
1092 ncp_unlock_server(server
);
1095 ncp_unlock_server(server
);
1098 #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
1100 #ifdef CONFIG_NCPFS_NLS
1101 /* This are the NLS conversion routines with inspirations and code parts
1102 * from the vfat file system and hints from Petr Vandrovec.
1106 ncp__io2vol(struct ncp_server
*server
, unsigned char *vname
, unsigned int *vlen
,
1107 const unsigned char *iname
, unsigned int ilen
, int cc
)
1109 struct nls_table
*in
= server
->nls_io
;
1110 struct nls_table
*out
= server
->nls_vol
;
1111 unsigned char *vname_start
;
1112 unsigned char *vname_end
;
1113 const unsigned char *iname_end
;
1115 iname_end
= iname
+ ilen
;
1116 vname_start
= vname
;
1117 vname_end
= vname
+ *vlen
- 1;
1119 while (iname
< iname_end
) {
1123 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1127 k
= utf8_to_utf32(iname
, iname_end
- iname
, &u
);
1128 if (k
< 0 || u
> MAX_WCHAR_T
)
1133 if (*iname
== NCP_ESC
) {
1136 if (iname_end
- iname
< 5)
1140 for (k
= 1; k
< 5; k
++) {
1143 nc
= iname
[k
] - '0';
1145 nc
-= 'A' - '0' - 10;
1146 if ((nc
< 10) || (nc
> 15)) {
1150 ec
= (ec
<< 4) | nc
;
1155 if ( (chl
= in
->char2uni(iname
, iname_end
- iname
, &ec
)) < 0)
1161 /* unitoupper should be here! */
1163 chl
= out
->uni2char(ec
, vname
, vname_end
- vname
);
1167 /* this is wrong... */
1171 for (chi
= 0; chi
< chl
; chi
++){
1172 vname
[chi
] = ncp_toupper(out
, vname
[chi
]);
1179 *vlen
= vname
- vname_start
;
1184 ncp__vol2io(struct ncp_server
*server
, unsigned char *iname
, unsigned int *ilen
,
1185 const unsigned char *vname
, unsigned int vlen
, int cc
)
1187 struct nls_table
*in
= server
->nls_vol
;
1188 struct nls_table
*out
= server
->nls_io
;
1189 const unsigned char *vname_end
;
1190 unsigned char *iname_start
;
1191 unsigned char *iname_end
;
1192 unsigned char *vname_cc
;
1200 /* this is wrong! */
1201 vname_cc
= kmalloc(vlen
, GFP_KERNEL
);
1204 for (i
= 0; i
< vlen
; i
++)
1205 vname_cc
[i
] = ncp_tolower(in
, vname
[i
]);
1209 iname_start
= iname
;
1210 iname_end
= iname
+ *ilen
- 1;
1211 vname_end
= vname
+ vlen
;
1213 while (vname
< vname_end
) {
1217 if ( (chl
= in
->char2uni(vname
, vname_end
- vname
, &ec
)) < 0) {
1223 /* unitolower should be here! */
1225 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1228 k
= utf32_to_utf8(ec
, iname
, iname_end
- iname
);
1230 err
= -ENAMETOOLONG
;
1235 if ( (chl
= out
->uni2char(ec
, iname
, iname_end
- iname
)) >= 0) {
1240 if (iname_end
- iname
< 5) {
1241 err
= -ENAMETOOLONG
;
1245 for (k
= 4; k
> 0; k
--) {
1248 v
= (ec
& 0xF) + '0';
1261 *ilen
= iname
- iname_start
;
1272 ncp__io2vol(unsigned char *vname
, unsigned int *vlen
,
1273 const unsigned char *iname
, unsigned int ilen
, int cc
)
1278 return -ENAMETOOLONG
;
1281 for (i
= 0; i
< ilen
; i
++) {
1282 *vname
= toupper(*iname
);
1287 memmove(vname
, iname
, ilen
);
1297 ncp__vol2io(unsigned char *iname
, unsigned int *ilen
,
1298 const unsigned char *vname
, unsigned int vlen
, int cc
)
1303 return -ENAMETOOLONG
;
1306 for (i
= 0; i
< vlen
; i
++) {
1307 *iname
= tolower(*vname
);
1312 memmove(iname
, vname
, vlen
);