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(void *data
)
115 static u8
ncp_reply_byte(struct ncp_server
*server
, int offset
)
117 return *(u8
*)ncp_reply_data(server
, offset
);
120 static inline u16
WVAL_LH(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(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(void *structure
, struct nw_info_struct
*target
)
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(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
, 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 volnum
, __le32 dirent
,
456 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
, server
->name_space
[volnum
]);
464 ncp_add_byte(server
, server
->name_space
[volnum
]);
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_ObtainSpecificDirBase(struct ncp_server
*server
,
528 __u8 nsSrc
, __u8 nsDst
, __u8 vol_num
, __le32 dir_base
,
529 char *path
, /* At most 1 component */
530 __le32
*dirEntNum
, __le32
*DosDirNum
)
534 ncp_init_request(server
);
535 ncp_add_byte(server
, 6); /* subfunction */
536 ncp_add_byte(server
, nsSrc
);
537 ncp_add_byte(server
, nsDst
);
538 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
539 ncp_add_dword(server
, RIM_ALL
);
540 ncp_add_handle_path(server
, vol_num
, dir_base
, 1, path
);
542 if ((result
= ncp_request(server
, 87)) != 0)
544 ncp_unlock_server(server
);
549 *dirEntNum
= ncp_reply_dword(server
, 0x30);
551 *DosDirNum
= ncp_reply_dword(server
, 0x34);
552 ncp_unlock_server(server
);
557 ncp_mount_subdir(struct ncp_server
*server
,
558 __u8 volNumber
, __u8 srcNS
, __le32 dirEntNum
,
559 __u32
* volume
, __le32
* newDirEnt
, __le32
* newDosEnt
)
564 dstNS
= ncp_get_known_namespace(server
, volNumber
);
565 if ((result
= ncp_ObtainSpecificDirBase(server
, srcNS
, dstNS
, volNumber
,
566 dirEntNum
, NULL
, newDirEnt
, newDosEnt
)) != 0)
570 server
->name_space
[volNumber
] = dstNS
;
572 server
->m
.mounted_vol
[1] = 0;
573 server
->m
.mounted_vol
[0] = 'X';
578 ncp_get_volume_root(struct ncp_server
*server
, const char *volname
,
579 __u32
* volume
, __le32
* dirent
, __le32
* dosdirent
)
584 DPRINTK("ncp_get_volume_root: looking up vol %s\n", volname
);
586 ncp_init_request(server
);
587 ncp_add_byte(server
, 22); /* Subfunction: Generate dir handle */
588 ncp_add_byte(server
, 0); /* DOS namespace */
589 ncp_add_byte(server
, 0); /* reserved */
590 ncp_add_byte(server
, 0); /* reserved */
591 ncp_add_byte(server
, 0); /* reserved */
593 ncp_add_byte(server
, 0); /* faked volume number */
594 ncp_add_dword(server
, 0); /* faked dir_base */
595 ncp_add_byte(server
, 0xff); /* Don't have a dir_base */
596 ncp_add_byte(server
, 1); /* 1 path component */
597 ncp_add_pstring(server
, volname
);
599 if ((result
= ncp_request(server
, 87)) != 0) {
600 ncp_unlock_server(server
);
603 *dirent
= *dosdirent
= ncp_reply_dword(server
, 4);
604 volnum
= ncp_reply_byte(server
, 8);
605 ncp_unlock_server(server
);
608 server
->name_space
[volnum
] = ncp_get_known_namespace(server
, volnum
);
610 DPRINTK("lookup_vol: namespace[%d] = %d\n",
611 volnum
, server
->name_space
[volnum
]);
617 ncp_lookup_volume(struct ncp_server
*server
, const char *volname
,
618 struct nw_info_struct
*target
)
622 memset(target
, 0, sizeof(*target
));
623 result
= ncp_get_volume_root(server
, volname
,
624 &target
->volNumber
, &target
->dirEntNum
, &target
->DosDirNum
);
628 target
->nameLen
= strlen(volname
);
629 memcpy(target
->entryName
, volname
, target
->nameLen
+1);
630 target
->attributes
= aDIR
;
631 /* set dates to Jan 1, 1986 00:00 */
632 target
->creationTime
= target
->modifyTime
= cpu_to_le16(0x0000);
633 target
->creationDate
= target
->modifyDate
= target
->lastAccessDate
= cpu_to_le16(0x0C21);
634 target
->nfs
.mode
= 0;
638 int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server
*server
,
642 const struct nw_modify_dos_info
*info
)
644 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
645 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
648 ncp_init_request(server
);
649 ncp_add_byte(server
, 7); /* subfunction */
650 ncp_add_byte(server
, server
->name_space
[volnum
]);
651 ncp_add_byte(server
, 0); /* reserved */
652 ncp_add_word(server
, cpu_to_le16(0x8006)); /* search attribs: all */
654 ncp_add_dword(server
, info_mask
);
655 ncp_add_mem(server
, info
, sizeof(*info
));
656 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
658 result
= ncp_request(server
, 87);
659 ncp_unlock_server(server
);
663 int ncp_modify_file_or_subdir_dos_info(struct ncp_server
*server
,
666 const struct nw_modify_dos_info
*info
)
668 return ncp_modify_file_or_subdir_dos_info_path(server
, dir
, NULL
,
672 #ifdef CONFIG_NCPFS_NFS_NS
673 int ncp_modify_nfs_info(struct ncp_server
*server
, __u8 volnum
, __le32 dirent
,
674 __u32 mode
, __u32 rdev
)
679 if (server
->name_space
[volnum
] == NW_NS_NFS
) {
680 ncp_init_request(server
);
681 ncp_add_byte(server
, 25); /* subfunction */
682 ncp_add_byte(server
, server
->name_space
[volnum
]);
683 ncp_add_byte(server
, NW_NS_NFS
);
684 ncp_add_byte(server
, volnum
);
685 ncp_add_dword(server
, dirent
);
686 /* we must always operate on both nlinks and rdev, otherwise
688 ncp_add_dword_lh(server
, NSIBM_NFS_MODE
| NSIBM_NFS_NLINKS
| NSIBM_NFS_RDEV
);
689 ncp_add_dword_lh(server
, mode
);
690 ncp_add_dword_lh(server
, 1); /* nlinks */
691 ncp_add_dword_lh(server
, rdev
);
692 result
= ncp_request(server
, 87);
693 ncp_unlock_server(server
);
701 ncp_DeleteNSEntry(struct ncp_server
*server
,
702 __u8 have_dir_base
, __u8 volnum
, __le32 dirent
,
703 char* name
, __u8 ns
, __le16 attr
)
707 ncp_init_request(server
);
708 ncp_add_byte(server
, 8); /* subfunction */
709 ncp_add_byte(server
, ns
);
710 ncp_add_byte(server
, 0); /* reserved */
711 ncp_add_word(server
, attr
); /* search attribs: all */
712 ncp_add_handle_path(server
, volnum
, dirent
, have_dir_base
, name
);
714 result
= ncp_request(server
, 87);
715 ncp_unlock_server(server
);
720 ncp_del_file_or_subdir2(struct ncp_server
*server
,
721 struct dentry
*dentry
)
723 struct inode
*inode
= dentry
->d_inode
;
728 return 0xFF; /* Any error */
730 volnum
= NCP_FINFO(inode
)->volNumber
;
731 dirent
= NCP_FINFO(inode
)->DosDirNum
;
732 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, NULL
, NW_NS_DOS
, cpu_to_le16(0x8006));
736 ncp_del_file_or_subdir(struct ncp_server
*server
,
737 struct inode
*dir
, char *name
)
739 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
740 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
742 #ifdef CONFIG_NCPFS_NFS_NS
743 if (server
->name_space
[volnum
]==NW_NS_NFS
)
747 result
=ncp_obtain_DOS_dir_base(server
, volnum
, dirent
, name
, &dirent
);
748 if (result
) return result
;
749 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, NULL
, NW_NS_DOS
, cpu_to_le16(0x8006));
752 #endif /* CONFIG_NCPFS_NFS_NS */
753 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, name
, server
->name_space
[volnum
], cpu_to_le16(0x8006));
756 static inline void ConvertToNWfromDWORD(__u16 v0
, __u16 v1
, __u8 ret
[6])
758 __le16
*dest
= (__le16
*) ret
;
759 dest
[1] = cpu_to_le16(v0
);
760 dest
[2] = cpu_to_le16(v1
);
761 dest
[0] = cpu_to_le16(v0
+ 1);
765 /* If both dir and name are NULL, then in target there's already a
766 looked-up entry that wants to be opened. */
767 int ncp_open_create_file_or_subdir(struct ncp_server
*server
,
768 struct inode
*dir
, char *name
,
769 int open_create_mode
,
770 __le32 create_attributes
,
771 __le16 desired_acc_rights
,
772 struct ncp_entry_info
*target
)
774 __le16 search_attribs
= cpu_to_le16(0x0006);
779 volnum
= NCP_FINFO(dir
)->volNumber
;
780 dirent
= NCP_FINFO(dir
)->dirEntNum
;
782 if ((create_attributes
& aDIR
) != 0) {
783 search_attribs
|= cpu_to_le16(0x8000);
785 ncp_init_request(server
);
786 ncp_add_byte(server
, 1); /* subfunction */
787 ncp_add_byte(server
, server
->name_space
[volnum
]);
788 ncp_add_byte(server
, open_create_mode
);
789 ncp_add_word(server
, search_attribs
);
790 ncp_add_dword(server
, RIM_ALL
);
791 ncp_add_dword(server
, create_attributes
);
792 /* The desired acc rights seem to be the inherited rights mask
794 ncp_add_word(server
, desired_acc_rights
);
795 ncp_add_handle_path(server
, volnum
, dirent
, 1, name
);
797 if ((result
= ncp_request(server
, 87)) != 0)
799 if (!(create_attributes
& aDIR
))
802 /* in target there's a new finfo to fill */
803 ncp_extract_file_info(ncp_reply_data(server
, 6), &(target
->i
));
804 target
->volume
= target
->i
.volNumber
;
805 ConvertToNWfromDWORD(ncp_reply_le16(server
, 0),
806 ncp_reply_le16(server
, 2),
807 target
->file_handle
);
809 ncp_unlock_server(server
);
811 (void)ncp_obtain_nfs_info(server
, &(target
->i
));
815 ncp_unlock_server(server
);
820 ncp_initialize_search(struct ncp_server
*server
, struct inode
*dir
,
821 struct nw_search_sequence
*target
)
823 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
824 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
827 ncp_init_request(server
);
828 ncp_add_byte(server
, 2); /* subfunction */
829 ncp_add_byte(server
, server
->name_space
[volnum
]);
830 ncp_add_byte(server
, 0); /* reserved */
831 ncp_add_handle_path(server
, volnum
, dirent
, 1, NULL
);
833 result
= ncp_request(server
, 87);
836 memcpy(target
, ncp_reply_data(server
, 0), sizeof(*target
));
839 ncp_unlock_server(server
);
843 int ncp_search_for_fileset(struct ncp_server
*server
,
844 struct nw_search_sequence
*seq
,
854 ncp_init_request(server
);
855 ncp_add_byte(server
, 20);
856 ncp_add_byte(server
, server
->name_space
[seq
->volNumber
]);
857 ncp_add_byte(server
, 0); /* datastream */
858 ncp_add_word(server
, cpu_to_le16(0x8006));
859 ncp_add_dword(server
, RIM_ALL
);
860 ncp_add_word(server
, cpu_to_le16(32767)); /* max returned items */
861 ncp_add_mem(server
, seq
, 9);
862 #ifdef CONFIG_NCPFS_NFS_NS
863 if (server
->name_space
[seq
->volNumber
] == NW_NS_NFS
) {
864 ncp_add_byte(server
, 0); /* 0 byte pattern */
868 ncp_add_byte(server
, 2); /* 2 byte pattern */
869 ncp_add_byte(server
, 0xff); /* following is a wildcard */
870 ncp_add_byte(server
, '*');
872 result
= ncp_request2(server
, 87, buffer
, bufsize
);
874 ncp_unlock_server(server
);
877 if (server
->ncp_reply_size
< 12) {
878 ncp_unlock_server(server
);
881 *rsize
= server
->ncp_reply_size
- 12;
882 ncp_unlock_server(server
);
883 buffer
= buffer
+ sizeof(struct ncp_reply_header
);
885 *cnt
= WVAL_LH(buffer
+ 10);
886 *more
= BVAL(buffer
+ 9);
887 memcpy(seq
, buffer
, 9);
892 ncp_RenameNSEntry(struct ncp_server
*server
,
893 struct inode
*old_dir
, char *old_name
, __le16 old_type
,
894 struct inode
*new_dir
, char *new_name
)
896 int result
= -EINVAL
;
898 if ((old_dir
== NULL
) || (old_name
== NULL
) ||
899 (new_dir
== NULL
) || (new_name
== NULL
))
902 ncp_init_request(server
);
903 ncp_add_byte(server
, 4); /* subfunction */
904 ncp_add_byte(server
, server
->name_space
[NCP_FINFO(old_dir
)->volNumber
]);
905 ncp_add_byte(server
, 1); /* rename flag */
906 ncp_add_word(server
, old_type
); /* search attributes */
908 /* source Handle Path */
909 ncp_add_byte(server
, NCP_FINFO(old_dir
)->volNumber
);
910 ncp_add_dword(server
, NCP_FINFO(old_dir
)->dirEntNum
);
911 ncp_add_byte(server
, 1);
912 ncp_add_byte(server
, 1); /* 1 source component */
914 /* dest Handle Path */
915 ncp_add_byte(server
, NCP_FINFO(new_dir
)->volNumber
);
916 ncp_add_dword(server
, NCP_FINFO(new_dir
)->dirEntNum
);
917 ncp_add_byte(server
, 1);
918 ncp_add_byte(server
, 1); /* 1 destination component */
920 /* source path string */
921 ncp_add_pstring(server
, old_name
);
922 /* dest path string */
923 ncp_add_pstring(server
, new_name
);
925 result
= ncp_request(server
, 87);
926 ncp_unlock_server(server
);
931 int ncp_ren_or_mov_file_or_subdir(struct ncp_server
*server
,
932 struct inode
*old_dir
, char *old_name
,
933 struct inode
*new_dir
, char *new_name
)
936 __le16 old_type
= cpu_to_le16(0x06);
938 /* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */
939 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
941 if (result
== 0xFF) /* File Not Found, try directory */
943 old_type
= cpu_to_le16(0x16);
944 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
947 if (result
!= 0x92) return result
; /* All except NO_FILES_RENAMED */
948 result
= ncp_del_file_or_subdir(server
, new_dir
, new_name
);
949 if (result
!= 0) return -EACCES
;
950 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
956 /* We have to transfer to/from user space */
958 ncp_read_kernel(struct ncp_server
*server
, const char *file_id
,
959 __u32 offset
, __u16 to_read
, char *target
, int *bytes_read
)
964 ncp_init_request(server
);
965 ncp_add_byte(server
, 0);
966 ncp_add_mem(server
, file_id
, 6);
967 ncp_add_be32(server
, offset
);
968 ncp_add_be16(server
, to_read
);
970 if ((result
= ncp_request(server
, 72)) != 0) {
973 *bytes_read
= ncp_reply_be16(server
, 0);
974 source
= ncp_reply_data(server
, 2 + (offset
& 1));
976 memcpy(target
, source
, *bytes_read
);
978 ncp_unlock_server(server
);
982 /* There is a problem... egrep and some other silly tools do:
983 x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768);
984 read(<ncpfs fd>, x, 32768);
985 Now copying read result by copy_to_user causes pagefault. This pagefault
986 could not be handled because of server was locked due to read. So we have
987 to use temporary buffer. So ncp_unlock_server must be done before
988 copy_to_user (and for write, copy_from_user must be done before
989 ncp_init_request... same applies for send raw packet ioctl). Because of
990 file is normally read in bigger chunks, caller provides kmalloced
991 (vmalloced) chunk of memory with size >= to_read...
994 ncp_read_bounce(struct ncp_server
*server
, const char *file_id
,
995 __u32 offset
, __u16 to_read
, char __user
*target
, int *bytes_read
,
996 void* bounce
, __u32 bufsize
)
1000 ncp_init_request(server
);
1001 ncp_add_byte(server
, 0);
1002 ncp_add_mem(server
, file_id
, 6);
1003 ncp_add_be32(server
, offset
);
1004 ncp_add_be16(server
, to_read
);
1005 result
= ncp_request2(server
, 72, bounce
, bufsize
);
1006 ncp_unlock_server(server
);
1008 int len
= get_unaligned_be16((char *)bounce
+
1009 sizeof(struct ncp_reply_header
));
1011 if (len
<= to_read
) {
1014 source
= (char*)bounce
+
1015 sizeof(struct ncp_reply_header
) + 2 +
1019 if (copy_to_user(target
, source
, len
))
1027 ncp_write_kernel(struct ncp_server
*server
, const char *file_id
,
1028 __u32 offset
, __u16 to_write
,
1029 const char *source
, int *bytes_written
)
1033 ncp_init_request(server
);
1034 ncp_add_byte(server
, 0);
1035 ncp_add_mem(server
, file_id
, 6);
1036 ncp_add_be32(server
, offset
);
1037 ncp_add_be16(server
, to_write
);
1038 ncp_add_mem(server
, source
, to_write
);
1040 if ((result
= ncp_request(server
, 73)) == 0)
1041 *bytes_written
= to_write
;
1042 ncp_unlock_server(server
);
1046 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
1048 ncp_LogPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
1049 __u8 locktype
, __u32 offset
, __u32 length
, __u16 timeout
)
1053 ncp_init_request(server
);
1054 ncp_add_byte(server
, locktype
);
1055 ncp_add_mem(server
, file_id
, 6);
1056 ncp_add_be32(server
, offset
);
1057 ncp_add_be32(server
, length
);
1058 ncp_add_be16(server
, timeout
);
1060 if ((result
= ncp_request(server
, 0x1A)) != 0)
1062 ncp_unlock_server(server
);
1065 ncp_unlock_server(server
);
1070 ncp_ClearPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
1071 __u32 offset
, __u32 length
)
1075 ncp_init_request(server
);
1076 ncp_add_byte(server
, 0); /* who knows... lanalyzer says that */
1077 ncp_add_mem(server
, file_id
, 6);
1078 ncp_add_be32(server
, offset
);
1079 ncp_add_be32(server
, length
);
1081 if ((result
= ncp_request(server
, 0x1E)) != 0)
1083 ncp_unlock_server(server
);
1086 ncp_unlock_server(server
);
1089 #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
1091 #ifdef CONFIG_NCPFS_NLS
1092 /* This are the NLS conversion routines with inspirations and code parts
1093 * from the vfat file system and hints from Petr Vandrovec.
1097 ncp__io2vol(struct ncp_server
*server
, unsigned char *vname
, unsigned int *vlen
,
1098 const unsigned char *iname
, unsigned int ilen
, int cc
)
1100 struct nls_table
*in
= server
->nls_io
;
1101 struct nls_table
*out
= server
->nls_vol
;
1102 unsigned char *vname_start
;
1103 unsigned char *vname_end
;
1104 const unsigned char *iname_end
;
1106 iname_end
= iname
+ ilen
;
1107 vname_start
= vname
;
1108 vname_end
= vname
+ *vlen
- 1;
1110 while (iname
< iname_end
) {
1114 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1118 k
= utf8_to_utf32(iname
, iname_end
- iname
, &u
);
1119 if (k
< 0 || u
> MAX_WCHAR_T
)
1124 if (*iname
== NCP_ESC
) {
1127 if (iname_end
- iname
< 5)
1131 for (k
= 1; k
< 5; k
++) {
1134 nc
= iname
[k
] - '0';
1136 nc
-= 'A' - '0' - 10;
1137 if ((nc
< 10) || (nc
> 15)) {
1141 ec
= (ec
<< 4) | nc
;
1146 if ( (chl
= in
->char2uni(iname
, iname_end
- iname
, &ec
)) < 0)
1152 /* unitoupper should be here! */
1154 chl
= out
->uni2char(ec
, vname
, vname_end
- vname
);
1158 /* this is wrong... */
1162 for (chi
= 0; chi
< chl
; chi
++){
1163 vname
[chi
] = ncp_toupper(out
, vname
[chi
]);
1170 *vlen
= vname
- vname_start
;
1175 ncp__vol2io(struct ncp_server
*server
, unsigned char *iname
, unsigned int *ilen
,
1176 const unsigned char *vname
, unsigned int vlen
, int cc
)
1178 struct nls_table
*in
= server
->nls_vol
;
1179 struct nls_table
*out
= server
->nls_io
;
1180 const unsigned char *vname_end
;
1181 unsigned char *iname_start
;
1182 unsigned char *iname_end
;
1183 unsigned char *vname_cc
;
1191 /* this is wrong! */
1192 vname_cc
= kmalloc(vlen
, GFP_KERNEL
);
1195 for (i
= 0; i
< vlen
; i
++)
1196 vname_cc
[i
] = ncp_tolower(in
, vname
[i
]);
1200 iname_start
= iname
;
1201 iname_end
= iname
+ *ilen
- 1;
1202 vname_end
= vname
+ vlen
;
1204 while (vname
< vname_end
) {
1208 if ( (chl
= in
->char2uni(vname
, vname_end
- vname
, &ec
)) < 0) {
1214 /* unitolower should be here! */
1216 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1219 k
= utf32_to_utf8(ec
, iname
, iname_end
- iname
);
1221 err
= -ENAMETOOLONG
;
1226 if ( (chl
= out
->uni2char(ec
, iname
, iname_end
- iname
)) >= 0) {
1231 if (iname_end
- iname
< 5) {
1232 err
= -ENAMETOOLONG
;
1236 for (k
= 4; k
> 0; k
--) {
1239 v
= (ec
& 0xF) + '0';
1252 *ilen
= iname
- iname_start
;
1263 ncp__io2vol(unsigned char *vname
, unsigned int *vlen
,
1264 const unsigned char *iname
, unsigned int ilen
, int cc
)
1269 return -ENAMETOOLONG
;
1272 for (i
= 0; i
< ilen
; i
++) {
1273 *vname
= toupper(*iname
);
1278 memmove(vname
, iname
, ilen
);
1288 ncp__vol2io(unsigned char *iname
, unsigned int *ilen
,
1289 const unsigned char *vname
, unsigned int vlen
, int cc
)
1294 return -ENAMETOOLONG
;
1297 for (i
= 0; i
< vlen
; i
++) {
1298 *iname
= tolower(*vname
);
1303 memmove(iname
, vname
, vlen
);