1/* 2 * ncplib_kernel.c 3 * 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 * 9 */ 10 11 12#include <linux/config.h> 13 14#include "ncplib_kernel.h" 15 16static inline void assert_server_locked(struct ncp_server *server) 17{ 18 if (server->lock == 0) { 19 DPRINTK("ncpfs: server not locked!\n"); 20 } 21} 22 23static void ncp_add_byte(struct ncp_server *server, __u8 x) 24{ 25 assert_server_locked(server); 26 *(__u8 *) (&(server->packet[server->current_size])) = x; 27 server->current_size += 1; 28 return; 29} 30 31static void ncp_add_word(struct ncp_server *server, __u16 x) 32{ 33 assert_server_locked(server); 34 put_unaligned(x, (__u16 *) (&(server->packet[server->current_size]))); 35 server->current_size += 2; 36 return; 37} 38 39static void ncp_add_dword(struct ncp_server *server, __u32 x) 40{ 41 assert_server_locked(server); 42 put_unaligned(x, (__u32 *) (&(server->packet[server->current_size]))); 43 server->current_size += 4; 44 return; 45} 46 47static void ncp_add_mem(struct ncp_server *server, const void *source, int size) 48{ 49 assert_server_locked(server); 50 memcpy(&(server->packet[server->current_size]), source, size); 51 server->current_size += size; 52 return; 53} 54 55static void ncp_add_pstring(struct ncp_server *server, const char *s) 56{ 57 int len = strlen(s); 58 assert_server_locked(server); 59 if (len > 255) { 60 DPRINTK("ncpfs: string too long: %s\n", s); 61 len = 255; 62 } 63 ncp_add_byte(server, len); 64 ncp_add_mem(server, s, len); 65 return; 66} 67 68static inline void ncp_init_request(struct ncp_server *server) 69{ 70 ncp_lock_server(server); 71 72 server->current_size = sizeof(struct ncp_request_header); 73 server->has_subfunction = 0; 74} 75 76static inline void ncp_init_request_s(struct ncp_server *server, int subfunction) 77{ 78 ncp_lock_server(server); 79 80 server->current_size = sizeof(struct ncp_request_header) + 2; 81 ncp_add_byte(server, subfunction); 82 83 server->has_subfunction = 1; 84} 85 86static inline char * 87 ncp_reply_data(struct ncp_server *server, int offset) 88{ 89 return &(server->packet[sizeof(struct ncp_reply_header) + offset]); 90} 91 92static __u8 93 ncp_reply_byte(struct ncp_server *server, int offset) 94{ 95 return get_unaligned((__u8 *) ncp_reply_data(server, offset)); 96} 97 98static __u16 99 ncp_reply_word(struct ncp_server *server, int offset) 100{ 101 return get_unaligned((__u16 *) ncp_reply_data(server, offset)); 102} 103 104static __u32 105 ncp_reply_dword(struct ncp_server *server, int offset) 106{ 107 return get_unaligned((__u32 *) ncp_reply_data(server, offset)); 108} 109 110int 111ncp_negotiate_buffersize(struct ncp_server *server, int size, int *target) 112{ 113 int result; 114 115 ncp_init_request(server); 116 ncp_add_word(server, htons(size)); 117 118 if ((result = ncp_request(server, 33)) != 0) { 119 ncp_unlock_server(server); 120 return result; 121 } 122 *target = min_t(unsigned int, ntohs(ncp_reply_word(server, 0)), size); 123 124 ncp_unlock_server(server); 125 return 0; 126} 127 128 129/* options: 130 * bit 0 ipx checksum 131 * bit 1 packet signing 132 */ 133int 134ncp_negotiate_size_and_options(struct ncp_server *server, 135 int size, int options, int *ret_size, int *ret_options) { 136 int result; 137 138 /* there is minimum */ 139 if (size < NCP_BLOCK_SIZE) size = NCP_BLOCK_SIZE; 140 141 ncp_init_request(server); 142 ncp_add_word(server, htons(size)); 143 ncp_add_byte(server, options); 144 145 if ((result = ncp_request(server, 0x61)) != 0) 146 { 147 ncp_unlock_server(server); 148 return result; 149 } 150 151 /* NCP over UDP returns 0 (!!!) */ 152 result = ntohs(ncp_reply_word(server, 0)); 153 if (result >= NCP_BLOCK_SIZE) 154 size = min(result, size); 155 *ret_size = size; 156 *ret_options = ncp_reply_byte(server, 4); 157 158 ncp_unlock_server(server); 159 return 0; 160} 161 162int 163ncp_get_volume_info_with_number(struct ncp_server *server, int n, 164 struct ncp_volume_info *target) 165{ 166 int result; 167 int len; 168 169 ncp_init_request_s(server, 44); 170 ncp_add_byte(server, n); 171 172 if ((result = ncp_request(server, 22)) != 0) { 173 goto out; 174 } 175 target->total_blocks = ncp_reply_dword(server, 0); 176 target->free_blocks = ncp_reply_dword(server, 4); 177 target->purgeable_blocks = ncp_reply_dword(server, 8); 178 target->not_yet_purgeable_blocks = ncp_reply_dword(server, 12); 179 target->total_dir_entries = ncp_reply_dword(server, 16); 180 target->available_dir_entries = ncp_reply_dword(server, 20); 181 target->sectors_per_block = ncp_reply_byte(server, 28); 182 183 memset(&(target->volume_name), 0, sizeof(target->volume_name)); 184 185 result = -EIO; 186 len = ncp_reply_byte(server, 29); 187 if (len > NCP_VOLNAME_LEN) { 188 DPRINTK("ncpfs: volume name too long: %d\n", len); 189 goto out; 190 } 191 memcpy(&(target->volume_name), ncp_reply_data(server, 30), len); 192 result = 0; 193out: 194 ncp_unlock_server(server); 195 return result; 196} 197 198int 199ncp_close_file(struct ncp_server *server, const char *file_id) 200{ 201 int result; 202 203 ncp_init_request(server); 204 ncp_add_byte(server, 0); 205 ncp_add_mem(server, file_id, 6); 206 207 result = ncp_request(server, 66); 208 ncp_unlock_server(server); 209 return result; 210} 211 212int 213ncp_make_closed(struct inode *inode) 214{ 215 int err; 216 217 err = 0; 218 down(&NCP_FINFO(inode)->open_sem); 219 if (atomic_read(&NCP_FINFO(inode)->opened) == 1) { 220 atomic_set(&NCP_FINFO(inode)->opened, 0); 221 err = ncp_close_file(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle); 222 223 if (!err) 224 PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n", 225 NCP_FINFO(inode)->volNumber, 226 NCP_FINFO(inode)->dirEntNum, err); 227 } 228 up(&NCP_FINFO(inode)->open_sem); 229 return err; 230} 231 232static void ncp_add_handle_path(struct ncp_server *server, __u8 vol_num, 233 __u32 dir_base, int have_dir_base, 234 const char *path) 235{ 236 ncp_add_byte(server, vol_num); 237 ncp_add_dword(server, dir_base); 238 if (have_dir_base != 0) { 239 ncp_add_byte(server, 1); /* dir_base */ 240 } else { 241 ncp_add_byte(server, 0xff); /* no handle */ 242 } 243 if (path != NULL) { 244 ncp_add_byte(server, 1); /* 1 component */ 245 ncp_add_pstring(server, path); 246 } else { 247 ncp_add_byte(server, 0); 248 } 249} 250 251static void ncp_extract_file_info(void *structure, struct nw_info_struct *target) 252{ 253 __u8 *name_len; 254 const int info_struct_size = sizeof(struct nw_info_struct) - 257; 255 256 memcpy(target, structure, info_struct_size); 257 name_len = structure + info_struct_size; 258 target->nameLen = *name_len; 259 memcpy(target->entryName, name_len + 1, *name_len); 260 target->entryName[*name_len] = '\0'; 261 target->volNumber = le32_to_cpu(target->volNumber); 262 return; 263} 264 265/* 266 * Returns information for a (one-component) name relative to 267 * the specified directory. 268 */ 269int ncp_obtain_info(struct ncp_server *server, struct inode *dir, char *path, 270 struct nw_info_struct *target) 271{ 272 __u8 volnum = NCP_FINFO(dir)->volNumber; 273 __u32 dirent = NCP_FINFO(dir)->dirEntNum; 274 int result; 275 276 if (target == NULL) { 277 printk(KERN_ERR "ncp_obtain_info: invalid call\n"); 278 return -EINVAL; 279 } 280 ncp_init_request(server); 281 ncp_add_byte(server, 6); /* subfunction */ 282 ncp_add_byte(server, server->name_space[volnum]); 283 ncp_add_byte(server, server->name_space[volnum]); /* N.B. twice ?? */ 284 ncp_add_word(server, htons(0x0680)); /* get all */ 285 ncp_add_dword(server, RIM_ALL); 286 ncp_add_handle_path(server, volnum, dirent, 1, path); 287 288 if ((result = ncp_request(server, 87)) != 0) 289 goto out; 290 ncp_extract_file_info(ncp_reply_data(server, 0), target); 291 292out: 293 ncp_unlock_server(server); 294 return result; 295} 296 297#ifdef CONFIG_NCPFS_NFS_NS 298static int 299ncp_obtain_DOS_dir_base(struct ncp_server *server, 300 __u8 volnum, __u32 dirent, 301 char *path, /* At most 1 component */ 302 __u32 *DOS_dir_base) 303{ 304 int result; 305 306 ncp_init_request(server); 307 ncp_add_byte(server, 6); /* subfunction */ 308 ncp_add_byte(server, server->name_space[volnum]); 309 ncp_add_byte(server, server->name_space[volnum]); 310 ncp_add_word(server, htons(0x0680)); /* get all */ 311 ncp_add_dword(server, RIM_DIRECTORY); 312 ncp_add_handle_path(server, volnum, dirent, 1, path); 313 314 if ((result = ncp_request(server, 87)) == 0) 315 { 316 if (DOS_dir_base) *DOS_dir_base=ncp_reply_dword(server, 0x34); 317 } 318 ncp_unlock_server(server); 319 return result; 320} 321#endif /* CONFIG_NCPFS_NFS_NS */ 322 323static inline int 324ncp_get_known_namespace(struct ncp_server *server, __u8 volume) 325{ 326#if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) 327 int result; 328 __u8 *namespace; 329 __u16 no_namespaces; 330 331 ncp_init_request(server); 332 ncp_add_byte(server, 24); /* Subfunction: Get Name Spaces Loaded */ 333 ncp_add_word(server, 0); 334 ncp_add_byte(server, volume); 335 336 if ((result = ncp_request(server, 87)) != 0) { 337 ncp_unlock_server(server); 338 return NW_NS_DOS; /* not result ?? */ 339 } 340 341 result = NW_NS_DOS; 342 no_namespaces = le16_to_cpu(ncp_reply_word(server, 0)); 343 namespace = ncp_reply_data(server, 2); 344 345 while (no_namespaces > 0) { 346 DPRINTK("get_namespaces: found %d on %d\n", *namespace, volume); 347 348#ifdef CONFIG_NCPFS_NFS_NS 349 if ((*namespace == NW_NS_NFS) && !(server->m.flags&NCP_MOUNT_NO_NFS)) 350 { 351 result = NW_NS_NFS; 352 break; 353 } 354#endif /* CONFIG_NCPFS_NFS_NS */ 355#ifdef CONFIG_NCPFS_OS2_NS 356 if ((*namespace == NW_NS_OS2) && !(server->m.flags&NCP_MOUNT_NO_OS2)) 357 { 358 result = NW_NS_OS2; 359 } 360#endif /* CONFIG_NCPFS_OS2_NS */ 361 namespace += 1; 362 no_namespaces -= 1; 363 } 364 ncp_unlock_server(server); 365 return result; 366#else /* neither OS2 nor NFS - only DOS */ 367 return NW_NS_DOS; 368#endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */ 369} 370 371static int 372ncp_ObtainSpecificDirBase(struct ncp_server *server, 373 __u8 nsSrc, __u8 nsDst, __u8 vol_num, __u32 dir_base, 374 char *path, /* At most 1 component */ 375 __u32 *dirEntNum, __u32 *DosDirNum) 376{ 377 int result; 378 379 ncp_init_request(server); 380 ncp_add_byte(server, 6); /* subfunction */ 381 ncp_add_byte(server, nsSrc); 382 ncp_add_byte(server, nsDst); 383 ncp_add_word(server, htons(0x0680)); /* get all */ 384 ncp_add_dword(server, RIM_ALL); 385 ncp_add_handle_path(server, vol_num, dir_base, 1, path); 386 387 if ((result = ncp_request(server, 87)) != 0) 388 { 389 ncp_unlock_server(server); 390 return result; 391 } 392 393 if (dirEntNum) 394 *dirEntNum = ncp_reply_dword(server, 0x30); 395 if (DosDirNum) 396 *DosDirNum = ncp_reply_dword(server, 0x34); 397 ncp_unlock_server(server); 398 return 0; 399} 400 401int 402ncp_mount_subdir(struct ncp_server *server, struct nw_info_struct *i, 403 __u8 volNumber, __u8 srcNS, __u32 dirEntNum) 404{ 405 int dstNS; 406 int result; 407 __u32 newDirEnt; 408 __u32 newDosEnt; 409 410 dstNS = ncp_get_known_namespace(server, volNumber); 411 if ((result = ncp_ObtainSpecificDirBase(server, srcNS, dstNS, volNumber, 412 dirEntNum, NULL, &newDirEnt, &newDosEnt)) != 0) 413 { 414 return result; 415 } 416 server->name_space[volNumber] = dstNS; 417 i->volNumber = volNumber; 418 i->dirEntNum = newDirEnt; 419 i->DosDirNum = newDosEnt; 420 server->m.mounted_vol[1] = 0; 421 server->m.mounted_vol[0] = 'X'; 422 return 0; 423} 424 425int 426ncp_lookup_volume(struct ncp_server *server, char *volname, 427 struct nw_info_struct *target) 428{ 429 int result; 430 int volnum; 431 432 DPRINTK("ncp_lookup_volume: looking up vol %s\n", volname); 433 434 ncp_init_request(server); 435 ncp_add_byte(server, 22); /* Subfunction: Generate dir handle */ 436 ncp_add_byte(server, 0); /* DOS namespace */ 437 ncp_add_byte(server, 0); /* reserved */ 438 ncp_add_byte(server, 0); /* reserved */ 439 ncp_add_byte(server, 0); /* reserved */ 440 441 ncp_add_byte(server, 0); /* faked volume number */ 442 ncp_add_dword(server, 0); /* faked dir_base */ 443 ncp_add_byte(server, 0xff); /* Don't have a dir_base */ 444 ncp_add_byte(server, 1); /* 1 path component */ 445 ncp_add_pstring(server, volname); 446 447 if ((result = ncp_request(server, 87)) != 0) { 448 ncp_unlock_server(server); 449 return result; 450 } 451 memset(target, 0, sizeof(*target)); 452 target->DosDirNum = target->dirEntNum = ncp_reply_dword(server, 4); 453 target->volNumber = volnum = ncp_reply_byte(server, 8); 454 ncp_unlock_server(server); 455 456 server->name_space[volnum] = ncp_get_known_namespace(server, volnum); 457 458 DPRINTK("lookup_vol: namespace[%d] = %d\n", 459 volnum, server->name_space[volnum]); 460 461 target->nameLen = strlen(volname); 462 memcpy(target->entryName, volname, target->nameLen+1); 463 target->attributes = aDIR; 464 /* set dates to Jan 1, 1986 00:00 */ 465 target->creationTime = target->modifyTime = cpu_to_le16(0x0000); 466 target->creationDate = target->modifyDate = target->lastAccessDate = cpu_to_le16(0x0C21); 467 return 0; 468} 469 470int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *server, 471 struct inode *dir, 472 const char *path, 473 __u32 info_mask, 474 const struct nw_modify_dos_info *info) 475{ 476 __u8 volnum = NCP_FINFO(dir)->volNumber; 477 __u32 dirent = NCP_FINFO(dir)->dirEntNum; 478 int result; 479 480 ncp_init_request(server); 481 ncp_add_byte(server, 7); /* subfunction */ 482 ncp_add_byte(server, server->name_space[volnum]); 483 ncp_add_byte(server, 0); /* reserved */ 484 ncp_add_word(server, htons(0x0680)); /* search attribs: all */ 485 486 ncp_add_dword(server, info_mask); 487 ncp_add_mem(server, info, sizeof(*info)); 488 ncp_add_handle_path(server, volnum, dirent, 1, path); 489 490 result = ncp_request(server, 87); 491 ncp_unlock_server(server); 492 return result; 493} 494 495int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server, 496 struct inode *dir, 497 __u32 info_mask, 498 const struct nw_modify_dos_info *info) 499{ 500 return ncp_modify_file_or_subdir_dos_info_path(server, dir, NULL, 501 info_mask, info); 502} 503 504static int 505ncp_DeleteNSEntry(struct ncp_server *server, 506 __u8 have_dir_base, __u8 volnum, __u32 dirent, 507 char* name, __u8 ns, int attr) 508{ 509 int result; 510 511 ncp_init_request(server); 512 ncp_add_byte(server, 8); /* subfunction */ 513 ncp_add_byte(server, ns); 514 ncp_add_byte(server, 0); /* reserved */ 515 ncp_add_word(server, attr); /* search attribs: all */ 516 ncp_add_handle_path(server, volnum, dirent, have_dir_base, name); 517 518 result = ncp_request(server, 87); 519 ncp_unlock_server(server); 520 return result; 521} 522 523int 524ncp_del_file_or_subdir2(struct ncp_server *server, 525 struct dentry *dentry) 526{ 527 struct inode *inode = dentry->d_inode; 528 __u8 volnum; 529 __u32 dirent; 530 531 if (!inode) { 532#if CONFIG_NCPFS_DEBUGDENTRY 533 PRINTK("ncpfs: ncpdel2: dentry->d_inode == NULL\n"); 534#endif 535 return 0xFF; /* Any error */ 536 } 537 volnum = NCP_FINFO(inode)->volNumber; 538 dirent = NCP_FINFO(inode)->DosDirNum; 539 return ncp_DeleteNSEntry(server, 1, volnum, dirent, NULL, NW_NS_DOS, htons(0x0680)); 540} 541 542int 543ncp_del_file_or_subdir(struct ncp_server *server, 544 struct inode *dir, char *name) 545{ 546 __u8 volnum = NCP_FINFO(dir)->volNumber; 547 __u32 dirent = NCP_FINFO(dir)->dirEntNum; 548 549#ifdef CONFIG_NCPFS_NFS_NS 550 if (server->name_space[volnum]==NW_NS_NFS) 551 { 552 int result; 553 554 result=ncp_obtain_DOS_dir_base(server, volnum, dirent, name, &dirent); 555 if (result) return result; 556 return ncp_DeleteNSEntry(server, 1, volnum, dirent, NULL, NW_NS_DOS, htons(0x0680)); 557 } 558 else 559#endif /* CONFIG_NCPFS_NFS_NS */ 560 return ncp_DeleteNSEntry(server, 1, volnum, dirent, name, server->name_space[volnum], htons(0x0680)); 561} 562 563static inline void ConvertToNWfromDWORD(__u32 sfd, __u8 ret[6]) 564{ 565 __u16 *dest = (__u16 *) ret; 566 memcpy(ret + 2, &sfd, 4); 567 dest[0] = cpu_to_le16((le16_to_cpu(dest[1]) + le16_to_cpu(1))); 568 return; 569} 570 571/* If both dir and name are NULL, then in target there's already a 572 looked-up entry that wants to be opened. */ 573int ncp_open_create_file_or_subdir(struct ncp_server *server, 574 struct inode *dir, char *name, 575 int open_create_mode, 576 __u32 create_attributes, 577 int desired_acc_rights, 578 struct ncp_entry_info *target) 579{ 580 __u16 search_attribs = ntohs(0x0600); 581 __u8 volnum = target->i.volNumber; 582 __u32 dirent = target->i.dirEntNum; 583 int result; 584 585 if (dir) 586 { 587 volnum = NCP_FINFO(dir)->volNumber; 588 dirent = NCP_FINFO(dir)->dirEntNum; 589 } 590 591 if ((create_attributes & aDIR) != 0) { 592 search_attribs |= ntohs(0x0080); 593 } 594 ncp_init_request(server); 595 ncp_add_byte(server, 1); /* subfunction */ 596 ncp_add_byte(server, server->name_space[volnum]); 597 ncp_add_byte(server, open_create_mode); 598 ncp_add_word(server, search_attribs); 599 ncp_add_dword(server, RIM_ALL); 600 ncp_add_dword(server, create_attributes); 601 /* The desired acc rights seem to be the inherited rights mask 602 for directories */ 603 ncp_add_word(server, desired_acc_rights); 604 ncp_add_handle_path(server, volnum, dirent, 1, name); 605 606 if ((result = ncp_request(server, 87)) != 0) 607 goto out; 608 if (!(create_attributes & aDIR)) 609 target->opened = 1; 610 target->server_file_handle = ncp_reply_dword(server, 0); 611 target->open_create_action = ncp_reply_byte(server, 4); 612 613 /* in target there's a new finfo to fill */ 614 ncp_extract_file_info(ncp_reply_data(server, 6), &(target->i)); 615 ConvertToNWfromDWORD(target->server_file_handle, target->file_handle); 616 617out: 618 ncp_unlock_server(server); 619 return result; 620} 621 622int 623ncp_initialize_search(struct ncp_server *server, struct inode *dir, 624 struct nw_search_sequence *target) 625{ 626 __u8 volnum = NCP_FINFO(dir)->volNumber; 627 __u32 dirent = NCP_FINFO(dir)->dirEntNum; 628 int result; 629 630 ncp_init_request(server); 631 ncp_add_byte(server, 2); /* subfunction */ 632 ncp_add_byte(server, server->name_space[volnum]); 633 ncp_add_byte(server, 0); /* reserved */ 634 ncp_add_handle_path(server, volnum, dirent, 1, NULL); 635 636 result = ncp_request(server, 87); 637 if (result) 638 goto out; 639 memcpy(target, ncp_reply_data(server, 0), sizeof(*target)); 640 641out: 642 ncp_unlock_server(server); 643 return result; 644} 645 646/* Search for everything */ 647int ncp_search_for_file_or_subdir(struct ncp_server *server, 648 struct nw_search_sequence *seq, 649 struct nw_info_struct *target) 650{ 651 int result; 652 653 ncp_init_request(server); 654 ncp_add_byte(server, 3); /* subfunction */ 655 ncp_add_byte(server, server->name_space[seq->volNumber]); 656 ncp_add_byte(server, 0); /* data stream (???) */ 657 ncp_add_word(server, htons(0x0680)); /* Search attribs */ 658 ncp_add_dword(server, RIM_ALL); /* return info mask */ 659 ncp_add_mem(server, seq, 9); 660#ifdef CONFIG_NCPFS_NFS_NS 661 if (server->name_space[seq->volNumber] == NW_NS_NFS) { 662 ncp_add_byte(server, 0); /* 0 byte pattern */ 663 } else 664#endif 665 { 666 ncp_add_byte(server, 2); /* 2 byte pattern */ 667 ncp_add_byte(server, 0xff); /* following is a wildcard */ 668 ncp_add_byte(server, '*'); 669 } 670 671 if ((result = ncp_request(server, 87)) != 0) 672 goto out; 673 memcpy(seq, ncp_reply_data(server, 0), sizeof(*seq)); 674 ncp_extract_file_info(ncp_reply_data(server, 10), target); 675 676out: 677 ncp_unlock_server(server); 678 return result; 679} 680 681int 682ncp_RenameNSEntry(struct ncp_server *server, 683 struct inode *old_dir, char *old_name, int old_type, 684 struct inode *new_dir, char *new_name) 685{ 686 int result = -EINVAL; 687 688 if ((old_dir == NULL) || (old_name == NULL) || 689 (new_dir == NULL) || (new_name == NULL)) 690 goto out; 691 692 ncp_init_request(server); 693 ncp_add_byte(server, 4); /* subfunction */ 694 ncp_add_byte(server, server->name_space[NCP_FINFO(old_dir)->volNumber]); 695 ncp_add_byte(server, 1); /* rename flag */ 696 ncp_add_word(server, old_type); /* search attributes */ 697 698 /* source Handle Path */ 699 ncp_add_byte(server, NCP_FINFO(old_dir)->volNumber); 700 ncp_add_dword(server, NCP_FINFO(old_dir)->dirEntNum); 701 ncp_add_byte(server, 1); 702 ncp_add_byte(server, 1); /* 1 source component */ 703 704 /* dest Handle Path */ 705 ncp_add_byte(server, NCP_FINFO(new_dir)->volNumber); 706 ncp_add_dword(server, NCP_FINFO(new_dir)->dirEntNum); 707 ncp_add_byte(server, 1); 708 ncp_add_byte(server, 1); /* 1 destination component */ 709 710 /* source path string */ 711 ncp_add_pstring(server, old_name); 712 /* dest path string */ 713 ncp_add_pstring(server, new_name); 714 715 result = ncp_request(server, 87); 716 ncp_unlock_server(server); 717out: 718 return result; 719} 720 721int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, 722 struct inode *old_dir, char *old_name, 723 struct inode *new_dir, char *new_name) 724{ 725 int result; 726 int old_type = htons(0x0600); 727 728/* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */ 729 result = ncp_RenameNSEntry(server, old_dir, old_name, old_type, 730 new_dir, new_name); 731 if (result == 0xFF) /* File Not Found, try directory */ 732 { 733 old_type = htons(0x1600); 734 result = ncp_RenameNSEntry(server, old_dir, old_name, old_type, 735 new_dir, new_name); 736 } 737 if (result != 0x92) return result; /* All except NO_FILES_RENAMED */ 738 result = ncp_del_file_or_subdir(server, new_dir, new_name); 739 if (result != 0) return -EACCES; 740 result = ncp_RenameNSEntry(server, old_dir, old_name, old_type, 741 new_dir, new_name); 742 return result; 743} 744 745 746/* We have to transfer to/from user space */ 747int 748ncp_read_kernel(struct ncp_server *server, const char *file_id, 749 __u32 offset, __u16 to_read, char *target, int *bytes_read) 750{ 751 char *source; 752 int result; 753 754 ncp_init_request(server); 755 ncp_add_byte(server, 0); 756 ncp_add_mem(server, file_id, 6); 757 ncp_add_dword(server, htonl(offset)); 758 ncp_add_word(server, htons(to_read)); 759 760 if ((result = ncp_request(server, 72)) != 0) { 761 goto out; 762 } 763 *bytes_read = ntohs(ncp_reply_word(server, 0)); 764 source = ncp_reply_data(server, 2 + (offset & 1)); 765 766 memcpy(target, source, *bytes_read); 767out: 768 ncp_unlock_server(server); 769 return result; 770} 771 772/* There is a problem... egrep and some other silly tools do: 773 x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768); 774 read(<ncpfs fd>, x, 32768); 775 Now copying read result by copy_to_user causes pagefault. This pagefault 776 could not be handled because of server was locked due to read. So we have 777 to use temporary buffer. So ncp_unlock_server must be done before 778 copy_to_user (and for write, copy_from_user must be done before 779 ncp_init_request... same applies for send raw packet ioctl). Because of 780 file is normally read in bigger chunks, caller provides kmalloced 781 (vmalloced) chunk of memory with size >= to_read... 782 */ 783int 784ncp_read_bounce(struct ncp_server *server, const char *file_id, 785 __u32 offset, __u16 to_read, char *target, int *bytes_read, 786 void* bounce, __u32 bufsize) 787{ 788 int result; 789 790 ncp_init_request(server); 791 ncp_add_byte(server, 0); 792 ncp_add_mem(server, file_id, 6); 793 ncp_add_dword(server, htonl(offset)); 794 ncp_add_word(server, htons(to_read)); 795 result = ncp_request2(server, 72, bounce, bufsize); 796 ncp_unlock_server(server); 797 if (!result) { 798 int len = be16_to_cpu(get_unaligned((__u16*)((char*)bounce + 799 sizeof(struct ncp_reply_header)))); 800 result = -EIO; 801 if (len <= to_read) { 802 char* source; 803 804 source = (char*)bounce + 805 sizeof(struct ncp_reply_header) + 2 + 806 (offset & 1); 807 *bytes_read = len; 808 result = 0; 809 if (copy_to_user(target, source, len)) 810 result = -EFAULT; 811 } 812 } 813 return result; 814} 815 816int 817ncp_write_kernel(struct ncp_server *server, const char *file_id, 818 __u32 offset, __u16 to_write, 819 const char *source, int *bytes_written) 820{ 821 int result; 822 823 ncp_init_request(server); 824 ncp_add_byte(server, 0); 825 ncp_add_mem(server, file_id, 6); 826 ncp_add_dword(server, htonl(offset)); 827 ncp_add_word(server, htons(to_write)); 828 ncp_add_mem(server, source, to_write); 829 830 if ((result = ncp_request(server, 73)) == 0) 831 *bytes_written = to_write; 832 ncp_unlock_server(server); 833 return result; 834} 835 836#ifdef CONFIG_NCPFS_IOCTL_LOCKING 837int 838ncp_LogPhysicalRecord(struct ncp_server *server, const char *file_id, 839 __u8 locktype, __u32 offset, __u32 length, __u16 timeout) 840{ 841 int result; 842 843 ncp_init_request(server); 844 ncp_add_byte(server, locktype); 845 ncp_add_mem(server, file_id, 6); 846 ncp_add_dword(server, htonl(offset)); 847 ncp_add_dword(server, htonl(length)); 848 ncp_add_word(server, htons(timeout)); 849 850 if ((result = ncp_request(server, 0x1A)) != 0) 851 { 852 ncp_unlock_server(server); 853 return result; 854 } 855 ncp_unlock_server(server); 856 return 0; 857} 858 859int 860ncp_ClearPhysicalRecord(struct ncp_server *server, const char *file_id, 861 __u32 offset, __u32 length) 862{ 863 int result; 864 865 ncp_init_request(server); 866 ncp_add_byte(server, 0); /* who knows... lanalyzer says that */ 867 ncp_add_mem(server, file_id, 6); 868 ncp_add_dword(server, htonl(offset)); 869 ncp_add_dword(server, htonl(length)); 870 871 if ((result = ncp_request(server, 0x1E)) != 0) 872 { 873 ncp_unlock_server(server); 874 return result; 875 } 876 ncp_unlock_server(server); 877 return 0; 878} 879#endif /* CONFIG_NCPFS_IOCTL_LOCKING */ 880 881#ifdef CONFIG_NCPFS_NLS 882/* This are the NLS conversion routines with inspirations and code parts 883 * from the vfat file system and hints from Petr Vandrovec. 884 */ 885 886inline unsigned char 887ncp__tolower(struct nls_table *t, unsigned char c) 888{ 889 unsigned char nc = t->charset2lower[c]; 890 891 return nc ? nc : c; 892} 893 894inline unsigned char 895ncp__toupper(struct nls_table *t, unsigned char c) 896{ 897 unsigned char nc = t->charset2upper[c]; 898 899 return nc ? nc : c; 900} 901 902int 903ncp__io2vol(struct ncp_server *server, unsigned char *vname, unsigned int *vlen, 904 const unsigned char *iname, unsigned int ilen, int cc) 905{ 906 struct nls_table *in = server->nls_io; 907 struct nls_table *out = server->nls_vol; 908 unsigned char *vname_start; 909 unsigned char *vname_end; 910 const unsigned char *iname_end; 911 912 iname_end = iname + ilen; 913 vname_start = vname; 914 vname_end = vname + *vlen - 1; 915 916 while (iname < iname_end) { 917 int chl; 918 wchar_t ec; 919 920 if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) { 921 int k; 922 923 k = utf8_mbtowc(&ec, iname, iname_end - iname); 924 if (k < 0) 925 return -EINVAL; 926 iname += k; 927 } else { 928 if (*iname == NCP_ESC) { 929 int k; 930 931 if (iname_end - iname < 5) 932 goto nospec; 933 934 ec = 0; 935 for (k = 1; k < 5; k++) { 936 unsigned char nc; 937 938 nc = iname[k] - '0'; 939 if (nc >= 10) { 940 nc -= 'A' - '0' - 10; 941 if ((nc < 10) || (nc > 15)) { 942 goto nospec; 943 } 944 } 945 ec = (ec << 4) | nc; 946 } 947 iname += 5; 948 } else { 949nospec:; 950 if ( (chl = in->char2uni(iname, iname_end - iname, &ec)) < 0) 951 return chl; 952 iname += chl; 953 } 954 } 955 956 /* unitoupper should be here! */ 957 958 chl = out->uni2char(ec, vname, vname_end - vname); 959 if (chl < 0) 960 return chl; 961 962 /* this is wrong... */ 963 if (cc) { 964 int chi; 965 966 for (chi = 0; chi < chl; chi++){ 967 vname[chi] = ncp_toupper(out, vname[chi]); 968 } 969 } 970 vname += chl; 971 } 972 973 *vname = 0; 974 *vlen = vname - vname_start; 975 return 0; 976} 977 978int 979ncp__vol2io(struct ncp_server *server, unsigned char *iname, unsigned int *ilen, 980 const unsigned char *vname, unsigned int vlen, int cc) 981{ 982 struct nls_table *in = server->nls_vol; 983 struct nls_table *out = server->nls_io; 984 const unsigned char *vname_end; 985 unsigned char *iname_start; 986 unsigned char *iname_end; 987 unsigned char *vname_cc; 988 int err; 989 990 vname_cc = NULL; 991 992 if (cc) { 993 int i; 994 995 /* this is wrong! */ 996 vname_cc = kmalloc(vlen, GFP_KERNEL); 997 if (!vname_cc) 998 return -ENOMEM; 999 for (i = 0; i < vlen; i++) 1000 vname_cc[i] = ncp_tolower(in, vname[i]); 1001 vname = vname_cc; 1002 } 1003 1004 iname_start = iname; 1005 iname_end = iname + *ilen - 1; 1006 vname_end = vname + vlen; 1007 1008 while (vname < vname_end) { 1009 wchar_t ec; 1010 int chl; 1011 1012 if ( (chl = in->char2uni(vname, vname_end - vname, &ec)) < 0) { 1013 err = chl; 1014 goto quit; 1015 } 1016 vname += chl; 1017 1018 /* unitolower should be here! */ 1019 1020 if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) { 1021 int k; 1022 1023 k = utf8_wctomb(iname, ec, iname_end - iname); 1024 if (k < 0) { 1025 err = -ENAMETOOLONG; 1026 goto quit; 1027 } 1028 iname += k; 1029 } else { 1030 if ( (chl = out->uni2char(ec, iname, iname_end - iname)) >= 0) { 1031 iname += chl; 1032 } else { 1033 int k; 1034 1035 if (iname_end - iname < 5) { 1036 err = -ENAMETOOLONG; 1037 goto quit; 1038 } 1039 *iname = NCP_ESC; 1040 for (k = 4; k > 0; k--) { 1041 unsigned char v; 1042 1043 v = (ec & 0xF) + '0'; 1044 if (v > '9') { 1045 v += 'A' - '9' - 1; 1046 } 1047 iname[k] = v; 1048 ec >>= 4; 1049 } 1050 iname += 5; 1051 } 1052 } 1053 } 1054 1055 *iname = 0; 1056 *ilen = iname - iname_start; 1057 err = 0; 1058quit:; 1059 if (cc) 1060 kfree(vname_cc); 1061 return err; 1062} 1063 1064#else 1065 1066int 1067ncp__io2vol(unsigned char *vname, unsigned int *vlen, 1068 const unsigned char *iname, unsigned int ilen, int cc) 1069{ 1070 int i; 1071 1072 if (*vlen <= ilen) 1073 return -ENAMETOOLONG; 1074 1075 if (cc) 1076 for (i = 0; i < ilen; i++) { 1077 *vname = toupper(*iname); 1078 vname++; 1079 iname++; 1080 } 1081 else { 1082 memmove(vname, iname, ilen); 1083 vname += ilen; 1084 } 1085 1086 *vlen = ilen; 1087 *vname = 0; 1088 return 0; 1089} 1090 1091int 1092ncp__vol2io(unsigned char *iname, unsigned int *ilen, 1093 const unsigned char *vname, unsigned int vlen, int cc) 1094{ 1095 int i; 1096 1097 if (*ilen <= vlen) 1098 return -ENAMETOOLONG; 1099 1100 if (cc) 1101 for (i = 0; i < vlen; i++) { 1102 *iname = tolower(*vname); 1103 iname++; 1104 vname++; 1105 } 1106 else { 1107 memmove(iname, vname, vlen); 1108 iname += vlen; 1109 } 1110 1111 *ilen = vlen; 1112 *iname = 0; 1113 return 0; 1114} 1115 1116#endif 1117 1118inline int 1119ncp_strnicmp(struct nls_table *t, const unsigned char *s1, 1120 const unsigned char *s2, int n) 1121{ 1122 int i; 1123 1124 for (i=0; i<n; i++) 1125 if (ncp_tolower(t, s1[i]) != ncp_tolower(t, s2[i])) 1126 return 1; 1127 1128 return 0; 1129} 1130