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
)
112 return get_unaligned((__u8
*)data
);
116 ncp_reply_byte(struct ncp_server
*server
, int offset
)
118 return get_unaligned((__u8
*) ncp_reply_data(server
, offset
));
121 static inline __u16
WVAL_LH(void* data
)
123 return le16_to_cpu(get_unaligned((__le16
*)data
));
127 ncp_reply_le16(struct ncp_server
*server
, int offset
)
129 return le16_to_cpu(get_unaligned((__le16
*) ncp_reply_data(server
, offset
)));
133 ncp_reply_be16(struct ncp_server
*server
, int offset
)
135 return be16_to_cpu(get_unaligned((__be16
*) ncp_reply_data(server
, offset
)));
138 static inline __u32
DVAL_LH(void* data
)
140 return le32_to_cpu(get_unaligned((__le32
*)data
));
144 ncp_reply_dword(struct ncp_server
*server
, int offset
)
146 return get_unaligned((__le32
*) ncp_reply_data(server
, offset
));
149 static inline __u32
ncp_reply_dword_lh(struct ncp_server
* server
, int offset
) {
150 return le32_to_cpu(ncp_reply_dword(server
, offset
));
154 ncp_negotiate_buffersize(struct ncp_server
*server
, int size
, int *target
)
158 ncp_init_request(server
);
159 ncp_add_be16(server
, size
);
161 if ((result
= ncp_request(server
, 33)) != 0) {
162 ncp_unlock_server(server
);
165 *target
= min_t(unsigned int, ncp_reply_be16(server
, 0), size
);
167 ncp_unlock_server(server
);
174 * bit 1 packet signing
177 ncp_negotiate_size_and_options(struct ncp_server
*server
,
178 int size
, int options
, int *ret_size
, int *ret_options
) {
181 /* there is minimum */
182 if (size
< NCP_BLOCK_SIZE
) size
= NCP_BLOCK_SIZE
;
184 ncp_init_request(server
);
185 ncp_add_be16(server
, size
);
186 ncp_add_byte(server
, options
);
188 if ((result
= ncp_request(server
, 0x61)) != 0)
190 ncp_unlock_server(server
);
194 /* NCP over UDP returns 0 (!!!) */
195 result
= ncp_reply_be16(server
, 0);
196 if (result
>= NCP_BLOCK_SIZE
)
197 size
= min(result
, size
);
199 *ret_options
= ncp_reply_byte(server
, 4);
201 ncp_unlock_server(server
);
205 int ncp_get_volume_info_with_number(struct ncp_server
* server
,
206 int n
, struct ncp_volume_info
* target
) {
210 ncp_init_request_s(server
, 44);
211 ncp_add_byte(server
, n
);
213 if ((result
= ncp_request(server
, 22)) != 0) {
216 target
->total_blocks
= ncp_reply_dword_lh(server
, 0);
217 target
->free_blocks
= ncp_reply_dword_lh(server
, 4);
218 target
->purgeable_blocks
= ncp_reply_dword_lh(server
, 8);
219 target
->not_yet_purgeable_blocks
= ncp_reply_dword_lh(server
, 12);
220 target
->total_dir_entries
= ncp_reply_dword_lh(server
, 16);
221 target
->available_dir_entries
= ncp_reply_dword_lh(server
, 20);
222 target
->sectors_per_block
= ncp_reply_byte(server
, 28);
224 memset(&(target
->volume_name
), 0, sizeof(target
->volume_name
));
227 len
= ncp_reply_byte(server
, 29);
228 if (len
> NCP_VOLNAME_LEN
) {
229 DPRINTK("ncpfs: volume name too long: %d\n", len
);
232 memcpy(&(target
->volume_name
), ncp_reply_data(server
, 30), len
);
235 ncp_unlock_server(server
);
239 int ncp_get_directory_info(struct ncp_server
* server
, __u8 n
,
240 struct ncp_volume_info
* target
) {
244 ncp_init_request_s(server
, 45);
245 ncp_add_byte(server
, n
);
247 if ((result
= ncp_request(server
, 22)) != 0) {
250 target
->total_blocks
= ncp_reply_dword_lh(server
, 0);
251 target
->free_blocks
= ncp_reply_dword_lh(server
, 4);
252 target
->purgeable_blocks
= 0;
253 target
->not_yet_purgeable_blocks
= 0;
254 target
->total_dir_entries
= ncp_reply_dword_lh(server
, 8);
255 target
->available_dir_entries
= ncp_reply_dword_lh(server
, 12);
256 target
->sectors_per_block
= ncp_reply_byte(server
, 20);
258 memset(&(target
->volume_name
), 0, sizeof(target
->volume_name
));
261 len
= ncp_reply_byte(server
, 21);
262 if (len
> NCP_VOLNAME_LEN
) {
263 DPRINTK("ncpfs: volume name too long: %d\n", len
);
266 memcpy(&(target
->volume_name
), ncp_reply_data(server
, 22), len
);
269 ncp_unlock_server(server
);
274 ncp_close_file(struct ncp_server
*server
, const char *file_id
)
278 ncp_init_request(server
);
279 ncp_add_byte(server
, 0);
280 ncp_add_mem(server
, file_id
, 6);
282 result
= ncp_request(server
, 66);
283 ncp_unlock_server(server
);
288 ncp_make_closed(struct inode
*inode
)
293 mutex_lock(&NCP_FINFO(inode
)->open_mutex
);
294 if (atomic_read(&NCP_FINFO(inode
)->opened
) == 1) {
295 atomic_set(&NCP_FINFO(inode
)->opened
, 0);
296 err
= ncp_close_file(NCP_SERVER(inode
), NCP_FINFO(inode
)->file_handle
);
299 PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n",
300 NCP_FINFO(inode
)->volNumber
,
301 NCP_FINFO(inode
)->dirEntNum
, err
);
303 mutex_unlock(&NCP_FINFO(inode
)->open_mutex
);
307 static void ncp_add_handle_path(struct ncp_server
*server
, __u8 vol_num
,
308 __le32 dir_base
, int have_dir_base
,
311 ncp_add_byte(server
, vol_num
);
312 ncp_add_dword(server
, dir_base
);
313 if (have_dir_base
!= 0) {
314 ncp_add_byte(server
, 1); /* dir_base */
316 ncp_add_byte(server
, 0xff); /* no handle */
319 ncp_add_byte(server
, 1); /* 1 component */
320 ncp_add_pstring(server
, path
);
322 ncp_add_byte(server
, 0);
326 int ncp_dirhandle_alloc(struct ncp_server
* server
, __u8 volnum
, __le32 dirent
,
330 ncp_init_request(server
);
331 ncp_add_byte(server
, 12); /* subfunction */
332 ncp_add_byte(server
, NW_NS_DOS
);
333 ncp_add_byte(server
, 0);
334 ncp_add_word(server
, 0);
335 ncp_add_handle_path(server
, volnum
, dirent
, 1, NULL
);
336 if ((result
= ncp_request(server
, 87)) == 0) {
337 *dirhandle
= ncp_reply_byte(server
, 0);
339 ncp_unlock_server(server
);
343 int ncp_dirhandle_free(struct ncp_server
* server
, __u8 dirhandle
) {
346 ncp_init_request_s(server
, 20);
347 ncp_add_byte(server
, dirhandle
);
348 result
= ncp_request(server
, 22);
349 ncp_unlock_server(server
);
353 void ncp_extract_file_info(void *structure
, struct nw_info_struct
*target
)
356 const int info_struct_size
= offsetof(struct nw_info_struct
, nameLen
);
358 memcpy(target
, structure
, info_struct_size
);
359 name_len
= structure
+ info_struct_size
;
360 target
->nameLen
= *name_len
;
361 memcpy(target
->entryName
, name_len
+ 1, *name_len
);
362 target
->entryName
[*name_len
] = '\0';
363 target
->volNumber
= le32_to_cpu(target
->volNumber
);
367 #ifdef CONFIG_NCPFS_NFS_NS
368 static inline void ncp_extract_nfs_info(unsigned char *structure
,
369 struct nw_nfs_info
*target
)
371 target
->mode
= DVAL_LH(structure
);
372 target
->rdev
= DVAL_LH(structure
+ 8);
376 int ncp_obtain_nfs_info(struct ncp_server
*server
,
377 struct nw_info_struct
*target
)
381 #ifdef CONFIG_NCPFS_NFS_NS
382 __u32 volnum
= target
->volNumber
;
384 if (ncp_is_nfs_extras(server
, volnum
)) {
385 ncp_init_request(server
);
386 ncp_add_byte(server
, 19); /* subfunction */
387 ncp_add_byte(server
, server
->name_space
[volnum
]);
388 ncp_add_byte(server
, NW_NS_NFS
);
389 ncp_add_byte(server
, 0);
390 ncp_add_byte(server
, volnum
);
391 ncp_add_dword(server
, target
->dirEntNum
);
392 /* We must retrieve both nlinks and rdev, otherwise some server versions
393 report zeroes instead of valid data */
394 ncp_add_dword_lh(server
, NSIBM_NFS_MODE
| NSIBM_NFS_NLINKS
| NSIBM_NFS_RDEV
);
396 if ((result
= ncp_request(server
, 87)) == 0) {
397 ncp_extract_nfs_info(ncp_reply_data(server
, 0), &target
->nfs
);
399 "ncp_obtain_nfs_info: (%s) mode=0%o, rdev=0x%x\n",
400 target
->entryName
, target
->nfs
.mode
,
403 target
->nfs
.mode
= 0;
404 target
->nfs
.rdev
= 0;
406 ncp_unlock_server(server
);
411 target
->nfs
.mode
= 0;
412 target
->nfs
.rdev
= 0;
418 * Returns information for a (one-component) name relative to
419 * the specified directory.
421 int ncp_obtain_info(struct ncp_server
*server
, struct inode
*dir
, char *path
,
422 struct nw_info_struct
*target
)
424 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
425 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
428 if (target
== NULL
) {
429 printk(KERN_ERR
"ncp_obtain_info: invalid call\n");
432 ncp_init_request(server
);
433 ncp_add_byte(server
, 6); /* subfunction */
434 ncp_add_byte(server
, server
->name_space
[volnum
]);
435 ncp_add_byte(server
, server
->name_space
[volnum
]); /* N.B. twice ?? */
436 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
437 ncp_add_dword(server
, RIM_ALL
);
438 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
440 if ((result
= ncp_request(server
, 87)) != 0)
442 ncp_extract_file_info(ncp_reply_data(server
, 0), target
);
443 ncp_unlock_server(server
);
445 result
= ncp_obtain_nfs_info(server
, target
);
449 ncp_unlock_server(server
);
453 #ifdef CONFIG_NCPFS_NFS_NS
455 ncp_obtain_DOS_dir_base(struct ncp_server
*server
,
456 __u8 volnum
, __le32 dirent
,
457 char *path
, /* At most 1 component */
458 __le32
*DOS_dir_base
)
462 ncp_init_request(server
);
463 ncp_add_byte(server
, 6); /* subfunction */
464 ncp_add_byte(server
, server
->name_space
[volnum
]);
465 ncp_add_byte(server
, server
->name_space
[volnum
]);
466 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
467 ncp_add_dword(server
, RIM_DIRECTORY
);
468 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
470 if ((result
= ncp_request(server
, 87)) == 0)
472 if (DOS_dir_base
) *DOS_dir_base
=ncp_reply_dword(server
, 0x34);
474 ncp_unlock_server(server
);
477 #endif /* CONFIG_NCPFS_NFS_NS */
480 ncp_get_known_namespace(struct ncp_server
*server
, __u8 volume
)
482 #if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS)
487 ncp_init_request(server
);
488 ncp_add_byte(server
, 24); /* Subfunction: Get Name Spaces Loaded */
489 ncp_add_word(server
, 0);
490 ncp_add_byte(server
, volume
);
492 if ((result
= ncp_request(server
, 87)) != 0) {
493 ncp_unlock_server(server
);
494 return NW_NS_DOS
; /* not result ?? */
498 no_namespaces
= ncp_reply_le16(server
, 0);
499 namespace = ncp_reply_data(server
, 2);
501 while (no_namespaces
> 0) {
502 DPRINTK("get_namespaces: found %d on %d\n", *namespace, volume
);
504 #ifdef CONFIG_NCPFS_NFS_NS
505 if ((*namespace == NW_NS_NFS
) && !(server
->m
.flags
&NCP_MOUNT_NO_NFS
))
510 #endif /* CONFIG_NCPFS_NFS_NS */
511 #ifdef CONFIG_NCPFS_OS2_NS
512 if ((*namespace == NW_NS_OS2
) && !(server
->m
.flags
&NCP_MOUNT_NO_OS2
))
516 #endif /* CONFIG_NCPFS_OS2_NS */
520 ncp_unlock_server(server
);
522 #else /* neither OS2 nor NFS - only DOS */
524 #endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */
528 ncp_ObtainSpecificDirBase(struct ncp_server
*server
,
529 __u8 nsSrc
, __u8 nsDst
, __u8 vol_num
, __le32 dir_base
,
530 char *path
, /* At most 1 component */
531 __le32
*dirEntNum
, __le32
*DosDirNum
)
535 ncp_init_request(server
);
536 ncp_add_byte(server
, 6); /* subfunction */
537 ncp_add_byte(server
, nsSrc
);
538 ncp_add_byte(server
, nsDst
);
539 ncp_add_word(server
, cpu_to_le16(0x8006)); /* get all */
540 ncp_add_dword(server
, RIM_ALL
);
541 ncp_add_handle_path(server
, vol_num
, dir_base
, 1, path
);
543 if ((result
= ncp_request(server
, 87)) != 0)
545 ncp_unlock_server(server
);
550 *dirEntNum
= ncp_reply_dword(server
, 0x30);
552 *DosDirNum
= ncp_reply_dword(server
, 0x34);
553 ncp_unlock_server(server
);
558 ncp_mount_subdir(struct ncp_server
*server
,
559 __u8 volNumber
, __u8 srcNS
, __le32 dirEntNum
,
560 __u32
* volume
, __le32
* newDirEnt
, __le32
* newDosEnt
)
565 dstNS
= ncp_get_known_namespace(server
, volNumber
);
566 if ((result
= ncp_ObtainSpecificDirBase(server
, srcNS
, dstNS
, volNumber
,
567 dirEntNum
, NULL
, newDirEnt
, newDosEnt
)) != 0)
571 server
->name_space
[volNumber
] = dstNS
;
573 server
->m
.mounted_vol
[1] = 0;
574 server
->m
.mounted_vol
[0] = 'X';
579 ncp_get_volume_root(struct ncp_server
*server
, const char *volname
,
580 __u32
* volume
, __le32
* dirent
, __le32
* dosdirent
)
585 DPRINTK("ncp_get_volume_root: looking up vol %s\n", volname
);
587 ncp_init_request(server
);
588 ncp_add_byte(server
, 22); /* Subfunction: Generate dir handle */
589 ncp_add_byte(server
, 0); /* DOS namespace */
590 ncp_add_byte(server
, 0); /* reserved */
591 ncp_add_byte(server
, 0); /* reserved */
592 ncp_add_byte(server
, 0); /* reserved */
594 ncp_add_byte(server
, 0); /* faked volume number */
595 ncp_add_dword(server
, 0); /* faked dir_base */
596 ncp_add_byte(server
, 0xff); /* Don't have a dir_base */
597 ncp_add_byte(server
, 1); /* 1 path component */
598 ncp_add_pstring(server
, volname
);
600 if ((result
= ncp_request(server
, 87)) != 0) {
601 ncp_unlock_server(server
);
604 *dirent
= *dosdirent
= ncp_reply_dword(server
, 4);
605 volnum
= ncp_reply_byte(server
, 8);
606 ncp_unlock_server(server
);
609 server
->name_space
[volnum
] = ncp_get_known_namespace(server
, volnum
);
611 DPRINTK("lookup_vol: namespace[%d] = %d\n",
612 volnum
, server
->name_space
[volnum
]);
618 ncp_lookup_volume(struct ncp_server
*server
, const char *volname
,
619 struct nw_info_struct
*target
)
623 memset(target
, 0, sizeof(*target
));
624 result
= ncp_get_volume_root(server
, volname
,
625 &target
->volNumber
, &target
->dirEntNum
, &target
->DosDirNum
);
629 target
->nameLen
= strlen(volname
);
630 memcpy(target
->entryName
, volname
, target
->nameLen
+1);
631 target
->attributes
= aDIR
;
632 /* set dates to Jan 1, 1986 00:00 */
633 target
->creationTime
= target
->modifyTime
= cpu_to_le16(0x0000);
634 target
->creationDate
= target
->modifyDate
= target
->lastAccessDate
= cpu_to_le16(0x0C21);
635 target
->nfs
.mode
= 0;
639 int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server
*server
,
643 const struct nw_modify_dos_info
*info
)
645 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
646 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
649 ncp_init_request(server
);
650 ncp_add_byte(server
, 7); /* subfunction */
651 ncp_add_byte(server
, server
->name_space
[volnum
]);
652 ncp_add_byte(server
, 0); /* reserved */
653 ncp_add_word(server
, cpu_to_le16(0x8006)); /* search attribs: all */
655 ncp_add_dword(server
, info_mask
);
656 ncp_add_mem(server
, info
, sizeof(*info
));
657 ncp_add_handle_path(server
, volnum
, dirent
, 1, path
);
659 result
= ncp_request(server
, 87);
660 ncp_unlock_server(server
);
664 int ncp_modify_file_or_subdir_dos_info(struct ncp_server
*server
,
667 const struct nw_modify_dos_info
*info
)
669 return ncp_modify_file_or_subdir_dos_info_path(server
, dir
, NULL
,
673 #ifdef CONFIG_NCPFS_NFS_NS
674 int ncp_modify_nfs_info(struct ncp_server
*server
, __u8 volnum
, __le32 dirent
,
675 __u32 mode
, __u32 rdev
)
680 if (server
->name_space
[volnum
] == NW_NS_NFS
) {
681 ncp_init_request(server
);
682 ncp_add_byte(server
, 25); /* subfunction */
683 ncp_add_byte(server
, server
->name_space
[volnum
]);
684 ncp_add_byte(server
, NW_NS_NFS
);
685 ncp_add_byte(server
, volnum
);
686 ncp_add_dword(server
, dirent
);
687 /* we must always operate on both nlinks and rdev, otherwise
689 ncp_add_dword_lh(server
, NSIBM_NFS_MODE
| NSIBM_NFS_NLINKS
| NSIBM_NFS_RDEV
);
690 ncp_add_dword_lh(server
, mode
);
691 ncp_add_dword_lh(server
, 1); /* nlinks */
692 ncp_add_dword_lh(server
, rdev
);
693 result
= ncp_request(server
, 87);
694 ncp_unlock_server(server
);
702 ncp_DeleteNSEntry(struct ncp_server
*server
,
703 __u8 have_dir_base
, __u8 volnum
, __le32 dirent
,
704 char* name
, __u8 ns
, __le16 attr
)
708 ncp_init_request(server
);
709 ncp_add_byte(server
, 8); /* subfunction */
710 ncp_add_byte(server
, ns
);
711 ncp_add_byte(server
, 0); /* reserved */
712 ncp_add_word(server
, attr
); /* search attribs: all */
713 ncp_add_handle_path(server
, volnum
, dirent
, have_dir_base
, name
);
715 result
= ncp_request(server
, 87);
716 ncp_unlock_server(server
);
721 ncp_del_file_or_subdir2(struct ncp_server
*server
,
722 struct dentry
*dentry
)
724 struct inode
*inode
= dentry
->d_inode
;
729 return 0xFF; /* Any error */
731 volnum
= NCP_FINFO(inode
)->volNumber
;
732 dirent
= NCP_FINFO(inode
)->DosDirNum
;
733 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, NULL
, NW_NS_DOS
, cpu_to_le16(0x8006));
737 ncp_del_file_or_subdir(struct ncp_server
*server
,
738 struct inode
*dir
, char *name
)
740 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
741 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
743 #ifdef CONFIG_NCPFS_NFS_NS
744 if (server
->name_space
[volnum
]==NW_NS_NFS
)
748 result
=ncp_obtain_DOS_dir_base(server
, volnum
, dirent
, name
, &dirent
);
749 if (result
) return result
;
750 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, NULL
, NW_NS_DOS
, cpu_to_le16(0x8006));
753 #endif /* CONFIG_NCPFS_NFS_NS */
754 return ncp_DeleteNSEntry(server
, 1, volnum
, dirent
, name
, server
->name_space
[volnum
], cpu_to_le16(0x8006));
757 static inline void ConvertToNWfromDWORD(__u16 v0
, __u16 v1
, __u8 ret
[6])
759 __le16
*dest
= (__le16
*) ret
;
760 dest
[1] = cpu_to_le16(v0
);
761 dest
[2] = cpu_to_le16(v1
);
762 dest
[0] = cpu_to_le16(v0
+ 1);
766 /* If both dir and name are NULL, then in target there's already a
767 looked-up entry that wants to be opened. */
768 int ncp_open_create_file_or_subdir(struct ncp_server
*server
,
769 struct inode
*dir
, char *name
,
770 int open_create_mode
,
771 __le32 create_attributes
,
772 __le16 desired_acc_rights
,
773 struct ncp_entry_info
*target
)
775 __le16 search_attribs
= cpu_to_le16(0x0006);
780 volnum
= NCP_FINFO(dir
)->volNumber
;
781 dirent
= NCP_FINFO(dir
)->dirEntNum
;
783 if ((create_attributes
& aDIR
) != 0) {
784 search_attribs
|= cpu_to_le16(0x8000);
786 ncp_init_request(server
);
787 ncp_add_byte(server
, 1); /* subfunction */
788 ncp_add_byte(server
, server
->name_space
[volnum
]);
789 ncp_add_byte(server
, open_create_mode
);
790 ncp_add_word(server
, search_attribs
);
791 ncp_add_dword(server
, RIM_ALL
);
792 ncp_add_dword(server
, create_attributes
);
793 /* The desired acc rights seem to be the inherited rights mask
795 ncp_add_word(server
, desired_acc_rights
);
796 ncp_add_handle_path(server
, volnum
, dirent
, 1, name
);
798 if ((result
= ncp_request(server
, 87)) != 0)
800 if (!(create_attributes
& aDIR
))
803 /* in target there's a new finfo to fill */
804 ncp_extract_file_info(ncp_reply_data(server
, 6), &(target
->i
));
805 target
->volume
= target
->i
.volNumber
;
806 ConvertToNWfromDWORD(ncp_reply_le16(server
, 0),
807 ncp_reply_le16(server
, 2),
808 target
->file_handle
);
810 ncp_unlock_server(server
);
812 (void)ncp_obtain_nfs_info(server
, &(target
->i
));
816 ncp_unlock_server(server
);
821 ncp_initialize_search(struct ncp_server
*server
, struct inode
*dir
,
822 struct nw_search_sequence
*target
)
824 __u8 volnum
= NCP_FINFO(dir
)->volNumber
;
825 __le32 dirent
= NCP_FINFO(dir
)->dirEntNum
;
828 ncp_init_request(server
);
829 ncp_add_byte(server
, 2); /* subfunction */
830 ncp_add_byte(server
, server
->name_space
[volnum
]);
831 ncp_add_byte(server
, 0); /* reserved */
832 ncp_add_handle_path(server
, volnum
, dirent
, 1, NULL
);
834 result
= ncp_request(server
, 87);
837 memcpy(target
, ncp_reply_data(server
, 0), sizeof(*target
));
840 ncp_unlock_server(server
);
844 int ncp_search_for_fileset(struct ncp_server
*server
,
845 struct nw_search_sequence
*seq
,
855 ncp_init_request(server
);
856 ncp_add_byte(server
, 20);
857 ncp_add_byte(server
, server
->name_space
[seq
->volNumber
]);
858 ncp_add_byte(server
, 0); /* datastream */
859 ncp_add_word(server
, cpu_to_le16(0x8006));
860 ncp_add_dword(server
, RIM_ALL
);
861 ncp_add_word(server
, cpu_to_le16(32767)); /* max returned items */
862 ncp_add_mem(server
, seq
, 9);
863 #ifdef CONFIG_NCPFS_NFS_NS
864 if (server
->name_space
[seq
->volNumber
] == NW_NS_NFS
) {
865 ncp_add_byte(server
, 0); /* 0 byte pattern */
869 ncp_add_byte(server
, 2); /* 2 byte pattern */
870 ncp_add_byte(server
, 0xff); /* following is a wildcard */
871 ncp_add_byte(server
, '*');
873 result
= ncp_request2(server
, 87, buffer
, bufsize
);
875 ncp_unlock_server(server
);
878 if (server
->ncp_reply_size
< 12) {
879 ncp_unlock_server(server
);
882 *rsize
= server
->ncp_reply_size
- 12;
883 ncp_unlock_server(server
);
884 buffer
= buffer
+ sizeof(struct ncp_reply_header
);
886 *cnt
= WVAL_LH(buffer
+ 10);
887 *more
= BVAL(buffer
+ 9);
888 memcpy(seq
, buffer
, 9);
893 ncp_RenameNSEntry(struct ncp_server
*server
,
894 struct inode
*old_dir
, char *old_name
, __le16 old_type
,
895 struct inode
*new_dir
, char *new_name
)
897 int result
= -EINVAL
;
899 if ((old_dir
== NULL
) || (old_name
== NULL
) ||
900 (new_dir
== NULL
) || (new_name
== NULL
))
903 ncp_init_request(server
);
904 ncp_add_byte(server
, 4); /* subfunction */
905 ncp_add_byte(server
, server
->name_space
[NCP_FINFO(old_dir
)->volNumber
]);
906 ncp_add_byte(server
, 1); /* rename flag */
907 ncp_add_word(server
, old_type
); /* search attributes */
909 /* source Handle Path */
910 ncp_add_byte(server
, NCP_FINFO(old_dir
)->volNumber
);
911 ncp_add_dword(server
, NCP_FINFO(old_dir
)->dirEntNum
);
912 ncp_add_byte(server
, 1);
913 ncp_add_byte(server
, 1); /* 1 source component */
915 /* dest Handle Path */
916 ncp_add_byte(server
, NCP_FINFO(new_dir
)->volNumber
);
917 ncp_add_dword(server
, NCP_FINFO(new_dir
)->dirEntNum
);
918 ncp_add_byte(server
, 1);
919 ncp_add_byte(server
, 1); /* 1 destination component */
921 /* source path string */
922 ncp_add_pstring(server
, old_name
);
923 /* dest path string */
924 ncp_add_pstring(server
, new_name
);
926 result
= ncp_request(server
, 87);
927 ncp_unlock_server(server
);
932 int ncp_ren_or_mov_file_or_subdir(struct ncp_server
*server
,
933 struct inode
*old_dir
, char *old_name
,
934 struct inode
*new_dir
, char *new_name
)
937 __le16 old_type
= cpu_to_le16(0x06);
939 /* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */
940 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
942 if (result
== 0xFF) /* File Not Found, try directory */
944 old_type
= cpu_to_le16(0x16);
945 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
948 if (result
!= 0x92) return result
; /* All except NO_FILES_RENAMED */
949 result
= ncp_del_file_or_subdir(server
, new_dir
, new_name
);
950 if (result
!= 0) return -EACCES
;
951 result
= ncp_RenameNSEntry(server
, old_dir
, old_name
, old_type
,
957 /* We have to transfer to/from user space */
959 ncp_read_kernel(struct ncp_server
*server
, const char *file_id
,
960 __u32 offset
, __u16 to_read
, char *target
, int *bytes_read
)
965 ncp_init_request(server
);
966 ncp_add_byte(server
, 0);
967 ncp_add_mem(server
, file_id
, 6);
968 ncp_add_be32(server
, offset
);
969 ncp_add_be16(server
, to_read
);
971 if ((result
= ncp_request(server
, 72)) != 0) {
974 *bytes_read
= ncp_reply_be16(server
, 0);
975 source
= ncp_reply_data(server
, 2 + (offset
& 1));
977 memcpy(target
, source
, *bytes_read
);
979 ncp_unlock_server(server
);
983 /* There is a problem... egrep and some other silly tools do:
984 x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768);
985 read(<ncpfs fd>, x, 32768);
986 Now copying read result by copy_to_user causes pagefault. This pagefault
987 could not be handled because of server was locked due to read. So we have
988 to use temporary buffer. So ncp_unlock_server must be done before
989 copy_to_user (and for write, copy_from_user must be done before
990 ncp_init_request... same applies for send raw packet ioctl). Because of
991 file is normally read in bigger chunks, caller provides kmalloced
992 (vmalloced) chunk of memory with size >= to_read...
995 ncp_read_bounce(struct ncp_server
*server
, const char *file_id
,
996 __u32 offset
, __u16 to_read
, char __user
*target
, int *bytes_read
,
997 void* bounce
, __u32 bufsize
)
1001 ncp_init_request(server
);
1002 ncp_add_byte(server
, 0);
1003 ncp_add_mem(server
, file_id
, 6);
1004 ncp_add_be32(server
, offset
);
1005 ncp_add_be16(server
, to_read
);
1006 result
= ncp_request2(server
, 72, bounce
, bufsize
);
1007 ncp_unlock_server(server
);
1009 int len
= be16_to_cpu(get_unaligned((__be16
*)((char*)bounce
+
1010 sizeof(struct ncp_reply_header
))));
1012 if (len
<= to_read
) {
1015 source
= (char*)bounce
+
1016 sizeof(struct ncp_reply_header
) + 2 +
1020 if (copy_to_user(target
, source
, len
))
1028 ncp_write_kernel(struct ncp_server
*server
, const char *file_id
,
1029 __u32 offset
, __u16 to_write
,
1030 const char *source
, int *bytes_written
)
1034 ncp_init_request(server
);
1035 ncp_add_byte(server
, 0);
1036 ncp_add_mem(server
, file_id
, 6);
1037 ncp_add_be32(server
, offset
);
1038 ncp_add_be16(server
, to_write
);
1039 ncp_add_mem(server
, source
, to_write
);
1041 if ((result
= ncp_request(server
, 73)) == 0)
1042 *bytes_written
= to_write
;
1043 ncp_unlock_server(server
);
1047 #ifdef CONFIG_NCPFS_IOCTL_LOCKING
1049 ncp_LogPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
1050 __u8 locktype
, __u32 offset
, __u32 length
, __u16 timeout
)
1054 ncp_init_request(server
);
1055 ncp_add_byte(server
, locktype
);
1056 ncp_add_mem(server
, file_id
, 6);
1057 ncp_add_be32(server
, offset
);
1058 ncp_add_be32(server
, length
);
1059 ncp_add_be16(server
, timeout
);
1061 if ((result
= ncp_request(server
, 0x1A)) != 0)
1063 ncp_unlock_server(server
);
1066 ncp_unlock_server(server
);
1071 ncp_ClearPhysicalRecord(struct ncp_server
*server
, const char *file_id
,
1072 __u32 offset
, __u32 length
)
1076 ncp_init_request(server
);
1077 ncp_add_byte(server
, 0); /* who knows... lanalyzer says that */
1078 ncp_add_mem(server
, file_id
, 6);
1079 ncp_add_be32(server
, offset
);
1080 ncp_add_be32(server
, length
);
1082 if ((result
= ncp_request(server
, 0x1E)) != 0)
1084 ncp_unlock_server(server
);
1087 ncp_unlock_server(server
);
1090 #endif /* CONFIG_NCPFS_IOCTL_LOCKING */
1092 #ifdef CONFIG_NCPFS_NLS
1093 /* This are the NLS conversion routines with inspirations and code parts
1094 * from the vfat file system and hints from Petr Vandrovec.
1098 ncp__io2vol(struct ncp_server
*server
, unsigned char *vname
, unsigned int *vlen
,
1099 const unsigned char *iname
, unsigned int ilen
, int cc
)
1101 struct nls_table
*in
= server
->nls_io
;
1102 struct nls_table
*out
= server
->nls_vol
;
1103 unsigned char *vname_start
;
1104 unsigned char *vname_end
;
1105 const unsigned char *iname_end
;
1107 iname_end
= iname
+ ilen
;
1108 vname_start
= vname
;
1109 vname_end
= vname
+ *vlen
- 1;
1111 while (iname
< iname_end
) {
1115 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1118 k
= utf8_mbtowc(&ec
, iname
, iname_end
- iname
);
1123 if (*iname
== NCP_ESC
) {
1126 if (iname_end
- iname
< 5)
1130 for (k
= 1; k
< 5; k
++) {
1133 nc
= iname
[k
] - '0';
1135 nc
-= 'A' - '0' - 10;
1136 if ((nc
< 10) || (nc
> 15)) {
1140 ec
= (ec
<< 4) | nc
;
1145 if ( (chl
= in
->char2uni(iname
, iname_end
- iname
, &ec
)) < 0)
1151 /* unitoupper should be here! */
1153 chl
= out
->uni2char(ec
, vname
, vname_end
- vname
);
1157 /* this is wrong... */
1161 for (chi
= 0; chi
< chl
; chi
++){
1162 vname
[chi
] = ncp_toupper(out
, vname
[chi
]);
1169 *vlen
= vname
- vname_start
;
1174 ncp__vol2io(struct ncp_server
*server
, unsigned char *iname
, unsigned int *ilen
,
1175 const unsigned char *vname
, unsigned int vlen
, int cc
)
1177 struct nls_table
*in
= server
->nls_vol
;
1178 struct nls_table
*out
= server
->nls_io
;
1179 const unsigned char *vname_end
;
1180 unsigned char *iname_start
;
1181 unsigned char *iname_end
;
1182 unsigned char *vname_cc
;
1190 /* this is wrong! */
1191 vname_cc
= kmalloc(vlen
, GFP_KERNEL
);
1194 for (i
= 0; i
< vlen
; i
++)
1195 vname_cc
[i
] = ncp_tolower(in
, vname
[i
]);
1199 iname_start
= iname
;
1200 iname_end
= iname
+ *ilen
- 1;
1201 vname_end
= vname
+ vlen
;
1203 while (vname
< vname_end
) {
1207 if ( (chl
= in
->char2uni(vname
, vname_end
- vname
, &ec
)) < 0) {
1213 /* unitolower should be here! */
1215 if (NCP_IS_FLAG(server
, NCP_FLAG_UTF8
)) {
1218 k
= utf8_wctomb(iname
, ec
, iname_end
- iname
);
1220 err
= -ENAMETOOLONG
;
1225 if ( (chl
= out
->uni2char(ec
, iname
, iname_end
- iname
)) >= 0) {
1230 if (iname_end
- iname
< 5) {
1231 err
= -ENAMETOOLONG
;
1235 for (k
= 4; k
> 0; k
--) {
1238 v
= (ec
& 0xF) + '0';
1251 *ilen
= iname
- iname_start
;
1262 ncp__io2vol(unsigned char *vname
, unsigned int *vlen
,
1263 const unsigned char *iname
, unsigned int ilen
, int cc
)
1268 return -ENAMETOOLONG
;
1271 for (i
= 0; i
< ilen
; i
++) {
1272 *vname
= toupper(*iname
);
1277 memmove(vname
, iname
, ilen
);
1287 ncp__vol2io(unsigned char *iname
, unsigned int *ilen
,
1288 const unsigned char *vname
, unsigned int vlen
, int cc
)
1293 return -ENAMETOOLONG
;
1296 for (i
= 0; i
< vlen
; i
++) {
1297 *iname
= tolower(*vname
);
1302 memmove(iname
, vname
, vlen
);