root/fs/ncpfs/inode.c

/* [previous][next][first][last][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. ncp_read_inode
  2. ncp_put_inode
  3. ncp_read_super
  4. ncp_put_super
  5. ncp_trigger_message
  6. ncp_statfs
  7. ncp_notify_change
  8. init_ncp_fs
  9. init_module
  10. cleanup_module

   1 /*
   2  *  inode.c
   3  *
   4  *  Copyright (C) 1995, 1996 by Volker Lendecke
   5  *
   6  */
   7 
   8 #include <linux/module.h>
   9 #include <linux/config.h>
  10 
  11 #include <asm/system.h>
  12 #include <asm/segment.h>
  13 
  14 #include <linux/sched.h>
  15 #include <linux/ncp_fs.h>
  16 #include <linux/kernel.h>
  17 #include <linux/mm.h>
  18 #include <linux/string.h>
  19 #include <linux/stat.h>
  20 #include <linux/errno.h>
  21 #include <linux/locks.h>
  22 #include <linux/fcntl.h>
  23 #include <linux/malloc.h>
  24 #ifdef CONFIG_KERNELD
  25 #include <linux/kerneld.h>
  26 #endif
  27 #include "ncplib_kernel.h"
  28 
  29 extern int close_fp(struct file *filp);
  30 
  31 static void ncp_put_inode(struct inode *);
  32 static void ncp_read_inode(struct inode *);
  33 static void ncp_put_super(struct super_block *);
  34 static void ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz);
  35 static int ncp_notify_change(struct inode *inode, struct iattr *attr);
  36 
  37 static struct super_operations ncp_sops = {
  38         ncp_read_inode,         /* read inode */
  39         ncp_notify_change,      /* notify change */
  40         NULL,                   /* write inode */
  41         ncp_put_inode,          /* put inode */
  42         ncp_put_super,          /* put superblock */
  43         NULL,                   /* write superblock */
  44         ncp_statfs,             /* stat filesystem */
  45         NULL
  46 };
  47 
  48 /* ncp_read_inode: Called from iget, it only traverses the allocated
  49    ncp_inode_info's and initializes the inode from the data found
  50    there.  It does not allocate or deallocate anything. */
  51 
  52 static void
  53 ncp_read_inode(struct inode *inode)
     /* [previous][next][first][last][top][bottom][index][help] */
  54 {
  55         /* Our task should be extremely simple here. We only have to
  56            look up the information somebody else (ncp_iget) put into
  57            the inode tree. The address of this information is the
  58            inode->i_ino. Just to make sure everything went well, we
  59            check it's there. */
  60 
  61         struct ncp_inode_info *inode_info = ncp_find_inode(inode);
  62 
  63         if (inode_info == NULL)
  64         {
  65                 /* Ok, now we're in trouble. The inode info is not there. What
  66                    should we do now??? */
  67                 printk("ncp_read_inode: inode info not found\n");
  68                 return;
  69         }
  70 
  71         inode_info->state = NCP_INODE_VALID;
  72 
  73         NCP_INOP(inode) = inode_info;
  74         inode_info->inode = inode;
  75 
  76         if (NCP_ISTRUCT(inode)->attributes & aDIR)
  77         {
  78                 inode->i_mode = NCP_SERVER(inode)->m.dir_mode;
  79                 /* for directories dataStreamSize seems to be some
  80                    Object ID ??? */
  81                 inode->i_size = 512;
  82         }
  83         else
  84         {
  85                 inode->i_mode = NCP_SERVER(inode)->m.file_mode;
  86                 inode->i_size = NCP_ISTRUCT(inode)->dataStreamSize;
  87         }
  88 
  89         DDPRINTK("ncp_read_inode: inode->i_mode = %u\n", inode->i_mode);
  90 
  91         inode->i_nlink   = 1;
  92         inode->i_uid     = NCP_SERVER(inode)->m.uid;
  93         inode->i_gid     = NCP_SERVER(inode)->m.gid;
  94         inode->i_blksize = 512;
  95         inode->i_rdev    = 0;
  96 
  97         if ((inode->i_blksize != 0) && (inode->i_size != 0))
  98         {
  99                 inode->i_blocks =
 100                         (inode->i_size - 1) / inode->i_blksize + 1;
 101         }
 102         else
 103         {
 104                 inode->i_blocks = 0;
 105         }
 106 
 107         inode->i_mtime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->modifyTime,
 108                                            NCP_ISTRUCT(inode)->modifyDate);
 109         inode->i_ctime = ncp_date_dos2unix(NCP_ISTRUCT(inode)->creationTime,
 110                                            NCP_ISTRUCT(inode)->creationDate);
 111         inode->i_atime = ncp_date_dos2unix(0,
 112                                            NCP_ISTRUCT(inode)->lastAccessDate);
 113 
 114         if (S_ISREG(inode->i_mode))
 115         {
 116                 inode->i_op = &ncp_file_inode_operations;
 117         }
 118         else if (S_ISDIR(inode->i_mode))
 119         {
 120                 inode->i_op = &ncp_dir_inode_operations;
 121         }
 122         else
 123         {
 124                 inode->i_op = NULL;
 125         }
 126 }
 127 
 128 static void
 129 ncp_put_inode(struct inode *inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 130 {
 131         struct nw_file_info *finfo = NCP_FINFO(inode);
 132 
 133         if (finfo->opened != 0)
 134         {
 135                 if (ncp_close_file(NCP_SERVER(inode), finfo->file_handle)!=0)
 136                 {
 137                         /* We can't do anything but complain. */
 138                         printk("ncp_put_inode: could not close\n");
 139                 }
 140         }
 141 
 142         DDPRINTK("ncp_put_inode: put %s\n",
 143                 finfo->i.entryName);
 144 
 145         ncp_free_inode_info(NCP_INOP(inode));
 146 
 147         if (S_ISDIR(inode->i_mode))
 148         {
 149                 DDPRINTK("ncp_put_inode: put directory %ld\n",
 150                          inode->i_ino);
 151                 ncp_invalid_dir_cache(inode);
 152         }                
 153 
 154         clear_inode(inode);
 155 }
 156 
 157 struct super_block *
 158 ncp_read_super(struct super_block *sb, void *raw_data, int silent)
     /* [previous][next][first][last][top][bottom][index][help] */
 159 {
 160         struct ncp_mount_data *data = (struct ncp_mount_data *) raw_data;
 161         struct ncp_server *server;
 162         struct file *ncp_filp;
 163         struct file *wdog_filp;
 164         struct file *msg_filp;
 165         kdev_t dev = sb->s_dev;
 166         int error;
 167 
 168         if (data == NULL)
 169         {
 170                 printk("ncp_read_super: missing data argument\n");
 171                 sb->s_dev = 0;
 172                 return NULL;
 173         }
 174 
 175         if (data->version != NCP_MOUNT_VERSION)
 176         {
 177                 printk("ncp warning: mount version %s than kernel\n",
 178                        (data->version < NCP_MOUNT_VERSION) ?
 179                        "older" : "newer");
 180                 sb->s_dev = 0;
 181                 return NULL;
 182         }
 183 
 184         if (   (data->ncp_fd >= NR_OPEN)
 185             || ((ncp_filp = current->files->fd[data->ncp_fd]) == NULL)
 186             || (!S_ISSOCK(ncp_filp->f_inode->i_mode)))
 187         {
 188                 printk("ncp_read_super: invalid ncp socket\n");
 189                 sb->s_dev = 0;
 190                 return NULL;
 191         }
 192 
 193         if (   (data->wdog_fd >= NR_OPEN)
 194             || ((wdog_filp = current->files->fd[data->wdog_fd]) == NULL)
 195             || (!S_ISSOCK(wdog_filp->f_inode->i_mode)))
 196         {
 197                 printk("ncp_read_super: invalid wdog socket\n");
 198                 sb->s_dev = 0;
 199                 return NULL;
 200         }
 201 
 202         if (   (data->message_fd >= NR_OPEN)
 203             || ((msg_filp = current->files->fd[data->message_fd]) == NULL)
 204             || (!S_ISSOCK(msg_filp->f_inode->i_mode)))
 205         {
 206                 printk("ncp_read_super: invalid wdog socket\n");
 207                 sb->s_dev = 0;
 208                 return NULL;
 209         }
 210 
 211         /* We must malloc our own super-block info */
 212         server = (struct ncp_server *)ncp_kmalloc(sizeof(struct ncp_server),
 213                                                    GFP_KERNEL);
 214 
 215         if (server == NULL)
 216         {
 217                 printk("ncp_read_super: could not alloc ncp_server\n");
 218                 return NULL;
 219         }
 220 
 221         ncp_filp->f_count += 1;
 222         wdog_filp->f_count += 1;
 223         msg_filp->f_count += 1;
 224 
 225         lock_super(sb);
 226 
 227         NCP_SBP(sb) = server;
 228         
 229         sb->s_blocksize = 1024; /* Eh...  Is this correct? */
 230         sb->s_blocksize_bits = 10;
 231         sb->s_magic = NCP_SUPER_MAGIC;
 232         sb->s_dev = dev;
 233         sb->s_op = &ncp_sops;
 234 
 235         server->ncp_filp    = ncp_filp;
 236         server->wdog_filp   = wdog_filp;
 237         server->msg_filp    = msg_filp;
 238         server->lock        = 0;
 239         server->wait        = NULL;
 240         server->packet      = NULL;
 241         server->buffer_size = 0;
 242         server->conn_status = 0;
 243 
 244         server->m = *data;
 245         server->m.file_mode = (server->m.file_mode &
 246                                (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFREG;
 247         server->m.dir_mode  = (server->m.dir_mode &
 248                                (S_IRWXU|S_IRWXG|S_IRWXO)) | S_IFDIR;
 249 
 250         /* protect against invalid mount points */
 251         server->m.mount_point[sizeof(server->m.mount_point)-1] = '\0';
 252 
 253         server->packet_size = NCP_PACKET_SIZE;
 254         server->packet      = ncp_kmalloc(NCP_PACKET_SIZE, GFP_KERNEL);
 255 
 256         if (server->packet == NULL)
 257         {
 258                 printk("ncpfs: could not alloc packet\n");
 259                 error = -ENOMEM;
 260                 unlock_super(sb);
 261                 goto fail;
 262         }
 263    
 264         /*
 265          * Make the connection to the server
 266          */
 267 
 268         if (ncp_catch_watchdog(server) != 0)
 269         {
 270                 printk("ncp_read_super: Could not catch watchdog\n");
 271                 error = -EINVAL;
 272                 unlock_super(sb);
 273                 goto fail;
 274         }
 275 
 276         if (ncp_catch_message(server) != 0)
 277         {
 278                 printk("ncp_read_super: Could not catch messages\n");
 279                 ncp_dont_catch_watchdog(server);
 280                 error = -EINVAL;
 281                 unlock_super(sb);
 282                 goto fail;
 283         }
 284 
 285         ncp_lock_server(server);
 286         error = ncp_connect(server);
 287         ncp_unlock_server(server);
 288         unlock_super(sb);
 289 
 290         if (error < 0)
 291         {
 292                 sb->s_dev = 0;
 293                 printk("ncp_read_super: Failed connection, bailing out "
 294                        "(error = %d).\n", -error);
 295                 ncp_kfree_s(server->packet, server->packet_size);
 296                 ncp_dont_catch_watchdog(server);
 297                 goto fail;
 298         }
 299 
 300         DPRINTK("ncp_read_super: NCP_SBP(sb) = %x\n", (int)NCP_SBP(sb));
 301 
 302         ncp_init_root(server);
 303 
 304         if (!(sb->s_mounted = iget(sb, ncp_info_ino(server, &(server->root)))))
 305         {
 306                 sb->s_dev = 0;
 307                 printk("ncp_read_super: get root inode failed\n");
 308                 goto disconnect;
 309         }
 310 
 311         if (ncp_negotiate_buffersize(server, NCP_DEFAULT_BUFSIZE,
 312                                      &(server->buffer_size)) != 0)
 313         {
 314                 sb->s_dev = 0;
 315                 printk("ncp_read_super: could not get bufsize\n");
 316                 goto disconnect;
 317         }
 318 
 319         DPRINTK("ncpfs: bufsize = %d\n", server->buffer_size);
 320 
 321         MOD_INC_USE_COUNT;
 322         return sb;
 323 
 324  disconnect:
 325         ncp_lock_server(server);
 326         ncp_disconnect(server);
 327         ncp_unlock_server(server);
 328         ncp_kfree_s(server->packet, server->packet_size);
 329         ncp_dont_catch_watchdog(server);
 330  fail:
 331         ncp_filp->f_count -= 1;
 332         wdog_filp->f_count -= 1;
 333         msg_filp->f_count -= 1;
 334         ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
 335         return NULL;
 336 }
 337 
 338 static void
 339 ncp_put_super(struct super_block *sb)
     /* [previous][next][first][last][top][bottom][index][help] */
 340 {
 341         struct ncp_server *server = NCP_SBP(sb);
 342 
 343         lock_super(sb);
 344 
 345         ncp_lock_server(server);
 346         ncp_disconnect(server);
 347         ncp_unlock_server(server);
 348 
 349         close_fp(server->ncp_filp);
 350 
 351         ncp_dont_catch_watchdog(server);
 352         close_fp(server->wdog_filp);
 353         close_fp(server->msg_filp);
 354 
 355         ncp_free_all_inodes(server);
 356 
 357         ncp_kfree_s(server->packet, server->packet_size);
 358 
 359         sb->s_dev = 0;
 360         ncp_kfree_s(NCP_SBP(sb), sizeof(struct ncp_server));
 361         NCP_SBP(sb) = NULL;
 362 
 363         unlock_super(sb);
 364 
 365         MOD_DEC_USE_COUNT;
 366 }
 367 
 368 /* This routine is called from an interrupt in ncp_msg_data_ready. So
 369  * we have to be careful NOT to sleep here! */
 370 void
 371 ncp_trigger_message(struct ncp_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 372 {
 373 #ifdef CONFIG_KERNELD
 374         char command[ sizeof(server->m.mount_point)
 375                      + sizeof(NCP_MSG_COMMAND) + 2];
 376 #endif
 377 
 378         if (server == NULL)
 379         {
 380                 printk("ncp_trigger_message: invalid server!\n");
 381                 return;
 382         }
 383 
 384         DPRINTK("ncp_trigger_message: on %s\n",
 385                 server->m.mount_point);
 386 
 387 #ifdef CONFIG_KERNELD
 388         strcpy(command, NCP_MSG_COMMAND);
 389         strcat(command, " ");
 390         strcat(command, server->m.mount_point);
 391         DPRINTK("ksystem: %s\n", command);
 392         ksystem(command, KERNELD_NOWAIT);
 393 #endif
 394 }
 395 
 396 static void 
 397 ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
     /* [previous][next][first][last][top][bottom][index][help] */
 398 {
 399         struct statfs tmp;
 400         
 401         /* We cannot say how much disk space is left on a mounted
 402            NetWare Server, because free space is distributed over
 403            volumes, and the current user might have disk quotas. So
 404            free space is not that simple to determine. Our decision
 405            here is to err conservatively. */
 406 
 407         tmp.f_type = NCP_SUPER_MAGIC;
 408         tmp.f_bsize = 512;
 409         tmp.f_blocks = 0;
 410         tmp.f_bfree = 0;
 411         tmp.f_bavail = 0;
 412         tmp.f_files = -1;
 413         tmp.f_ffree = -1;
 414         tmp.f_namelen = 12;
 415         memcpy_tofs(buf, &tmp, bufsiz);
 416 }
 417 
 418 static int
 419 ncp_notify_change(struct inode *inode, struct iattr *attr)
     /* [previous][next][first][last][top][bottom][index][help] */
 420 {
 421         int result = 0;
 422         int info_mask;
 423         struct nw_modify_dos_info info;
 424 
 425         if (!ncp_conn_valid(NCP_SERVER(inode)))
 426         {
 427                 return -EIO;
 428         }
 429 
 430         if ((result = inode_change_ok(inode, attr)) < 0)
 431                 return result;
 432 
 433         if (((attr->ia_valid & ATTR_UID) && 
 434              (attr->ia_uid != NCP_SERVER(inode)->m.uid)))
 435                 return -EPERM;
 436 
 437         if (((attr->ia_valid & ATTR_GID) && 
 438              (attr->ia_uid != NCP_SERVER(inode)->m.gid)))
 439                 return -EPERM;
 440 
 441         if (((attr->ia_valid & ATTR_MODE) &&
 442              (attr->ia_mode &
 443               ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
 444                 return -EPERM;
 445 
 446         info_mask = 0;
 447         memset(&info, 0, sizeof(info));
 448 
 449         if ((attr->ia_valid & ATTR_CTIME) != 0)
 450         {
 451                 info_mask |= (DM_CREATE_TIME|DM_CREATE_DATE);
 452                 ncp_date_unix2dos(attr->ia_ctime,
 453                                   &(info.creationTime), &(info.creationDate));
 454         }
 455         
 456         if ((attr->ia_valid & ATTR_MTIME) != 0)
 457         {
 458                 info_mask |= (DM_MODIFY_TIME|DM_MODIFY_DATE);
 459                 ncp_date_unix2dos(attr->ia_mtime,
 460                                   &(info.modifyTime), &(info.modifyDate));
 461         }
 462         
 463         if ((attr->ia_valid & ATTR_ATIME) != 0)
 464         {
 465                 __u16 dummy;
 466                 info_mask |= (DM_LAST_ACCESS_DATE);
 467                 ncp_date_unix2dos(attr->ia_ctime,
 468                                   &(dummy), &(info.lastAccessDate));
 469         }
 470 
 471         if (info_mask != 0)
 472         {
 473                 if ((result =
 474                      ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
 475                                                         NCP_ISTRUCT(inode),
 476                                                         info_mask,
 477                                                         &info)) != 0)
 478                 {
 479                         result = -EACCES;
 480 
 481                         if (info_mask == (DM_CREATE_TIME|DM_CREATE_DATE))
 482                         {
 483                                 /* NetWare seems not to allow this. I
 484                                    do not know why. So, just tell the
 485                                    user everything went fine. This is
 486                                    a terrible hack, but I do not know
 487                                    how to do this correctly. */
 488                                 result = 0;
 489                         }
 490                 }
 491         }
 492 
 493         if ((attr->ia_valid & ATTR_SIZE) != 0)
 494         {
 495                 int written;
 496 
 497                 DPRINTK("ncpfs: trying to change size of %s to %ld\n",
 498                         NCP_ISTRUCT(inode)->entryName, attr->ia_size);
 499 
 500                 if ((result = ncp_make_open(inode, O_RDWR)) < 0)
 501                 {
 502                         return -EACCES;
 503                 }
 504 
 505                 ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
 506                           attr->ia_size, 0, "", &written);
 507 
 508                 /* According to ndir, the changes only take effect after
 509                    closing the file */
 510                 ncp_close_file(NCP_SERVER(inode),
 511                                NCP_FINFO(inode)->file_handle);
 512                 NCP_FINFO(inode)->opened = 0;
 513 
 514                 result = 0;
 515         }
 516 
 517         ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
 518 
 519         return result;
 520 }
 521                 
 522 #ifdef DEBUG_NCP_MALLOC
 523 int ncp_malloced;
 524 int ncp_current_malloced;
 525 #endif
 526 
 527 static struct file_system_type ncp_fs_type = {
 528         ncp_read_super, "ncpfs", 0, NULL
 529         };
 530 
 531 int init_ncp_fs(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 532 {
 533         return register_filesystem(&ncp_fs_type);
 534 }
 535 
 536 #ifdef MODULE
 537 int
 538 init_module( void)
     /* [previous][next][first][last][top][bottom][index][help] */
 539 {
 540         int status;
 541 
 542         DPRINTK("ncpfs: init_module called\n");
 543 
 544 #ifdef DEBUG_NCP_MALLOC
 545         ncp_malloced = 0;
 546         ncp_current_malloced = 0;
 547 #endif
 548         ncp_init_dir_cache();
 549 
 550         if ((status = init_ncp_fs()) == 0)
 551                 register_symtab(0);
 552         return status;
 553 }
 554 
 555 void
 556 cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 557 {
 558         DPRINTK("ncpfs: cleanup_module called\n");
 559         ncp_free_dir_cache();
 560         unregister_filesystem(&ncp_fs_type);
 561 #ifdef DEBUG_NCP_MALLOC
 562         printk("ncp_malloced: %d\n", ncp_malloced);
 563         printk("ncp_current_malloced: %d\n", ncp_current_malloced);
 564 #endif
 565 }
 566 
 567 #endif

/* [previous][next][first][last][top][bottom][index][help] */