~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/fs/ncpfs/inode.c

Version: ~ [ linux-5.4-rc3 ] ~ [ linux-5.3.6 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.79 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.149 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.196 ] ~ [ linux-4.8.17 ] ~ [ linux-4.7.10 ] ~ [ linux-4.6.7 ] ~ [ linux-4.5.7 ] ~ [ linux-4.4.196 ] ~ [ linux-4.3.6 ] ~ [ linux-4.2.8 ] ~ [ linux-4.1.52 ] ~ [ linux-4.0.9 ] ~ [ linux-3.19.8 ] ~ [ linux-3.18.140 ] ~ [ linux-3.17.8 ] ~ [ linux-3.16.75 ] ~ [ linux-3.15.10 ] ~ [ linux-3.14.79 ] ~ [ linux-3.13.11 ] ~ [ linux-3.12.74 ] ~ [ linux-3.11.10 ] ~ [ linux-3.10.108 ] ~ [ linux-3.9.11 ] ~ [ linux-3.8.13 ] ~ [ linux-3.7.10 ] ~ [ linux-3.6.11 ] ~ [ linux-3.5.7 ] ~ [ linux-3.4.113 ] ~ [ linux-3.3.8 ] ~ [ linux-3.2.102 ] ~ [ linux-3.1.10 ] ~ [ linux-3.0.101 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.5 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 /*
  2  *  inode.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 1998 Wolfram Pienkoss for NLS
  8  *  Modified 2000 Ben Harris, University of Cambridge for NFS NS meta-info
  9  *
 10  */
 11 
 12 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 13 
 14 #include <linux/module.h>
 15 
 16 #include <asm/uaccess.h>
 17 #include <asm/byteorder.h>
 18 
 19 #include <linux/time.h>
 20 #include <linux/kernel.h>
 21 #include <linux/mm.h>
 22 #include <linux/string.h>
 23 #include <linux/stat.h>
 24 #include <linux/errno.h>
 25 #include <linux/file.h>
 26 #include <linux/fcntl.h>
 27 #include <linux/slab.h>
 28 #include <linux/vmalloc.h>
 29 #include <linux/init.h>
 30 #include <linux/vfs.h>
 31 #include <linux/mount.h>
 32 #include <linux/seq_file.h>
 33 #include <linux/namei.h>
 34 
 35 #include <net/sock.h>
 36 
 37 #include "ncp_fs.h"
 38 #include "getopt.h"
 39 
 40 #define NCP_DEFAULT_FILE_MODE 0600
 41 #define NCP_DEFAULT_DIR_MODE 0700
 42 #define NCP_DEFAULT_TIME_OUT 10
 43 #define NCP_DEFAULT_RETRY_COUNT 20
 44 
 45 static void ncp_evict_inode(struct inode *);
 46 static void ncp_put_super(struct super_block *);
 47 static int  ncp_statfs(struct dentry *, struct kstatfs *);
 48 static int  ncp_show_options(struct seq_file *, struct dentry *);
 49 
 50 static struct kmem_cache * ncp_inode_cachep;
 51 
 52 static struct inode *ncp_alloc_inode(struct super_block *sb)
 53 {
 54         struct ncp_inode_info *ei;
 55         ei = (struct ncp_inode_info *)kmem_cache_alloc(ncp_inode_cachep, GFP_KERNEL);
 56         if (!ei)
 57                 return NULL;
 58         return &ei->vfs_inode;
 59 }
 60 
 61 static void ncp_i_callback(struct rcu_head *head)
 62 {
 63         struct inode *inode = container_of(head, struct inode, i_rcu);
 64         kmem_cache_free(ncp_inode_cachep, NCP_FINFO(inode));
 65 }
 66 
 67 static void ncp_destroy_inode(struct inode *inode)
 68 {
 69         call_rcu(&inode->i_rcu, ncp_i_callback);
 70 }
 71 
 72 static void init_once(void *foo)
 73 {
 74         struct ncp_inode_info *ei = (struct ncp_inode_info *) foo;
 75 
 76         mutex_init(&ei->open_mutex);
 77         inode_init_once(&ei->vfs_inode);
 78 }
 79 
 80 static int init_inodecache(void)
 81 {
 82         ncp_inode_cachep = kmem_cache_create("ncp_inode_cache",
 83                                              sizeof(struct ncp_inode_info),
 84                                              0, (SLAB_RECLAIM_ACCOUNT|
 85                                                 SLAB_MEM_SPREAD),
 86                                              init_once);
 87         if (ncp_inode_cachep == NULL)
 88                 return -ENOMEM;
 89         return 0;
 90 }
 91 
 92 static void destroy_inodecache(void)
 93 {
 94         /*
 95          * Make sure all delayed rcu free inodes are flushed before we
 96          * destroy cache.
 97          */
 98         rcu_barrier();
 99         kmem_cache_destroy(ncp_inode_cachep);
100 }
101 
102 static int ncp_remount(struct super_block *sb, int *flags, char* data)
103 {
104         sync_filesystem(sb);
105         *flags |= MS_NODIRATIME;
106         return 0;
107 }
108 
109 static const struct super_operations ncp_sops =
110 {
111         .alloc_inode    = ncp_alloc_inode,
112         .destroy_inode  = ncp_destroy_inode,
113         .drop_inode     = generic_delete_inode,
114         .evict_inode    = ncp_evict_inode,
115         .put_super      = ncp_put_super,
116         .statfs         = ncp_statfs,
117         .remount_fs     = ncp_remount,
118         .show_options   = ncp_show_options,
119 };
120 
121 /*
122  * Fill in the ncpfs-specific information in the inode.
123  */
124 static void ncp_update_dirent(struct inode *inode, struct ncp_entry_info *nwinfo)
125 {
126         NCP_FINFO(inode)->DosDirNum = nwinfo->i.DosDirNum;
127         NCP_FINFO(inode)->dirEntNum = nwinfo->i.dirEntNum;
128         NCP_FINFO(inode)->volNumber = nwinfo->volume;
129 }
130 
131 void ncp_update_inode(struct inode *inode, struct ncp_entry_info *nwinfo)
132 {
133         ncp_update_dirent(inode, nwinfo);
134         NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
135         NCP_FINFO(inode)->access = nwinfo->access;
136         memcpy(NCP_FINFO(inode)->file_handle, nwinfo->file_handle,
137                         sizeof(nwinfo->file_handle));
138         ncp_dbg(1, "updated %s, volnum=%d, dirent=%u\n",
139                 nwinfo->i.entryName, NCP_FINFO(inode)->volNumber,
140                 NCP_FINFO(inode)->dirEntNum);
141 }
142 
143 static void ncp_update_dates(struct inode *inode, struct nw_info_struct *nwi)
144 {
145         /* NFS namespace mode overrides others if it's set. */
146         ncp_dbg(1, "(%s) nfs.mode=0%o\n", nwi->entryName, nwi->nfs.mode);
147         if (nwi->nfs.mode) {
148                 /* XXX Security? */
149                 inode->i_mode = nwi->nfs.mode;
150         }
151 
152         inode->i_blocks = (i_size_read(inode) + NCP_BLOCK_SIZE - 1) >> NCP_BLOCK_SHIFT;
153 
154         inode->i_mtime.tv_sec = ncp_date_dos2unix(nwi->modifyTime, nwi->modifyDate);
155         inode->i_ctime.tv_sec = ncp_date_dos2unix(nwi->creationTime, nwi->creationDate);
156         inode->i_atime.tv_sec = ncp_date_dos2unix(0, nwi->lastAccessDate);
157         inode->i_atime.tv_nsec = 0;
158         inode->i_mtime.tv_nsec = 0;
159         inode->i_ctime.tv_nsec = 0;
160 }
161 
162 static void ncp_update_attrs(struct inode *inode, struct ncp_entry_info *nwinfo)
163 {
164         struct nw_info_struct *nwi = &nwinfo->i;
165         struct ncp_server *server = NCP_SERVER(inode);
166 
167         if (nwi->attributes & aDIR) {
168                 inode->i_mode = server->m.dir_mode;
169                 /* for directories dataStreamSize seems to be some
170                    Object ID ??? */
171                 i_size_write(inode, NCP_BLOCK_SIZE);
172         } else {
173                 u32 size;
174 
175                 inode->i_mode = server->m.file_mode;
176                 size = le32_to_cpu(nwi->dataStreamSize);
177                 i_size_write(inode, size);
178 #ifdef CONFIG_NCPFS_EXTRAS
179                 if ((server->m.flags & (NCP_MOUNT_EXTRAS|NCP_MOUNT_SYMLINKS)) 
180                  && (nwi->attributes & aSHARED)) {
181                         switch (nwi->attributes & (aHIDDEN|aSYSTEM)) {
182                                 case aHIDDEN:
183                                         if (server->m.flags & NCP_MOUNT_SYMLINKS) {
184                                                 if (/* (size >= NCP_MIN_SYMLINK_SIZE)
185                                                  && */ (size <= NCP_MAX_SYMLINK_SIZE)) {
186                                                         inode->i_mode = (inode->i_mode & ~S_IFMT) | S_IFLNK;
187                                                         NCP_FINFO(inode)->flags |= NCPI_KLUDGE_SYMLINK;
188                                                         break;
189                                                 }
190                                         }
191                                         /* FALLTHROUGH */
192                                 case 0:
193                                         if (server->m.flags & NCP_MOUNT_EXTRAS)
194                                                 inode->i_mode |= S_IRUGO;
195                                         break;
196                                 case aSYSTEM:
197                                         if (server->m.flags & NCP_MOUNT_EXTRAS)
198                                                 inode->i_mode |= (inode->i_mode >> 2) & S_IXUGO;
199                                         break;
200                                 /* case aSYSTEM|aHIDDEN: */
201                                 default:
202                                         /* reserved combination */
203                                         break;
204                         }
205                 }
206 #endif
207         }
208         if (nwi->attributes & aRONLY) inode->i_mode &= ~S_IWUGO;
209 }
210 
211 void ncp_update_inode2(struct inode* inode, struct ncp_entry_info *nwinfo)
212 {
213         NCP_FINFO(inode)->flags = 0;
214         if (!atomic_read(&NCP_FINFO(inode)->opened)) {
215                 NCP_FINFO(inode)->nwattr = nwinfo->i.attributes;
216                 ncp_update_attrs(inode, nwinfo);
217         }
218 
219         ncp_update_dates(inode, &nwinfo->i);
220         ncp_update_dirent(inode, nwinfo);
221 }
222 
223 /*
224  * Fill in the inode based on the ncp_entry_info structure.  Used only for brand new inodes.
225  */
226 static void ncp_set_attr(struct inode *inode, struct ncp_entry_info *nwinfo)
227 {
228         struct ncp_server *server = NCP_SERVER(inode);
229 
230         NCP_FINFO(inode)->flags = 0;
231         
232         ncp_update_attrs(inode, nwinfo);
233 
234         ncp_dbg(2, "inode->i_mode = %u\n", inode->i_mode);
235 
236         set_nlink(inode, 1);
237         inode->i_uid = server->m.uid;
238         inode->i_gid = server->m.gid;
239 
240         ncp_update_dates(inode, &nwinfo->i);
241         ncp_update_inode(inode, nwinfo);
242 }
243 
244 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
245 static const struct inode_operations ncp_symlink_inode_operations = {
246         .readlink       = generic_readlink,
247         .follow_link    = page_follow_link_light,
248         .put_link       = page_put_link,
249         .setattr        = ncp_notify_change,
250 };
251 #endif
252 
253 /*
254  * Get a new inode.
255  */
256 struct inode * 
257 ncp_iget(struct super_block *sb, struct ncp_entry_info *info)
258 {
259         struct inode *inode;
260 
261         if (info == NULL) {
262                 pr_err("%s: info is NULL\n", __func__);
263                 return NULL;
264         }
265 
266         inode = new_inode(sb);
267         if (inode) {
268                 atomic_set(&NCP_FINFO(inode)->opened, info->opened);
269 
270                 inode->i_ino = info->ino;
271                 ncp_set_attr(inode, info);
272                 if (S_ISREG(inode->i_mode)) {
273                         inode->i_op = &ncp_file_inode_operations;
274                         inode->i_fop = &ncp_file_operations;
275                 } else if (S_ISDIR(inode->i_mode)) {
276                         inode->i_op = &ncp_dir_inode_operations;
277                         inode->i_fop = &ncp_dir_operations;
278 #ifdef CONFIG_NCPFS_NFS_NS
279                 } else if (S_ISCHR(inode->i_mode) || S_ISBLK(inode->i_mode) || S_ISFIFO(inode->i_mode) || S_ISSOCK(inode->i_mode)) {
280                         init_special_inode(inode, inode->i_mode,
281                                 new_decode_dev(info->i.nfs.rdev));
282 #endif
283 #if defined(CONFIG_NCPFS_EXTRAS) || defined(CONFIG_NCPFS_NFS_NS)
284                 } else if (S_ISLNK(inode->i_mode)) {
285                         inode->i_op = &ncp_symlink_inode_operations;
286                         inode->i_data.a_ops = &ncp_symlink_aops;
287 #endif
288                 } else {
289                         make_bad_inode(inode);
290                 }
291                 insert_inode_hash(inode);
292         } else
293                 pr_err("%s: iget failed!\n", __func__);
294         return inode;
295 }
296 
297 static void
298 ncp_evict_inode(struct inode *inode)
299 {
300         truncate_inode_pages_final(&inode->i_data);
301         clear_inode(inode);
302 
303         if (S_ISDIR(inode->i_mode)) {
304                 ncp_dbg(2, "put directory %ld\n", inode->i_ino);
305         }
306 
307         if (ncp_make_closed(inode) != 0) {
308                 /* We can't do anything but complain. */
309                 pr_err("%s: could not close\n", __func__);
310         }
311 }
312 
313 static void ncp_stop_tasks(struct ncp_server *server) {
314         struct sock* sk = server->ncp_sock->sk;
315 
316         lock_sock(sk);
317         sk->sk_error_report = server->error_report;
318         sk->sk_data_ready   = server->data_ready;
319         sk->sk_write_space  = server->write_space;
320         release_sock(sk);
321         del_timer_sync(&server->timeout_tm);
322 
323         flush_work(&server->rcv.tq);
324         if (sk->sk_socket->type == SOCK_STREAM)
325                 flush_work(&server->tx.tq);
326         else
327                 flush_work(&server->timeout_tq);
328 }
329 
330 static int  ncp_show_options(struct seq_file *seq, struct dentry *root)
331 {
332         struct ncp_server *server = NCP_SBP(root->d_sb);
333         unsigned int tmp;
334 
335         if (!uid_eq(server->m.uid, GLOBAL_ROOT_UID))
336                 seq_printf(seq, ",uid=%u",
337                            from_kuid_munged(&init_user_ns, server->m.uid));
338         if (!gid_eq(server->m.gid, GLOBAL_ROOT_GID))
339                 seq_printf(seq, ",gid=%u",
340                            from_kgid_munged(&init_user_ns, server->m.gid));
341         if (!uid_eq(server->m.mounted_uid, GLOBAL_ROOT_UID))
342                 seq_printf(seq, ",owner=%u",
343                            from_kuid_munged(&init_user_ns, server->m.mounted_uid));
344         tmp = server->m.file_mode & S_IALLUGO;
345         if (tmp != NCP_DEFAULT_FILE_MODE)
346                 seq_printf(seq, ",mode=0%o", tmp);
347         tmp = server->m.dir_mode & S_IALLUGO;
348         if (tmp != NCP_DEFAULT_DIR_MODE)
349                 seq_printf(seq, ",dirmode=0%o", tmp);
350         if (server->m.time_out != NCP_DEFAULT_TIME_OUT * HZ / 100) {
351                 tmp = server->m.time_out * 100 / HZ;
352                 seq_printf(seq, ",timeout=%u", tmp);
353         }
354         if (server->m.retry_count != NCP_DEFAULT_RETRY_COUNT)
355                 seq_printf(seq, ",retry=%u", server->m.retry_count);
356         if (server->m.flags != 0)
357                 seq_printf(seq, ",flags=%lu", server->m.flags);
358         if (server->m.wdog_pid != NULL)
359                 seq_printf(seq, ",wdogpid=%u", pid_vnr(server->m.wdog_pid));
360 
361         return 0;
362 }
363 
364 static const struct ncp_option ncp_opts[] = {
365         { "uid",        OPT_INT,        'u' },
366         { "gid",        OPT_INT,        'g' },
367         { "owner",      OPT_INT,        'o' },
368         { "mode",       OPT_INT,        'm' },
369         { "dirmode",    OPT_INT,        'd' },
370         { "timeout",    OPT_INT,        't' },
371         { "retry",      OPT_INT,        'r' },
372         { "flags",      OPT_INT,        'f' },
373         { "wdogpid",    OPT_INT,        'w' },
374         { "ncpfd",      OPT_INT,        'n' },
375         { "infofd",     OPT_INT,        'i' },  /* v5 */
376         { "version",    OPT_INT,        'v' },
377         { NULL,         0,              0 } };
378 
379 static int ncp_parse_options(struct ncp_mount_data_kernel *data, char *options) {
380         int optval;
381         char *optarg;
382         unsigned long optint;
383         int version = 0;
384         int ret;
385 
386         data->flags = 0;
387         data->int_flags = 0;
388         data->mounted_uid = GLOBAL_ROOT_UID;
389         data->wdog_pid = NULL;
390         data->ncp_fd = ~0;
391         data->time_out = NCP_DEFAULT_TIME_OUT;
392         data->retry_count = NCP_DEFAULT_RETRY_COUNT;
393         data->uid = GLOBAL_ROOT_UID;
394         data->gid = GLOBAL_ROOT_GID;
395         data->file_mode = NCP_DEFAULT_FILE_MODE;
396         data->dir_mode = NCP_DEFAULT_DIR_MODE;
397         data->info_fd = -1;
398         data->mounted_vol[0] = 0;
399         
400         while ((optval = ncp_getopt("ncpfs", &options, ncp_opts, NULL, &optarg, &optint)) != 0) {
401                 ret = optval;
402                 if (ret < 0)
403                         goto err;
404                 switch (optval) {
405                         case 'u':
406                                 data->uid = make_kuid(current_user_ns(), optint);
407                                 if (!uid_valid(data->uid)) {
408                                         ret = -EINVAL;
409                                         goto err;
410                                 }
411                                 break;
412                         case 'g':
413                                 data->gid = make_kgid(current_user_ns(), optint);
414                                 if (!gid_valid(data->gid)) {
415                                         ret = -EINVAL;
416                                         goto err;
417                                 }
418                                 break;
419                         case 'o':
420                                 data->mounted_uid = make_kuid(current_user_ns(), optint);
421                                 if (!uid_valid(data->mounted_uid)) {
422                                         ret = -EINVAL;
423                                         goto err;
424                                 }
425                                 break;
426                         case 'm':
427                                 data->file_mode = optint;
428                                 break;
429                         case 'd':
430                                 data->dir_mode = optint;
431                                 break;
432                         case 't':
433                                 data->time_out = optint;
434                                 break;
435                         case 'r':
436                                 data->retry_count = optint;
437                                 break;
438                         case 'f':
439                                 data->flags = optint;
440                                 break;
441                         case 'w':
442                                 data->wdog_pid = find_get_pid(optint);
443                                 break;
444                         case 'n':
445                                 data->ncp_fd = optint;
446                                 break;
447                         case 'i':
448                                 data->info_fd = optint;
449                                 break;
450                         case 'v':
451                                 ret = -ECHRNG;
452                                 if (optint < NCP_MOUNT_VERSION_V4)
453                                         goto err;
454                                 if (optint > NCP_MOUNT_VERSION_V5)
455                                         goto err;
456                                 version = optint;
457                                 break;
458                         
459                 }
460         }
461         return 0;
462 err:
463         put_pid(data->wdog_pid);
464         data->wdog_pid = NULL;
465         return ret;
466 }
467 
468 static int ncp_fill_super(struct super_block *sb, void *raw_data, int silent)
469 {
470         struct ncp_mount_data_kernel data;
471         struct ncp_server *server;
472         struct inode *root_inode;
473         struct socket *sock;
474         int error;
475         int default_bufsize;
476 #ifdef CONFIG_NCPFS_PACKET_SIGNING
477         int options;
478 #endif
479         struct ncp_entry_info finfo;
480 
481         memset(&data, 0, sizeof(data));
482         server = kzalloc(sizeof(struct ncp_server), GFP_KERNEL);
483         if (!server)
484                 return -ENOMEM;
485         sb->s_fs_info = server;
486 
487         error = -EFAULT;
488         if (raw_data == NULL)
489                 goto out;
490         switch (*(int*)raw_data) {
491                 case NCP_MOUNT_VERSION:
492                         {
493                                 struct ncp_mount_data* md = (struct ncp_mount_data*)raw_data;
494 
495                                 data.flags = md->flags;
496                                 data.int_flags = NCP_IMOUNT_LOGGEDIN_POSSIBLE;
497                                 data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
498                                 data.wdog_pid = find_get_pid(md->wdog_pid);
499                                 data.ncp_fd = md->ncp_fd;
500                                 data.time_out = md->time_out;
501                                 data.retry_count = md->retry_count;
502                                 data.uid = make_kuid(current_user_ns(), md->uid);
503                                 data.gid = make_kgid(current_user_ns(), md->gid);
504                                 data.file_mode = md->file_mode;
505                                 data.dir_mode = md->dir_mode;
506                                 data.info_fd = -1;
507                                 memcpy(data.mounted_vol, md->mounted_vol,
508                                         NCP_VOLNAME_LEN+1);
509                         }
510                         break;
511                 case NCP_MOUNT_VERSION_V4:
512                         {
513                                 struct ncp_mount_data_v4* md = (struct ncp_mount_data_v4*)raw_data;
514 
515                                 data.flags = md->flags;
516                                 data.mounted_uid = make_kuid(current_user_ns(), md->mounted_uid);
517                                 data.wdog_pid = find_get_pid(md->wdog_pid);
518                                 data.ncp_fd = md->ncp_fd;
519                                 data.time_out = md->time_out;
520                                 data.retry_count = md->retry_count;
521                                 data.uid = make_kuid(current_user_ns(), md->uid);
522                                 data.gid = make_kgid(current_user_ns(), md->gid);
523                                 data.file_mode = md->file_mode;
524                                 data.dir_mode = md->dir_mode;
525                                 data.info_fd = -1;
526                         }
527                         break;
528                 default:
529                         error = -ECHRNG;
530                         if (memcmp(raw_data, "vers", 4) == 0) {
531                                 error = ncp_parse_options(&data, raw_data);
532                         }
533                         if (error)
534                                 goto out;
535                         break;
536         }
537         error = -EINVAL;
538         if (!uid_valid(data.mounted_uid) || !uid_valid(data.uid) ||
539             !gid_valid(data.gid))
540                 goto out;
541         sock = sockfd_lookup(data.ncp_fd, &error);
542         if (!sock)
543                 goto out;
544 
545         if (sock->type == SOCK_STREAM)
546                 default_bufsize = 0xF000;
547         else
548                 default_bufsize = 1024;
549 
550         sb->s_flags |= MS_NODIRATIME;   /* probably even noatime */
551         sb->s_maxbytes = 0xFFFFFFFFU;
552         sb->s_blocksize = 1024; /* Eh...  Is this correct? */
553         sb->s_blocksize_bits = 10;
554         sb->s_magic = NCP_SUPER_MAGIC;
555         sb->s_op = &ncp_sops;
556         sb->s_d_op = &ncp_dentry_operations;
557         sb->s_bdi = &server->bdi;
558 
559         server = NCP_SBP(sb);
560         memset(server, 0, sizeof(*server));
561 
562         error = bdi_setup_and_register(&server->bdi, "ncpfs");
563         if (error)
564                 goto out_fput;
565 
566         server->ncp_sock = sock;
567         
568         if (data.info_fd != -1) {
569                 struct socket *info_sock = sockfd_lookup(data.info_fd, &error);
570                 if (!info_sock)
571                         goto out_bdi;
572                 server->info_sock = info_sock;
573                 error = -EBADFD;
574                 if (info_sock->type != SOCK_STREAM)
575                         goto out_fput2;
576         }
577 
578 /*      server->lock = 0;       */
579         mutex_init(&server->mutex);
580         server->packet = NULL;
581 /*      server->buffer_size = 0;        */
582 /*      server->conn_status = 0;        */
583 /*      server->root_dentry = NULL;     */
584 /*      server->root_setuped = 0;       */
585         mutex_init(&server->root_setup_lock);
586 #ifdef CONFIG_NCPFS_PACKET_SIGNING
587 /*      server->sign_wanted = 0;        */
588 /*      server->sign_active = 0;        */
589 #endif
590         init_rwsem(&server->auth_rwsem);
591         server->auth.auth_type = NCP_AUTH_NONE;
592 /*      server->auth.object_name_len = 0;       */
593 /*      server->auth.object_name = NULL;        */
594 /*      server->auth.object_type = 0;           */
595 /*      server->priv.len = 0;                   */
596 /*      server->priv.data = NULL;               */
597 
598         server->m = data;
599         /* Although anything producing this is buggy, it happens
600            now because of PATH_MAX changes.. */
601         if (server->m.time_out < 1) {
602                 server->m.time_out = 10;
603                 pr_info("You need to recompile your ncpfs utils..\n");
604         }
605         server->m.time_out = server->m.time_out * HZ / 100;
606         server->m.file_mode = (server->m.file_mode & S_IRWXUGO) | S_IFREG;
607         server->m.dir_mode = (server->m.dir_mode & S_IRWXUGO) | S_IFDIR;
608 
609 #ifdef CONFIG_NCPFS_NLS
610         /* load the default NLS charsets */
611         server->nls_vol = load_nls_default();
612         server->nls_io = load_nls_default();
613 #endif /* CONFIG_NCPFS_NLS */
614 
615         atomic_set(&server->dentry_ttl, 0);     /* no caching */
616 
617         INIT_LIST_HEAD(&server->tx.requests);
618         mutex_init(&server->rcv.creq_mutex);
619         server->tx.creq         = NULL;
620         server->rcv.creq        = NULL;
621 
622         init_timer(&server->timeout_tm);
623 #undef NCP_PACKET_SIZE
624 #define NCP_PACKET_SIZE 131072
625         error = -ENOMEM;
626         server->packet_size = NCP_PACKET_SIZE;
627         server->packet = vmalloc(NCP_PACKET_SIZE);
628         if (server->packet == NULL)
629                 goto out_nls;
630         server->txbuf = vmalloc(NCP_PACKET_SIZE);
631         if (server->txbuf == NULL)
632                 goto out_packet;
633         server->rxbuf = vmalloc(NCP_PACKET_SIZE);
634         if (server->rxbuf == NULL)
635                 goto out_txbuf;
636 
637         lock_sock(sock->sk);
638         server->data_ready      = sock->sk->sk_data_ready;
639         server->write_space     = sock->sk->sk_write_space;
640         server->error_report    = sock->sk->sk_error_report;
641         sock->sk->sk_user_data  = server;
642         sock->sk->sk_data_ready   = ncp_tcp_data_ready;
643         sock->sk->sk_error_report = ncp_tcp_error_report;
644         if (sock->type == SOCK_STREAM) {
645                 server->rcv.ptr = (unsigned char*)&server->rcv.buf;
646                 server->rcv.len = 10;
647                 server->rcv.state = 0;
648                 INIT_WORK(&server->rcv.tq, ncp_tcp_rcv_proc);
649                 INIT_WORK(&server->tx.tq, ncp_tcp_tx_proc);
650                 sock->sk->sk_write_space = ncp_tcp_write_space;
651         } else {
652                 INIT_WORK(&server->rcv.tq, ncpdgram_rcv_proc);
653                 INIT_WORK(&server->timeout_tq, ncpdgram_timeout_proc);
654                 server->timeout_tm.data = (unsigned long)server;
655                 server->timeout_tm.function = ncpdgram_timeout_call;
656         }
657         release_sock(sock->sk);
658 
659         ncp_lock_server(server);
660         error = ncp_connect(server);
661         ncp_unlock_server(server);
662         if (error < 0)
663                 goto out_rxbuf;
664         ncp_dbg(1, "NCP_SBP(sb) = %p\n", NCP_SBP(sb));
665 
666         error = -EMSGSIZE;      /* -EREMOTESIDEINCOMPATIBLE */
667 #ifdef CONFIG_NCPFS_PACKET_SIGNING
668         if (ncp_negotiate_size_and_options(server, default_bufsize,
669                 NCP_DEFAULT_OPTIONS, &(server->buffer_size), &options) == 0)
670         {
671                 if (options != NCP_DEFAULT_OPTIONS)
672                 {
673                         if (ncp_negotiate_size_and_options(server, 
674                                 default_bufsize,
675                                 options & 2, 
676                                 &(server->buffer_size), &options) != 0)
677                                 
678                         {
679                                 goto out_disconnect;
680                         }
681                 }
682                 ncp_lock_server(server);
683                 if (options & 2)
684                         server->sign_wanted = 1;
685                 ncp_unlock_server(server);
686         }
687         else 
688 #endif  /* CONFIG_NCPFS_PACKET_SIGNING */
689         if (ncp_negotiate_buffersize(server, default_bufsize,
690                                      &(server->buffer_size)) != 0)
691                 goto out_disconnect;
692         ncp_dbg(1, "bufsize = %d\n", server->buffer_size);
693 
694         memset(&finfo, 0, sizeof(finfo));
695         finfo.i.attributes      = aDIR;
696         finfo.i.dataStreamSize  = 0;    /* ignored */
697         finfo.i.dirEntNum       = 0;
698         finfo.i.DosDirNum       = 0;
699 #ifdef CONFIG_NCPFS_SMALLDOS
700         finfo.i.NSCreator       = NW_NS_DOS;
701 #endif
702         finfo.volume            = NCP_NUMBER_OF_VOLUMES;
703         /* set dates of mountpoint to Jan 1, 1986; 00:00 */
704         finfo.i.creationTime    = finfo.i.modifyTime
705                                 = cpu_to_le16(0x0000);
706         finfo.i.creationDate    = finfo.i.modifyDate
707                                 = finfo.i.lastAccessDate
708                                 = cpu_to_le16(0x0C21);
709         finfo.i.nameLen         = 0;
710         finfo.i.entryName[0]    = '\0';
711 
712         finfo.opened            = 0;
713         finfo.ino               = 2;    /* tradition */
714 
715         server->name_space[finfo.volume] = NW_NS_DOS;
716 
717         error = -ENOMEM;
718         root_inode = ncp_iget(sb, &finfo);
719         if (!root_inode)
720                 goto out_disconnect;
721         ncp_dbg(1, "root vol=%d\n", NCP_FINFO(root_inode)->volNumber);
722         sb->s_root = d_make_root(root_inode);
723         if (!sb->s_root)
724                 goto out_disconnect;
725         return 0;
726 
727 out_disconnect:
728         ncp_lock_server(server);
729         ncp_disconnect(server);
730         ncp_unlock_server(server);
731 out_rxbuf:
732         ncp_stop_tasks(server);
733         vfree(server->rxbuf);
734 out_txbuf:
735         vfree(server->txbuf);
736 out_packet:
737         vfree(server->packet);
738 out_nls:
739 #ifdef CONFIG_NCPFS_NLS
740         unload_nls(server->nls_io);
741         unload_nls(server->nls_vol);
742 #endif
743         mutex_destroy(&server->rcv.creq_mutex);
744         mutex_destroy(&server->root_setup_lock);
745         mutex_destroy(&server->mutex);
746 out_fput2:
747         if (server->info_sock)
748                 sockfd_put(server->info_sock);
749 out_bdi:
750         bdi_destroy(&server->bdi);
751 out_fput:
752         sockfd_put(sock);
753 out:
754         put_pid(data.wdog_pid);
755         sb->s_fs_info = NULL;
756         kfree(server);
757         return error;
758 }
759 
760 static void delayed_free(struct rcu_head *p)
761 {
762         struct ncp_server *server = container_of(p, struct ncp_server, rcu);
763 #ifdef CONFIG_NCPFS_NLS
764         /* unload the NLS charsets */
765         unload_nls(server->nls_vol);
766         unload_nls(server->nls_io);
767 #endif /* CONFIG_NCPFS_NLS */
768         kfree(server);
769 }
770 
771 static void ncp_put_super(struct super_block *sb)
772 {
773         struct ncp_server *server = NCP_SBP(sb);
774 
775         ncp_lock_server(server);
776         ncp_disconnect(server);
777         ncp_unlock_server(server);
778 
779         ncp_stop_tasks(server);
780 
781         mutex_destroy(&server->rcv.creq_mutex);
782         mutex_destroy(&server->root_setup_lock);
783         mutex_destroy(&server->mutex);
784 
785         if (server->info_sock)
786                 sockfd_put(server->info_sock);
787         sockfd_put(server->ncp_sock);
788         kill_pid(server->m.wdog_pid, SIGTERM, 1);
789         put_pid(server->m.wdog_pid);
790 
791         bdi_destroy(&server->bdi);
792         kfree(server->priv.data);
793         kfree(server->auth.object_name);
794         vfree(server->rxbuf);
795         vfree(server->txbuf);
796         vfree(server->packet);
797         call_rcu(&server->rcu, delayed_free);
798 }
799 
800 static int ncp_statfs(struct dentry *dentry, struct kstatfs *buf)
801 {
802         struct dentry* d;
803         struct inode* i;
804         struct ncp_inode_info* ni;
805         struct ncp_server* s;
806         struct ncp_volume_info vi;
807         struct super_block *sb = dentry->d_sb;
808         int err;
809         __u8 dh;
810         
811         d = sb->s_root;
812         if (!d) {
813                 goto dflt;
814         }
815         i = d_inode(d);
816         if (!i) {
817                 goto dflt;
818         }
819         ni = NCP_FINFO(i);
820         if (!ni) {
821                 goto dflt;
822         }
823         s = NCP_SBP(sb);
824         if (!s) {
825                 goto dflt;
826         }
827         if (!s->m.mounted_vol[0]) {
828                 goto dflt;
829         }
830 
831         err = ncp_dirhandle_alloc(s, ni->volNumber, ni->DosDirNum, &dh);
832         if (err) {
833                 goto dflt;
834         }
835         err = ncp_get_directory_info(s, dh, &vi);
836         ncp_dirhandle_free(s, dh);
837         if (err) {
838                 goto dflt;
839         }
840         buf->f_type = NCP_SUPER_MAGIC;
841         buf->f_bsize = vi.sectors_per_block * 512;
842         buf->f_blocks = vi.total_blocks;
843         buf->f_bfree = vi.free_blocks;
844         buf->f_bavail = vi.free_blocks;
845         buf->f_files = vi.total_dir_entries;
846         buf->f_ffree = vi.available_dir_entries;
847         buf->f_namelen = 12;
848         return 0;
849 
850         /* We cannot say how much disk space is left on a mounted
851            NetWare Server, because free space is distributed over
852            volumes, and the current user might have disk quotas. So
853            free space is not that simple to determine. Our decision
854            here is to err conservatively. */
855 
856 dflt:;
857         buf->f_type = NCP_SUPER_MAGIC;
858         buf->f_bsize = NCP_BLOCK_SIZE;
859         buf->f_blocks = 0;
860         buf->f_bfree = 0;
861         buf->f_bavail = 0;
862         buf->f_namelen = 12;
863         return 0;
864 }
865 
866 int ncp_notify_change(struct dentry *dentry, struct iattr *attr)
867 {
868         struct inode *inode = d_inode(dentry);
869         int result = 0;
870         __le32 info_mask;
871         struct nw_modify_dos_info info;
872         struct ncp_server *server;
873 
874         result = -EIO;
875 
876         server = NCP_SERVER(inode);
877         if (!server)    /* How this could happen? */
878                 goto out;
879 
880         result = -EPERM;
881         if (IS_DEADDIR(d_inode(dentry)))
882                 goto out;
883 
884         /* ageing the dentry to force validation */
885         ncp_age_dentry(server, dentry);
886 
887         result = inode_change_ok(inode, attr);
888         if (result < 0)
889                 goto out;
890 
891         result = -EPERM;
892         if ((attr->ia_valid & ATTR_UID) && !uid_eq(attr->ia_uid, server->m.uid))
893                 goto out;
894 
895         if ((attr->ia_valid & ATTR_GID) && !gid_eq(attr->ia_gid, server->m.gid))
896                 goto out;
897 
898         if (((attr->ia_valid & ATTR_MODE) &&
899              (attr->ia_mode &
900               ~(S_IFREG | S_IFDIR | S_IRWXUGO))))
901                 goto out;
902 
903         info_mask = 0;
904         memset(&info, 0, sizeof(info));
905 
906 #if 1 
907         if ((attr->ia_valid & ATTR_MODE) != 0)
908         {
909                 umode_t newmode = attr->ia_mode;
910 
911                 info_mask |= DM_ATTRIBUTES;
912 
913                 if (S_ISDIR(inode->i_mode)) {
914                         newmode &= server->m.dir_mode;
915                 } else {
916 #ifdef CONFIG_NCPFS_EXTRAS                      
917                         if (server->m.flags & NCP_MOUNT_EXTRAS) {
918                                 /* any non-default execute bit set */
919                                 if (newmode & ~server->m.file_mode & S_IXUGO)
920                                         info.attributes |= aSHARED | aSYSTEM;
921                                 /* read for group/world and not in default file_mode */
922                                 else if (newmode & ~server->m.file_mode & S_IRUGO)
923                                         info.attributes |= aSHARED;
924                         } else
925 #endif
926                                 newmode &= server->m.file_mode;                 
927                 }
928                 if (newmode & S_IWUGO)
929                         info.attributes &= ~(aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
930                 else
931                         info.attributes |=  (aRONLY|aRENAMEINHIBIT|aDELETEINHIBIT);
932 
933 #ifdef CONFIG_NCPFS_NFS_NS
934                 if (ncp_is_nfs_extras(server, NCP_FINFO(inode)->volNumber)) {
935                         result = ncp_modify_nfs_info(server,
936                                                      NCP_FINFO(inode)->volNumber,
937                                                      NCP_FINFO(inode)->dirEntNum,
938                                                      attr->ia_mode, 0);
939                         if (result != 0)
940                                 goto out;
941                         info.attributes &= ~(aSHARED | aSYSTEM);
942                         {
943                                 /* mark partial success */
944                                 struct iattr tmpattr;
945                                 
946                                 tmpattr.ia_valid = ATTR_MODE;
947                                 tmpattr.ia_mode = attr->ia_mode;
948 
949                                 setattr_copy(inode, &tmpattr);
950                                 mark_inode_dirty(inode);
951                         }
952                 }
953 #endif
954         }
955 #endif
956 
957         /* Do SIZE before attributes, otherwise mtime together with size does not work...
958          */
959         if ((attr->ia_valid & ATTR_SIZE) != 0) {
960                 int written;
961 
962                 ncp_dbg(1, "trying to change size to %llu\n", attr->ia_size);
963 
964                 if ((result = ncp_make_open(inode, O_WRONLY)) < 0) {
965                         result = -EACCES;
966                         goto out;
967                 }
968                 ncp_write_kernel(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
969                           attr->ia_size, 0, "", &written);
970 
971                 /* According to ndir, the changes only take effect after
972                    closing the file */
973                 ncp_inode_close(inode);
974                 result = ncp_make_closed(inode);
975                 if (result)
976                         goto out;
977 
978                 if (attr->ia_size != i_size_read(inode)) {
979                         truncate_setsize(inode, attr->ia_size);
980                         mark_inode_dirty(inode);
981                 }
982         }
983         if ((attr->ia_valid & ATTR_CTIME) != 0) {
984                 info_mask |= (DM_CREATE_TIME | DM_CREATE_DATE);
985                 ncp_date_unix2dos(attr->ia_ctime.tv_sec,
986                              &info.creationTime, &info.creationDate);
987         }
988         if ((attr->ia_valid & ATTR_MTIME) != 0) {
989                 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
990                 ncp_date_unix2dos(attr->ia_mtime.tv_sec,
991                                   &info.modifyTime, &info.modifyDate);
992         }
993         if ((attr->ia_valid & ATTR_ATIME) != 0) {
994                 __le16 dummy;
995                 info_mask |= (DM_LAST_ACCESS_DATE);
996                 ncp_date_unix2dos(attr->ia_atime.tv_sec,
997                                   &dummy, &info.lastAccessDate);
998         }
999         if (info_mask != 0) {
1000                 result = ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
1001                                       inode, info_mask, &info);
1002                 if (result != 0) {
1003                         if (info_mask == (DM_CREATE_TIME | DM_CREATE_DATE)) {
1004                                 /* NetWare seems not to allow this. I
1005                                    do not know why. So, just tell the
1006                                    user everything went fine. This is
1007                                    a terrible hack, but I do not know
1008                                    how to do this correctly. */
1009                                 result = 0;
1010                         } else
1011                                 goto out;
1012                 }
1013 #ifdef CONFIG_NCPFS_STRONG              
1014                 if ((!result) && (info_mask & DM_ATTRIBUTES))
1015                         NCP_FINFO(inode)->nwattr = info.attributes;
1016 #endif
1017         }
1018         if (result)
1019                 goto out;
1020 
1021         setattr_copy(inode, attr);
1022         mark_inode_dirty(inode);
1023 
1024 out:
1025         if (result > 0)
1026                 result = -EACCES;
1027         return result;
1028 }
1029 
1030 static struct dentry *ncp_mount(struct file_system_type *fs_type,
1031         int flags, const char *dev_name, void *data)
1032 {
1033         return mount_nodev(fs_type, flags, data, ncp_fill_super);
1034 }
1035 
1036 static struct file_system_type ncp_fs_type = {
1037         .owner          = THIS_MODULE,
1038         .name           = "ncpfs",
1039         .mount          = ncp_mount,
1040         .kill_sb        = kill_anon_super,
1041         .fs_flags       = FS_BINARY_MOUNTDATA,
1042 };
1043 MODULE_ALIAS_FS("ncpfs");
1044 
1045 static int __init init_ncp_fs(void)
1046 {
1047         int err;
1048         ncp_dbg(1, "called\n");
1049 
1050         err = init_inodecache();
1051         if (err)
1052                 goto out1;
1053         err = register_filesystem(&ncp_fs_type);
1054         if (err)
1055                 goto out;
1056         return 0;
1057 out:
1058         destroy_inodecache();
1059 out1:
1060         return err;
1061 }
1062 
1063 static void __exit exit_ncp_fs(void)
1064 {
1065         ncp_dbg(1, "called\n");
1066         unregister_filesystem(&ncp_fs_type);
1067         destroy_inodecache();
1068 }
1069 
1070 module_init(init_ncp_fs)
1071 module_exit(exit_ncp_fs)
1072 MODULE_LICENSE("GPL");
1073 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | Wiki (Japanese) | Wiki (English) | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

osdn.jp