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 = 1024;
  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         char command[ sizeof(server->m.mount_point)
 374                      + sizeof(NCP_MSG_COMMAND) + 2];
 375 
 376         if (server == NULL)
 377         {
 378                 printk("ncp_trigger_message: invalid server!\n");
 379                 return;
 380         }
 381 
 382         DPRINTK("ncp_trigger_message: on %s\n",
 383                 server->m.mount_point);
 384 
 385 #ifdef CONFIG_KERNELD
 386         strcpy(command, NCP_MSG_COMMAND);
 387         strcat(command, " ");
 388         strcat(command, server->m.mount_point);
 389         DPRINTK("ksystem: %s\n", command);
 390         ksystem(command, KERNELD_NOWAIT);
 391 #endif
 392 }
 393 
 394 static void 
 395 ncp_statfs(struct super_block *sb, struct statfs *buf, int bufsiz)
     /* [previous][next][first][last][top][bottom][index][help] */
 396 {
 397         struct statfs tmp;
 398         
 399         /* We cannot say how much disk space is left on a mounted
 400            NetWare Server, because free space is distributed over
 401            volumes, and the current user might have disk quotas. So
 402            free space is not that simple to determine. Our decision
 403            here is to err conservatively. */
 404 
 405         tmp.f_type = NCP_SUPER_MAGIC;
 406         tmp.f_bsize = 512;
 407         tmp.f_blocks = 0;
 408         tmp.f_bfree = 0;
 409         tmp.f_bavail = 0;
 410         tmp.f_files = -1;
 411         tmp.f_ffree = -1;
 412         tmp.f_namelen = 12;
 413         memcpy_tofs(buf, &tmp, bufsiz);
 414 }
 415 
 416 static int
 417 ncp_notify_change(struct inode *inode, struct iattr *attr)
     /* [previous][next][first][last][top][bottom][index][help] */
 418 {
 419         int result = 0;
 420         int info_mask;
 421         struct nw_modify_dos_info info;
 422 
 423         if (!ncp_conn_valid(NCP_SERVER(inode)))
 424         {
 425                 return -EIO;
 426         }
 427 
 428         if ((result = inode_change_ok(inode, attr)) < 0)
 429                 return result;
 430 
 431         if (((attr->ia_valid & ATTR_UID) && 
 432              (attr->ia_uid != NCP_SERVER(inode)->m.uid)))
 433                 return -EPERM;
 434 
 435         if (((attr->ia_valid & ATTR_GID) && 
 436              (attr->ia_uid != NCP_SERVER(inode)->m.gid)))
 437                 return -EPERM;
 438 
 439         if (((attr->ia_valid & ATTR_MODE) &&
 440              (attr->ia_mode &
 441               ~(S_IFREG | S_IFDIR | S_IRWXU | S_IRWXG | S_IRWXO))))
 442                 return -EPERM;
 443 
 444         info_mask = 0;
 445         memset(&info, 0, sizeof(info));
 446 
 447         if ((attr->ia_valid & ATTR_CTIME) != 0)
 448         {
 449                 info_mask |= (DM_CREATE_TIME|DM_CREATE_DATE);
 450                 ncp_date_unix2dos(attr->ia_ctime,
 451                                   &(info.creationTime), &(info.creationDate));
 452         }
 453         
 454         if ((attr->ia_valid & ATTR_MTIME) != 0)
 455         {
 456                 info_mask |= (DM_MODIFY_TIME|DM_MODIFY_DATE);
 457                 ncp_date_unix2dos(attr->ia_mtime,
 458                                   &(info.modifyTime), &(info.modifyDate));
 459         }
 460         
 461         if ((attr->ia_valid & ATTR_ATIME) != 0)
 462         {
 463                 __u16 dummy;
 464                 info_mask |= (DM_LAST_ACCESS_DATE);
 465                 ncp_date_unix2dos(attr->ia_ctime,
 466                                   &(dummy), &(info.lastAccessDate));
 467         }
 468 
 469         if (info_mask != 0)
 470         {
 471                 if ((result =
 472                      ncp_modify_file_or_subdir_dos_info(NCP_SERVER(inode),
 473                                                         NCP_ISTRUCT(inode),
 474                                                         info_mask,
 475                                                         &info)) != 0)
 476                 {
 477                         result = -EACCES;
 478 
 479                         if (info_mask == (DM_CREATE_TIME|DM_CREATE_DATE))
 480                         {
 481                                 /* NetWare seems not to allow this. I
 482                                    do not know why. So, just tell the
 483                                    user everything went fine. This is
 484                                    a terrible hack, but I do not know
 485                                    how to do this correctly. */
 486                                 result = 0;
 487                         }
 488                 }
 489         }
 490 
 491         if ((attr->ia_valid & ATTR_SIZE) != 0)
 492         {
 493                 int written;
 494 
 495                 DPRINTK("ncpfs: trying to change size of %s to %ld\n",
 496                         NCP_ISTRUCT(inode)->entryName, attr->ia_size);
 497 
 498                 if ((result = ncp_make_open(inode, O_RDWR)) < 0)
 499                 {
 500                         return -EACCES;
 501                 }
 502 
 503                 ncp_write(NCP_SERVER(inode), NCP_FINFO(inode)->file_handle,
 504                           attr->ia_size, 0, "", &written);
 505 
 506                 /* According to ndir, the changes only take effect after
 507                    closing the file */
 508                 ncp_close_file(NCP_SERVER(inode),
 509                                NCP_FINFO(inode)->file_handle);
 510                 NCP_FINFO(inode)->opened = 0;
 511 
 512                 result = 0;
 513         }
 514 
 515         ncp_invalid_dir_cache(NCP_INOP(inode)->dir->inode);
 516 
 517         return result;
 518 }
 519                 
 520 #ifdef DEBUG_NCP_MALLOC
 521 int ncp_malloced;
 522 int ncp_current_malloced;
 523 #endif
 524 
 525 static struct file_system_type ncp_fs_type = {
 526         ncp_read_super, "ncpfs", 0, NULL
 527         };
 528 
 529 int init_ncp_fs(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 530 {
 531         return register_filesystem(&ncp_fs_type);
 532 }
 533 
 534 #ifdef MODULE
 535 int
 536 init_module( void)
     /* [previous][next][first][last][top][bottom][index][help] */
 537 {
 538         int status;
 539 
 540         DPRINTK("ncpfs: init_module called\n");
 541 
 542 #ifdef DEBUG_NCP_MALLOC
 543         ncp_malloced = 0;
 544         ncp_current_malloced = 0;
 545 #endif
 546         ncp_init_dir_cache();
 547 
 548         if ((status = init_ncp_fs()) == 0)
 549                 register_symtab(0);
 550         return status;
 551 }
 552 
 553 void
 554 cleanup_module(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 555 {
 556         DPRINTK("ncpfs: cleanup_module called\n");
 557         ncp_free_dir_cache();
 558         unregister_filesystem(&ncp_fs_type);
 559 #ifdef DEBUG_NCP_MALLOC
 560         printk("ncp_malloced: %d\n", ncp_malloced);
 561         printk("ncp_current_malloced: %d\n", ncp_current_malloced);
 562 #endif
 563 }
 564 
 565 #endif

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