ncplib_kernel.c 32 KB

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