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