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 * Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info 9 * 10 */ 11 12 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, __le16 x) 32{ 33 assert_server_locked(server); 34 put_unaligned(x, (__le16 *) (&(server->packet[server->current_size]))); 35 server->current_size += 2; 36 return; 37} 38 39static void ncp_add_be16(struct ncp_server *server, __u16 x) 40{ 41 assert_server_locked(server); 42 put_unaligned(cpu_to_be16(x), (__be16 *) (&(server->packet[server->current_size]))); 43 server->current_size += 2; 44} 45 46static void ncp_add_dword(struct ncp_server *server, __le32 x) 47{ 48 assert_server_locked(server); 49 put_unaligned(x, (__le32 *) (&(server->packet[server->current_size]))); 50 server->current_size += 4; 51 return; 52} 53 54static void ncp_add_be32(struct ncp_server *server, __u32 x) 55{ 56 assert_server_locked(server); 57 put_unaligned(cpu_to_be32(x), (__be32 *)(&(server->packet[server->current_size]))); 58 server->current_size += 4; 59} 60 61static inline void ncp_add_dword_lh(struct ncp_server *server, __u32 x) { 62 ncp_add_dword(server, cpu_to_le32(x)); 63} 64 65static void ncp_add_mem(struct ncp_server *server, const void *source, int size) 66{ 67 assert_server_locked(server); 68 memcpy(&(server->packet[server->current_size]), source, size); 69 server->current_size += size; 70 return; 71} 72 73static void ncp_add_pstring(struct ncp_server *server, const char *s) 74{ 75 int len = strlen(s); 76 assert_server_locked(server); 77 if (len > 255) { 78 DPRINTK("ncpfs: string too long: %s\n", s); 79 len = 255; 80 } 81 ncp_add_byte(server, len); 82 ncp_add_mem(server, s, len); 83 return; 84} 85 86static inline void ncp_init_request(struct ncp_server *server) 87{ 88 ncp_lock_server(server); 89 90 server->current_size = sizeof(struct ncp_request_header); 91 server->has_subfunction = 0; 92} 93 94static inline void ncp_init_request_s(struct ncp_server *server, int subfunction) 95{ 96 ncp_lock_server(server); 97 98 server->current_size = sizeof(struct ncp_request_header) + 2; 99 ncp_add_byte(server, subfunction); 100 101 server->has_subfunction = 1; 102} 103 104static inline char * 105 ncp_reply_data(struct ncp_server *server, int offset) 106{ 107 return &(server->packet[sizeof(struct ncp_reply_header) + offset]); 108} 109 110static inline __u8 BVAL(void* data) 111{ 112 return get_unaligned((__u8*)data); 113} 114 115static __u8 116 ncp_reply_byte(struct ncp_server *server, int offset) 117{ 118 return get_unaligned((__u8 *) ncp_reply_data(server, offset)); 119} 120 121static inline __u16 WVAL_LH(void* data) 122{ 123 return le16_to_cpu(get_unaligned((__le16*)data)); 124} 125 126static __u16 127 ncp_reply_le16(struct ncp_server *server, int offset) 128{ 129 return le16_to_cpu(get_unaligned((__le16 *) ncp_reply_data(server, offset))); 130} 131 132static __u16 133 ncp_reply_be16(struct ncp_server *server, int offset) 134{ 135 return be16_to_cpu(get_unaligned((__be16 *) ncp_reply_data(server, offset))); 136} 137 138static inline __u32 DVAL_LH(void* data) 139{ 140 return le32_to_cpu(get_unaligned((__le32*)data)); 141} 142 143static __le32 144 ncp_reply_dword(struct ncp_server *server, int offset) 145{ 146 return get_unaligned((__le32 *) ncp_reply_data(server, offset)); 147} 148 149static inline __u32 ncp_reply_dword_lh(struct ncp_server* server, int offset) { 150 return le32_to_cpu(ncp_reply_dword(server, offset)); 151} 152 153int 154ncp_negotiate_buffersize(struct ncp_server *server, int size, int *target) 155{ 156 int result; 157 158 ncp_init_request(server); 159 ncp_add_be16(server, size); 160 161 if ((result = ncp_request(server, 33)) != 0) { 162 ncp_unlock_server(server); 163 return result; 164 } 165 *target = min_t(unsigned int, ncp_reply_be16(server, 0), size); 166 167 ncp_unlock_server(server); 168 return 0; 169} 170 171 172/* options: 173 * bit 0 ipx checksum 174 * bit 1 packet signing 175 */ 176int 177ncp_negotiate_size_and_options(struct ncp_server *server, 178 int size, int options, int *ret_size, int *ret_options) { 179 int result; 180 181 /* there is minimum */ 182 if (size < NCP_BLOCK_SIZE) size = NCP_BLOCK_SIZE; 183 184 ncp_init_request(server); 185 ncp_add_be16(server, size); 186 ncp_add_byte(server, options); 187 188 if ((result = ncp_request(server, 0x61)) != 0) 189 { 190 ncp_unlock_server(server); 191 return result; 192 } 193 194 /* NCP over UDP returns 0 (!!!) */ 195 result = ncp_reply_be16(server, 0); 196 if (result >= NCP_BLOCK_SIZE) 197 size = min(result, size); 198 *ret_size = size; 199 *ret_options = ncp_reply_byte(server, 4); 200 201 ncp_unlock_server(server); 202 return 0; 203} 204 205int ncp_get_volume_info_with_number(struct ncp_server* server, 206 int n, struct ncp_volume_info* target) { 207 int result; 208 int len; 209 210 ncp_init_request_s(server, 44); 211 ncp_add_byte(server, n); 212 213 if ((result = ncp_request(server, 22)) != 0) { 214 goto out; 215 } 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); 223 224 memset(&(target->volume_name), 0, sizeof(target->volume_name)); 225 226 result = -EIO; 227 len = ncp_reply_byte(server, 29); 228 if (len > NCP_VOLNAME_LEN) { 229 DPRINTK("ncpfs: volume name too long: %d\n", len); 230 goto out; 231 } 232 memcpy(&(target->volume_name), ncp_reply_data(server, 30), len); 233 result = 0; 234out: 235 ncp_unlock_server(server); 236 return result; 237} 238 239int ncp_get_directory_info(struct ncp_server* server, __u8 n, 240 struct ncp_volume_info* target) { 241 int result; 242 int len; 243 244 ncp_init_request_s(server, 45); 245 ncp_add_byte(server, n); 246 247 if ((result = ncp_request(server, 22)) != 0) { 248 goto out; 249 } 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); 257 258 memset(&(target->volume_name), 0, sizeof(target->volume_name)); 259 260 result = -EIO; 261 len = ncp_reply_byte(server, 21); 262 if (len > NCP_VOLNAME_LEN) { 263 DPRINTK("ncpfs: volume name too long: %d\n", len); 264 goto out; 265 } 266 memcpy(&(target->volume_name), ncp_reply_data(server, 22), len); 267 result = 0; 268out: 269 ncp_unlock_server(server); 270 return result; 271} 272 273int 274ncp_close_file(struct ncp_server *server, const char *file_id) 275{ 276 int result; 277 278 ncp_init_request(server); 279 ncp_add_byte(server, 0); 280 ncp_add_mem(server, file_id, 6); 281 282 result = ncp_request(server, 66); 283 ncp_unlock_server(server); 284 return result; 285} 286 287int 288ncp_make_closed(struct inode *inode) 289{ 290 int err; 291 292 err = 0; 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); 297 298 if (!err) 299 PPRINTK("ncp_make_closed: volnum=%d, dirent=%u, error=%d\n", 300 NCP_FINFO(inode)->volNumber, 301 NCP_FINFO(inode)->dirEntNum, err); 302 } 303 mutex_unlock(&NCP_FINFO(inode)->open_mutex); 304 return err; 305} 306 307static void ncp_add_handle_path(struct ncp_server *server, __u8 vol_num, 308 __le32 dir_base, int have_dir_base, 309 const char *path) 310{ 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 */ 315 } else { 316 ncp_add_byte(server, 0xff); /* no handle */ 317 } 318 if (path != NULL) { 319 ncp_add_byte(server, 1); /* 1 component */ 320 ncp_add_pstring(server, path); 321 } else { 322 ncp_add_byte(server, 0); 323 } 324} 325 326int ncp_dirhandle_alloc(struct ncp_server* server, __u8 volnum, __le32 dirent, 327 __u8* dirhandle) { 328 int result; 329 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); 338 } 339 ncp_unlock_server(server); 340 return result; 341} 342 343int ncp_dirhandle_free(struct ncp_server* server, __u8 dirhandle) { 344 int result; 345 346 ncp_init_request_s(server, 20); 347 ncp_add_byte(server, dirhandle); 348 result = ncp_request(server, 22); 349 ncp_unlock_server(server); 350 return result; 351} 352 353void ncp_extract_file_info(void *structure, struct nw_info_struct *target) 354{ 355 __u8 *name_len; 356 const int info_struct_size = offsetof(struct nw_info_struct, nameLen); 357 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); 364 return; 365} 366 367#ifdef CONFIG_NCPFS_NFS_NS 368static inline void ncp_extract_nfs_info(unsigned char *structure, 369 struct nw_nfs_info *target) 370{ 371 target->mode = DVAL_LH(structure); 372 target->rdev = DVAL_LH(structure + 8); 373} 374#endif 375 376int ncp_obtain_nfs_info(struct ncp_server *server, 377 struct nw_info_struct *target) 378 379{ 380 int result = 0; 381#ifdef CONFIG_NCPFS_NFS_NS 382 __u32 volnum = target->volNumber; 383 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); 395 396 if ((result = ncp_request(server, 87)) == 0) { 397 ncp_extract_nfs_info(ncp_reply_data(server, 0), &target->nfs); 398 DPRINTK(KERN_DEBUG 399 "ncp_obtain_nfs_info: (%s) mode=0%o, rdev=0x%x\n", 400 target->entryName, target->nfs.mode, 401 target->nfs.rdev); 402 } else { 403 target->nfs.mode = 0; 404 target->nfs.rdev = 0; 405 } 406 ncp_unlock_server(server); 407 408 } else 409#endif 410 { 411 target->nfs.mode = 0; 412 target->nfs.rdev = 0; 413 } 414 return result; 415} 416 417/* 418 * Returns information for a (one-component) name relative to 419 * the specified directory. 420 */ 421int ncp_obtain_info(struct ncp_server *server, struct inode *dir, char *path, 422 struct nw_info_struct *target) 423{ 424 __u8 volnum = NCP_FINFO(dir)->volNumber; 425 __le32 dirent = NCP_FINFO(dir)->dirEntNum; 426 int result; 427 428 if (target == NULL) { 429 printk(KERN_ERR "ncp_obtain_info: invalid call\n"); 430 return -EINVAL; 431 } 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); 439 440 if ((result = ncp_request(server, 87)) != 0) 441 goto out; 442 ncp_extract_file_info(ncp_reply_data(server, 0), target); 443 ncp_unlock_server(server); 444 445 result = ncp_obtain_nfs_info(server, target); 446 return result; 447 448out: 449 ncp_unlock_server(server); 450 return result; 451} 452 453#ifdef CONFIG_NCPFS_NFS_NS 454static int 455ncp_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) 459{ 460 int result; 461 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); 469 470 if ((result = ncp_request(server, 87)) == 0) 471 { 472 if (DOS_dir_base) *DOS_dir_base=ncp_reply_dword(server, 0x34); 473 } 474 ncp_unlock_server(server); 475 return result; 476} 477#endif /* CONFIG_NCPFS_NFS_NS */ 478 479static inline int 480ncp_get_known_namespace(struct ncp_server *server, __u8 volume) 481{ 482#if defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) 483 int result; 484 __u8 *namespace; 485 __u16 no_namespaces; 486 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); 491 492 if ((result = ncp_request(server, 87)) != 0) { 493 ncp_unlock_server(server); 494 return NW_NS_DOS; /* not result ?? */ 495 } 496 497 result = NW_NS_DOS; 498 no_namespaces = ncp_reply_le16(server, 0); 499 namespace = ncp_reply_data(server, 2); 500 501 while (no_namespaces > 0) { 502 DPRINTK("get_namespaces: found %d on %d\n", *namespace, volume); 503 504#ifdef CONFIG_NCPFS_NFS_NS 505 if ((*namespace == NW_NS_NFS) && !(server->m.flags&NCP_MOUNT_NO_NFS)) 506 { 507 result = NW_NS_NFS; 508 break; 509 } 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)) 513 { 514 result = NW_NS_OS2; 515 } 516#endif /* CONFIG_NCPFS_OS2_NS */ 517 namespace += 1; 518 no_namespaces -= 1; 519 } 520 ncp_unlock_server(server); 521 return result; 522#else /* neither OS2 nor NFS - only DOS */ 523 return NW_NS_DOS; 524#endif /* defined(CONFIG_NCPFS_OS2_NS) || defined(CONFIG_NCPFS_NFS_NS) */ 525} 526 527static int 528ncp_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) 532{ 533 int result; 534 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); 542 543 if ((result = ncp_request(server, 87)) != 0) 544 { 545 ncp_unlock_server(server); 546 return result; 547 } 548 549 if (dirEntNum) 550 *dirEntNum = ncp_reply_dword(server, 0x30); 551 if (DosDirNum) 552 *DosDirNum = ncp_reply_dword(server, 0x34); 553 ncp_unlock_server(server); 554 return 0; 555} 556 557int 558ncp_mount_subdir(struct ncp_server *server, 559 __u8 volNumber, __u8 srcNS, __le32 dirEntNum, 560 __u32* volume, __le32* newDirEnt, __le32* newDosEnt) 561{ 562 int dstNS; 563 int result; 564 565 dstNS = ncp_get_known_namespace(server, volNumber); 566 if ((result = ncp_ObtainSpecificDirBase(server, srcNS, dstNS, volNumber, 567 dirEntNum, NULL, newDirEnt, newDosEnt)) != 0) 568 { 569 return result; 570 } 571 server->name_space[volNumber] = dstNS; 572 *volume = volNumber; 573 server->m.mounted_vol[1] = 0; 574 server->m.mounted_vol[0] = 'X'; 575 return 0; 576} 577 578int 579ncp_get_volume_root(struct ncp_server *server, const char *volname, 580 __u32* volume, __le32* dirent, __le32* dosdirent) 581{ 582 int result; 583 __u8 volnum; 584 585 DPRINTK("ncp_get_volume_root: looking up vol %s\n", volname); 586 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 */ 593 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); 599 600 if ((result = ncp_request(server, 87)) != 0) { 601 ncp_unlock_server(server); 602 return result; 603 } 604 *dirent = *dosdirent = ncp_reply_dword(server, 4); 605 volnum = ncp_reply_byte(server, 8); 606 ncp_unlock_server(server); 607 *volume = volnum; 608 609 server->name_space[volnum] = ncp_get_known_namespace(server, volnum); 610 611 DPRINTK("lookup_vol: namespace[%d] = %d\n", 612 volnum, server->name_space[volnum]); 613 614 return 0; 615} 616 617int 618ncp_lookup_volume(struct ncp_server *server, const char *volname, 619 struct nw_info_struct *target) 620{ 621 int result; 622 623 memset(target, 0, sizeof(*target)); 624 result = ncp_get_volume_root(server, volname, 625 &target->volNumber, &target->dirEntNum, &target->DosDirNum); 626 if (result) { 627 return result; 628 } 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; 636 return 0; 637} 638 639int ncp_modify_file_or_subdir_dos_info_path(struct ncp_server *server, 640 struct inode *dir, 641 const char *path, 642 __le32 info_mask, 643 const struct nw_modify_dos_info *info) 644{ 645 __u8 volnum = NCP_FINFO(dir)->volNumber; 646 __le32 dirent = NCP_FINFO(dir)->dirEntNum; 647 int result; 648 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 */ 654 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); 658 659 result = ncp_request(server, 87); 660 ncp_unlock_server(server); 661 return result; 662} 663 664int ncp_modify_file_or_subdir_dos_info(struct ncp_server *server, 665 struct inode *dir, 666 __le32 info_mask, 667 const struct nw_modify_dos_info *info) 668{ 669 return ncp_modify_file_or_subdir_dos_info_path(server, dir, NULL, 670 info_mask, info); 671} 672 673#ifdef CONFIG_NCPFS_NFS_NS 674int ncp_modify_nfs_info(struct ncp_server *server, __u8 volnum, __le32 dirent, 675 __u32 mode, __u32 rdev) 676 677{ 678 int result = 0; 679 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 688 rdev is not set */ 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); 695 } 696 return result; 697} 698#endif 699 700 701static int 702ncp_DeleteNSEntry(struct ncp_server *server, 703 __u8 have_dir_base, __u8 volnum, __le32 dirent, 704 char* name, __u8 ns, __le16 attr) 705{ 706 int result; 707 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); 714 715 result = ncp_request(server, 87); 716 ncp_unlock_server(server); 717 return result; 718} 719 720int 721ncp_del_file_or_subdir2(struct ncp_server *server, 722 struct dentry *dentry) 723{ 724 struct inode *inode = dentry->d_inode; 725 __u8 volnum; 726 __le32 dirent; 727 728 if (!inode) { 729#ifdef CONFIG_NCPFS_DEBUGDENTRY 730 PRINTK("ncpfs: ncpdel2: dentry->d_inode == NULL\n"); 731#endif 732 return 0xFF; /* Any error */ 733 } 734 volnum = NCP_FINFO(inode)->volNumber; 735 dirent = NCP_FINFO(inode)->DosDirNum; 736 return ncp_DeleteNSEntry(server, 1, volnum, dirent, NULL, NW_NS_DOS, cpu_to_le16(0x8006)); 737} 738 739int 740ncp_del_file_or_subdir(struct ncp_server *server, 741 struct inode *dir, char *name) 742{ 743 __u8 volnum = NCP_FINFO(dir)->volNumber; 744 __le32 dirent = NCP_FINFO(dir)->dirEntNum; 745 746#ifdef CONFIG_NCPFS_NFS_NS 747 if (server->name_space[volnum]==NW_NS_NFS) 748 { 749 int result; 750 751 result=ncp_obtain_DOS_dir_base(server, volnum, dirent, name, &dirent); 752 if (result) return result; 753 return ncp_DeleteNSEntry(server, 1, volnum, dirent, NULL, NW_NS_DOS, cpu_to_le16(0x8006)); 754 } 755 else 756#endif /* CONFIG_NCPFS_NFS_NS */ 757 return ncp_DeleteNSEntry(server, 1, volnum, dirent, name, server->name_space[volnum], cpu_to_le16(0x8006)); 758} 759 760static inline void ConvertToNWfromDWORD(__u16 v0, __u16 v1, __u8 ret[6]) 761{ 762 __le16 *dest = (__le16 *) ret; 763 dest[1] = cpu_to_le16(v0); 764 dest[2] = cpu_to_le16(v1); 765 dest[0] = cpu_to_le16(v0 + 1); 766 return; 767} 768 769/* If both dir and name are NULL, then in target there's already a 770 looked-up entry that wants to be opened. */ 771int ncp_open_create_file_or_subdir(struct ncp_server *server, 772 struct inode *dir, char *name, 773 int open_create_mode, 774 __le32 create_attributes, 775 __le16 desired_acc_rights, 776 struct ncp_entry_info *target) 777{ 778 __le16 search_attribs = cpu_to_le16(0x0006); 779 __u8 volnum; 780 __le32 dirent; 781 int result; 782 783 volnum = NCP_FINFO(dir)->volNumber; 784 dirent = NCP_FINFO(dir)->dirEntNum; 785 786 if ((create_attributes & aDIR) != 0) { 787 search_attribs |= cpu_to_le16(0x8000); 788 } 789 ncp_init_request(server); 790 ncp_add_byte(server, 1); /* subfunction */ 791 ncp_add_byte(server, server->name_space[volnum]); 792 ncp_add_byte(server, open_create_mode); 793 ncp_add_word(server, search_attribs); 794 ncp_add_dword(server, RIM_ALL); 795 ncp_add_dword(server, create_attributes); 796 /* The desired acc rights seem to be the inherited rights mask 797 for directories */ 798 ncp_add_word(server, desired_acc_rights); 799 ncp_add_handle_path(server, volnum, dirent, 1, name); 800 801 if ((result = ncp_request(server, 87)) != 0) 802 goto out; 803 if (!(create_attributes & aDIR)) 804 target->opened = 1; 805 806 /* in target there's a new finfo to fill */ 807 ncp_extract_file_info(ncp_reply_data(server, 6), &(target->i)); 808 target->volume = target->i.volNumber; 809 ConvertToNWfromDWORD(ncp_reply_le16(server, 0), 810 ncp_reply_le16(server, 2), 811 target->file_handle); 812 813 ncp_unlock_server(server); 814 815 (void)ncp_obtain_nfs_info(server, &(target->i)); 816 return 0; 817 818out: 819 ncp_unlock_server(server); 820 return result; 821} 822 823int 824ncp_initialize_search(struct ncp_server *server, struct inode *dir, 825 struct nw_search_sequence *target) 826{ 827 __u8 volnum = NCP_FINFO(dir)->volNumber; 828 __le32 dirent = NCP_FINFO(dir)->dirEntNum; 829 int result; 830 831 ncp_init_request(server); 832 ncp_add_byte(server, 2); /* subfunction */ 833 ncp_add_byte(server, server->name_space[volnum]); 834 ncp_add_byte(server, 0); /* reserved */ 835 ncp_add_handle_path(server, volnum, dirent, 1, NULL); 836 837 result = ncp_request(server, 87); 838 if (result) 839 goto out; 840 memcpy(target, ncp_reply_data(server, 0), sizeof(*target)); 841 842out: 843 ncp_unlock_server(server); 844 return result; 845} 846 847int ncp_search_for_fileset(struct ncp_server *server, 848 struct nw_search_sequence *seq, 849 int* more, 850 int* cnt, 851 char* buffer, 852 size_t bufsize, 853 char** rbuf, 854 size_t* rsize) 855{ 856 int result; 857 858 ncp_init_request(server); 859 ncp_add_byte(server, 20); 860 ncp_add_byte(server, server->name_space[seq->volNumber]); 861 ncp_add_byte(server, 0); /* datastream */ 862 ncp_add_word(server, cpu_to_le16(0x8006)); 863 ncp_add_dword(server, RIM_ALL); 864 ncp_add_word(server, cpu_to_le16(32767)); /* max returned items */ 865 ncp_add_mem(server, seq, 9); 866#ifdef CONFIG_NCPFS_NFS_NS 867 if (server->name_space[seq->volNumber] == NW_NS_NFS) { 868 ncp_add_byte(server, 0); /* 0 byte pattern */ 869 } else 870#endif 871 { 872 ncp_add_byte(server, 2); /* 2 byte pattern */ 873 ncp_add_byte(server, 0xff); /* following is a wildcard */ 874 ncp_add_byte(server, '*'); 875 } 876 result = ncp_request2(server, 87, buffer, bufsize); 877 if (result) { 878 ncp_unlock_server(server); 879 return result; 880 } 881 if (server->ncp_reply_size < 12) { 882 ncp_unlock_server(server); 883 return 0xFF; 884 } 885 *rsize = server->ncp_reply_size - 12; 886 ncp_unlock_server(server); 887 buffer = buffer + sizeof(struct ncp_reply_header); 888 *rbuf = buffer + 12; 889 *cnt = WVAL_LH(buffer + 10); 890 *more = BVAL(buffer + 9); 891 memcpy(seq, buffer, 9); 892 return 0; 893} 894 895static int 896ncp_RenameNSEntry(struct ncp_server *server, 897 struct inode *old_dir, char *old_name, __le16 old_type, 898 struct inode *new_dir, char *new_name) 899{ 900 int result = -EINVAL; 901 902 if ((old_dir == NULL) || (old_name == NULL) || 903 (new_dir == NULL) || (new_name == NULL)) 904 goto out; 905 906 ncp_init_request(server); 907 ncp_add_byte(server, 4); /* subfunction */ 908 ncp_add_byte(server, server->name_space[NCP_FINFO(old_dir)->volNumber]); 909 ncp_add_byte(server, 1); /* rename flag */ 910 ncp_add_word(server, old_type); /* search attributes */ 911 912 /* source Handle Path */ 913 ncp_add_byte(server, NCP_FINFO(old_dir)->volNumber); 914 ncp_add_dword(server, NCP_FINFO(old_dir)->dirEntNum); 915 ncp_add_byte(server, 1); 916 ncp_add_byte(server, 1); /* 1 source component */ 917 918 /* dest Handle Path */ 919 ncp_add_byte(server, NCP_FINFO(new_dir)->volNumber); 920 ncp_add_dword(server, NCP_FINFO(new_dir)->dirEntNum); 921 ncp_add_byte(server, 1); 922 ncp_add_byte(server, 1); /* 1 destination component */ 923 924 /* source path string */ 925 ncp_add_pstring(server, old_name); 926 /* dest path string */ 927 ncp_add_pstring(server, new_name); 928 929 result = ncp_request(server, 87); 930 ncp_unlock_server(server); 931out: 932 return result; 933} 934 935int ncp_ren_or_mov_file_or_subdir(struct ncp_server *server, 936 struct inode *old_dir, char *old_name, 937 struct inode *new_dir, char *new_name) 938{ 939 int result; 940 __le16 old_type = cpu_to_le16(0x06); 941 942/* If somebody can do it atomic, call me... vandrove@vc.cvut.cz */ 943 result = ncp_RenameNSEntry(server, old_dir, old_name, old_type, 944 new_dir, new_name); 945 if (result == 0xFF) /* File Not Found, try directory */ 946 { 947 old_type = cpu_to_le16(0x16); 948 result = ncp_RenameNSEntry(server, old_dir, old_name, old_type, 949 new_dir, new_name); 950 } 951 if (result != 0x92) return result; /* All except NO_FILES_RENAMED */ 952 result = ncp_del_file_or_subdir(server, new_dir, new_name); 953 if (result != 0) return -EACCES; 954 result = ncp_RenameNSEntry(server, old_dir, old_name, old_type, 955 new_dir, new_name); 956 return result; 957} 958 959 960/* We have to transfer to/from user space */ 961int 962ncp_read_kernel(struct ncp_server *server, const char *file_id, 963 __u32 offset, __u16 to_read, char *target, int *bytes_read) 964{ 965 char *source; 966 int result; 967 968 ncp_init_request(server); 969 ncp_add_byte(server, 0); 970 ncp_add_mem(server, file_id, 6); 971 ncp_add_be32(server, offset); 972 ncp_add_be16(server, to_read); 973 974 if ((result = ncp_request(server, 72)) != 0) { 975 goto out; 976 } 977 *bytes_read = ncp_reply_be16(server, 0); 978 source = ncp_reply_data(server, 2 + (offset & 1)); 979 980 memcpy(target, source, *bytes_read); 981out: 982 ncp_unlock_server(server); 983 return result; 984} 985 986/* There is a problem... egrep and some other silly tools do: 987 x = mmap(NULL, MAP_PRIVATE, PROT_READ|PROT_WRITE, <ncpfs fd>, 32768); 988 read(<ncpfs fd>, x, 32768); 989 Now copying read result by copy_to_user causes pagefault. This pagefault 990 could not be handled because of server was locked due to read. So we have 991 to use temporary buffer. So ncp_unlock_server must be done before 992 copy_to_user (and for write, copy_from_user must be done before 993 ncp_init_request... same applies for send raw packet ioctl). Because of 994 file is normally read in bigger chunks, caller provides kmalloced 995 (vmalloced) chunk of memory with size >= to_read... 996 */ 997int 998ncp_read_bounce(struct ncp_server *server, const char *file_id, 999 __u32 offset, __u16 to_read, char __user *target, int *bytes_read, 1000 void* bounce, __u32 bufsize) 1001{ 1002 int result; 1003 1004 ncp_init_request(server); 1005 ncp_add_byte(server, 0); 1006 ncp_add_mem(server, file_id, 6); 1007 ncp_add_be32(server, offset); 1008 ncp_add_be16(server, to_read); 1009 result = ncp_request2(server, 72, bounce, bufsize); 1010 ncp_unlock_server(server); 1011 if (!result) { 1012 int len = be16_to_cpu(get_unaligned((__be16*)((char*)bounce + 1013 sizeof(struct ncp_reply_header)))); 1014 result = -EIO; 1015 if (len <= to_read) { 1016 char* source; 1017 1018 source = (char*)bounce + 1019 sizeof(struct ncp_reply_header) + 2 + 1020 (offset & 1); 1021 *bytes_read = len; 1022 result = 0; 1023 if (copy_to_user(target, source, len)) 1024 result = -EFAULT; 1025 } 1026 } 1027 return result; 1028} 1029 1030int 1031ncp_write_kernel(struct ncp_server *server, const char *file_id, 1032 __u32 offset, __u16 to_write, 1033 const char *source, int *bytes_written) 1034{ 1035 int result; 1036 1037 ncp_init_request(server); 1038 ncp_add_byte(server, 0); 1039 ncp_add_mem(server, file_id, 6); 1040 ncp_add_be32(server, offset); 1041 ncp_add_be16(server, to_write); 1042 ncp_add_mem(server, source, to_write); 1043 1044 if ((result = ncp_request(server, 73)) == 0) 1045 *bytes_written = to_write; 1046 ncp_unlock_server(server); 1047 return result; 1048} 1049 1050#ifdef CONFIG_NCPFS_IOCTL_LOCKING 1051int 1052ncp_LogPhysicalRecord(struct ncp_server *server, const char *file_id, 1053 __u8 locktype, __u32 offset, __u32 length, __u16 timeout) 1054{ 1055 int result; 1056 1057 ncp_init_request(server); 1058 ncp_add_byte(server, locktype); 1059 ncp_add_mem(server, file_id, 6); 1060 ncp_add_be32(server, offset); 1061 ncp_add_be32(server, length); 1062 ncp_add_be16(server, timeout); 1063 1064 if ((result = ncp_request(server, 0x1A)) != 0) 1065 { 1066 ncp_unlock_server(server); 1067 return result; 1068 } 1069 ncp_unlock_server(server); 1070 return 0; 1071} 1072 1073int 1074ncp_ClearPhysicalRecord(struct ncp_server *server, const char *file_id, 1075 __u32 offset, __u32 length) 1076{ 1077 int result; 1078 1079 ncp_init_request(server); 1080 ncp_add_byte(server, 0); /* who knows... lanalyzer says that */ 1081 ncp_add_mem(server, file_id, 6); 1082 ncp_add_be32(server, offset); 1083 ncp_add_be32(server, length); 1084 1085 if ((result = ncp_request(server, 0x1E)) != 0) 1086 { 1087 ncp_unlock_server(server); 1088 return result; 1089 } 1090 ncp_unlock_server(server); 1091 return 0; 1092} 1093#endif /* CONFIG_NCPFS_IOCTL_LOCKING */ 1094 1095#ifdef CONFIG_NCPFS_NLS 1096/* This are the NLS conversion routines with inspirations and code parts 1097 * from the vfat file system and hints from Petr Vandrovec. 1098 */ 1099 1100int 1101ncp__io2vol(struct ncp_server *server, unsigned char *vname, unsigned int *vlen, 1102 const unsigned char *iname, unsigned int ilen, int cc) 1103{ 1104 struct nls_table *in = server->nls_io; 1105 struct nls_table *out = server->nls_vol; 1106 unsigned char *vname_start; 1107 unsigned char *vname_end; 1108 const unsigned char *iname_end; 1109 1110 iname_end = iname + ilen; 1111 vname_start = vname; 1112 vname_end = vname + *vlen - 1; 1113 1114 while (iname < iname_end) { 1115 int chl; 1116 wchar_t ec; 1117 1118 if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) { 1119 int k; 1120 1121 k = utf8_mbtowc(&ec, iname, iname_end - iname); 1122 if (k < 0) 1123 return -EINVAL; 1124 iname += k; 1125 } else { 1126 if (*iname == NCP_ESC) { 1127 int k; 1128 1129 if (iname_end - iname < 5) 1130 goto nospec; 1131 1132 ec = 0; 1133 for (k = 1; k < 5; k++) { 1134 unsigned char nc; 1135 1136 nc = iname[k] - '0'; 1137 if (nc >= 10) { 1138 nc -= 'A' - '0' - 10; 1139 if ((nc < 10) || (nc > 15)) { 1140 goto nospec; 1141 } 1142 } 1143 ec = (ec << 4) | nc; 1144 } 1145 iname += 5; 1146 } else { 1147nospec:; 1148 if ( (chl = in->char2uni(iname, iname_end - iname, &ec)) < 0) 1149 return chl; 1150 iname += chl; 1151 } 1152 } 1153 1154 /* unitoupper should be here! */ 1155 1156 chl = out->uni2char(ec, vname, vname_end - vname); 1157 if (chl < 0) 1158 return chl; 1159 1160 /* this is wrong... */ 1161 if (cc) { 1162 int chi; 1163 1164 for (chi = 0; chi < chl; chi++){ 1165 vname[chi] = ncp_toupper(out, vname[chi]); 1166 } 1167 } 1168 vname += chl; 1169 } 1170 1171 *vname = 0; 1172 *vlen = vname - vname_start; 1173 return 0; 1174} 1175 1176int 1177ncp__vol2io(struct ncp_server *server, unsigned char *iname, unsigned int *ilen, 1178 const unsigned char *vname, unsigned int vlen, int cc) 1179{ 1180 struct nls_table *in = server->nls_vol; 1181 struct nls_table *out = server->nls_io; 1182 const unsigned char *vname_end; 1183 unsigned char *iname_start; 1184 unsigned char *iname_end; 1185 unsigned char *vname_cc; 1186 int err; 1187 1188 vname_cc = NULL; 1189 1190 if (cc) { 1191 int i; 1192 1193 /* this is wrong! */ 1194 vname_cc = kmalloc(vlen, GFP_KERNEL); 1195 if (!vname_cc) 1196 return -ENOMEM; 1197 for (i = 0; i < vlen; i++) 1198 vname_cc[i] = ncp_tolower(in, vname[i]); 1199 vname = vname_cc; 1200 } 1201 1202 iname_start = iname; 1203 iname_end = iname + *ilen - 1; 1204 vname_end = vname + vlen; 1205 1206 while (vname < vname_end) { 1207 wchar_t ec; 1208 int chl; 1209 1210 if ( (chl = in->char2uni(vname, vname_end - vname, &ec)) < 0) { 1211 err = chl; 1212 goto quit; 1213 } 1214 vname += chl; 1215 1216 /* unitolower should be here! */ 1217 1218 if (NCP_IS_FLAG(server, NCP_FLAG_UTF8)) { 1219 int k; 1220 1221 k = utf8_wctomb(iname, ec, iname_end - iname); 1222 if (k < 0) { 1223 err = -ENAMETOOLONG; 1224 goto quit; 1225 } 1226 iname += k; 1227 } else { 1228 if ( (chl = out->uni2char(ec, iname, iname_end - iname)) >= 0) { 1229 iname += chl; 1230 } else { 1231 int k; 1232 1233 if (iname_end - iname < 5) { 1234 err = -ENAMETOOLONG; 1235 goto quit; 1236 } 1237 *iname = NCP_ESC; 1238 for (k = 4; k > 0; k--) { 1239 unsigned char v; 1240 1241 v = (ec & 0xF) + '0'; 1242 if (v > '9') { 1243 v += 'A' - '9' - 1; 1244 } 1245 iname[k] = v; 1246 ec >>= 4; 1247 } 1248 iname += 5; 1249 } 1250 } 1251 } 1252 1253 *iname = 0; 1254 *ilen = iname - iname_start; 1255 err = 0; 1256quit:; 1257 if (cc) 1258 kfree(vname_cc); 1259 return err; 1260} 1261 1262#else 1263 1264int 1265ncp__io2vol(unsigned char *vname, unsigned int *vlen, 1266 const unsigned char *iname, unsigned int ilen, int cc) 1267{ 1268 int i; 1269 1270 if (*vlen <= ilen) 1271 return -ENAMETOOLONG; 1272 1273 if (cc) 1274 for (i = 0; i < ilen; i++) { 1275 *vname = toupper(*iname); 1276 vname++; 1277 iname++; 1278 } 1279 else { 1280 memmove(vname, iname, ilen); 1281 vname += ilen; 1282 } 1283 1284 *vlen = ilen; 1285 *vname = 0; 1286 return 0; 1287} 1288 1289int 1290ncp__vol2io(unsigned char *iname, unsigned int *ilen, 1291 const unsigned char *vname, unsigned int vlen, int cc) 1292{ 1293 int i; 1294 1295 if (*ilen <= vlen) 1296 return -ENAMETOOLONG; 1297 1298 if (cc) 1299 for (i = 0; i < vlen; i++) { 1300 *iname = tolower(*vname); 1301 iname++; 1302 vname++; 1303 } 1304 else { 1305 memmove(iname, vname, vlen); 1306 iname += vlen; 1307 } 1308 1309 *ilen = vlen; 1310 *iname = 0; 1311 return 0; 1312} 1313 1314#endif 1315