ncplib_kernel.c
上传用户:lgb322
上传日期:2013-02-24
资源大小:30529k
文件大小:27k
源码类别:

嵌入式Linux

开发平台:

Unix_Linux

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