ncplib_kernel.c 32 KB

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