root/fs/ncpfs/dir.c

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

DEFINITIONS

This source file includes following definitions.
  1. str_upper
  2. str_lower
  3. ncp_single_volume
  4. ncp_info_ino
  5. ncp_is_server_root
  6. ncp_find_inode
  7. ncp_dir_read
  8. ncp_readdir
  9. ncp_read_volume_list
  10. ncp_do_readdir
  11. ncp_init_dir_cache
  12. ncp_invalid_dir_cache
  13. ncp_free_dir_cache
  14. ncp_iget
  15. ncp_free_inode_info
  16. ncp_init_root
  17. ncp_conn_logged_in
  18. ncp_free_all_inodes
  19. ncp_find_dir_inode
  20. ncp_lookup
  21. ncp_create
  22. ncp_mkdir
  23. ncp_rmdir
  24. ncp_unlink
  25. ncp_rename
  26. utc2local
  27. local2utc
  28. ncp_date_dos2unix
  29. ncp_date_unix2dos

   1 /*
   2  *  dir.c
   3  *
   4  *  Copyright (C) 1995, 1996 by Volker Lendecke
   5  *
   6  */
   7 
   8 #include <linux/sched.h>
   9 #include <linux/errno.h>
  10 #include <linux/stat.h>
  11 #include <linux/kernel.h>
  12 #include <linux/malloc.h>
  13 #include <linux/mm.h>
  14 #include <linux/ncp_fs.h>
  15 #include <asm/segment.h>
  16 #include <linux/errno.h>
  17 #include "ncplib_kernel.h"
  18 
  19 struct ncp_dirent {
  20         struct nw_info_struct i;
  21         struct nw_search_sequence s; /* given back for i */
  22         unsigned long f_pos;
  23 };
  24 
  25 static int 
  26 ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count);
  27 
  28 static int 
  29 ncp_readdir(struct inode *inode, struct file *filp,
  30             void *dirent, filldir_t filldir);
  31 
  32 static int
  33 ncp_read_volume_list(struct ncp_server *server, int start_with,
  34                      int cache_size);
  35 
  36 static int
  37 ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
  38                int cache_size, struct ncp_dirent *entry);
  39 
  40 static struct inode *
  41 ncp_iget(struct inode *dir, struct nw_file_info *finfo);
  42 
  43 static struct ncp_inode_info *
  44 ncp_find_dir_inode(struct inode *dir, const char *name);
  45 
  46 static int
  47 ncp_lookup(struct inode *dir, const char *__name,
  48            int len, struct inode **result);
  49 
  50 static int 
  51 ncp_create(struct inode *dir, const char *name, int len, int mode, 
  52            struct inode **result);
  53 
  54 static int 
  55 ncp_mkdir(struct inode *dir, const char *name, int len, int mode);
  56 
  57 static int 
  58 ncp_rmdir(struct inode *dir, const char *name, int len);
  59 
  60 static int
  61 ncp_unlink(struct inode *dir, const char *name, int len);
  62 
  63 static int
  64 ncp_rename(struct inode *old_dir, const char *old_name, int old_len, 
  65            struct inode *new_dir, const char *new_name, int new_len);
  66 
  67 static inline void
  68 str_upper(char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
  69 {
  70         while (*name)
  71         {
  72                 if (*name >= 'a' && *name <= 'z')
  73                 {
  74                         *name -= ('a' - 'A');
  75                 }
  76                 name++;
  77         }
  78 }
  79 
  80 static inline void
  81 str_lower(char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
  82 {
  83         while (*name)
  84         {
  85                 if (*name >= 'A' && *name <= 'Z')
  86                 {
  87                         *name += ('a' - 'A');
  88                 }
  89                 name ++;
  90         }
  91 }
  92 
  93 static struct file_operations ncp_dir_operations = {
  94         NULL,                   /* lseek - default */
  95         ncp_dir_read,           /* read - bad */
  96         NULL,                   /* write - bad */
  97         ncp_readdir,            /* readdir */
  98         NULL,                   /* select - default */
  99         ncp_ioctl,              /* ioctl */
 100         NULL,                   /* mmap */
 101         NULL,                   /* no special open code */
 102         NULL,                   /* no special release code */
 103         NULL                    /* fsync */
 104 };
 105 
 106 struct inode_operations ncp_dir_inode_operations = {
 107         &ncp_dir_operations,    /* default directory file ops */
 108         ncp_create,             /* create */
 109         ncp_lookup,             /* lookup */
 110         NULL,                   /* link */
 111         ncp_unlink,             /* unlink */
 112         NULL,                   /* symlink */
 113         ncp_mkdir,              /* mkdir */
 114         ncp_rmdir,              /* rmdir */
 115         NULL,                   /* mknod */
 116         ncp_rename,             /* rename */
 117         NULL,                   /* readlink */
 118         NULL,                   /* follow_link */
 119         NULL,                   /* bmap */
 120         NULL,                   /* truncate */
 121         NULL,                   /* permission */
 122         NULL                    /* smap */
 123 };
 124 
 125 
 126 /* Here we encapsulate the inode number handling that depends upon the
 127  * mount mode: When we mount a complete server, the memory address of
 128  * the npc_inode_info is used as an inode. When only a single volume
 129  * is mounted, then the DosDirNum is used as the inode number. As this
 130  * is unique for the complete volume, this should enable the NFS
 131  * exportability of a ncpfs-mounted volume.
 132  */
 133 
 134 static inline int
 135 ncp_single_volume(struct ncp_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 136 {
 137         return (server->m.mounted_vol[0] != '\0');
 138 }
 139 
 140 inline ino_t
 141 ncp_info_ino(struct ncp_server *server, struct ncp_inode_info *info)
     /* [previous][next][first][last][top][bottom][index][help] */
 142 {
 143         return ncp_single_volume(server)
 144                 ? info->finfo.i.DosDirNum : (ino_t)info;
 145 }
 146 
 147 static inline int
 148 ncp_is_server_root(struct inode *inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 149 {
 150         struct ncp_server *s = NCP_SERVER(inode);
 151 
 152         return (   (!ncp_single_volume(s))
 153                 && (inode->i_ino == ncp_info_ino(s, &(s->root))));
 154 }
 155 
 156 struct ncp_inode_info *
 157 ncp_find_inode(struct inode *inode)
     /* [previous][next][first][last][top][bottom][index][help] */
 158 {
 159         struct ncp_server *server = NCP_SERVER(inode);
 160         struct ncp_inode_info *root = &(server->root);
 161         struct ncp_inode_info *this = root;
 162 
 163         ino_t ino = inode->i_ino;
 164 
 165         do
 166         {
 167                 if (ino == ncp_info_ino(server, this))
 168                 {
 169                         return this;
 170                 }
 171                 this = this->next;
 172         }
 173         while (this != root);
 174 
 175         return NULL;
 176 }
 177         
 178 
 179 
 180 static int 
 181 ncp_dir_read(struct inode *inode, struct file *filp, char *buf, int count)
     /* [previous][next][first][last][top][bottom][index][help] */
 182 {
 183         return -EISDIR;
 184 }
 185 
 186 /* In ncpfs, we have unique inodes across all mounted filesystems, for
 187    all inodes that are in memory. That's why it's enough to index the
 188    directory cache by the inode number. */
 189 
 190 static kdev_t             c_dev = 0;
 191 static unsigned long      c_ino = 0;
 192 static int                c_size;
 193 static int                c_seen_eof;
 194 static int                c_last_returned_index;
 195 static struct ncp_dirent* c_entry = NULL;
 196 
 197 static int
 198 ncp_readdir(struct inode *inode, struct file *filp,
     /* [previous][next][first][last][top][bottom][index][help] */
 199             void *dirent, filldir_t filldir)
 200 {
 201         int result, i = 0;
 202         int index = 0;
 203         struct ncp_dirent *entry = NULL;
 204         struct ncp_server *server = NCP_SERVER(inode);
 205         struct ncp_inode_info *dir = NCP_INOP(inode);
 206 
 207         DDPRINTK("ncp_readdir: filp->f_pos = %d\n", (int)filp->f_pos);
 208         DDPRINTK("ncp_readdir: inode->i_ino = %ld, c_ino = %ld\n",
 209                  inode->i_ino, c_ino);
 210 
 211         if (!inode || !S_ISDIR(inode->i_mode))
 212         {
 213                 printk("ncp_readdir: inode is NULL or not a directory\n");
 214                 return -EBADF;
 215         }
 216 
 217         if (!ncp_conn_valid(server))
 218         {
 219                 return -EIO;
 220         }
 221 
 222         if (c_entry == NULL) 
 223         {
 224                 i = sizeof (struct ncp_dirent) * NCP_READDIR_CACHE_SIZE;
 225                 c_entry = (struct ncp_dirent *) ncp_kmalloc(i, GFP_KERNEL);
 226                 if (c_entry == NULL)
 227                 {
 228                         printk("ncp_readdir: no MEMORY for cache\n");
 229                         return -ENOMEM;
 230                 }
 231         }
 232 
 233         if (filp->f_pos == 0)
 234         {
 235                 ncp_invalid_dir_cache(inode);
 236                 if (filldir(dirent,".",1, filp->f_pos,
 237                             ncp_info_ino(server, dir)) < 0)
 238                 {
 239                         return 0;
 240                 }
 241                 filp->f_pos += 1;
 242         }
 243 
 244         if (filp->f_pos == 1)
 245         {
 246                 if (filldir(dirent,"..",2, filp->f_pos,
 247                             ncp_info_ino(server, dir->dir)) < 0)
 248                 {
 249                         return 0;
 250                 }
 251                 filp->f_pos += 1;
 252         }
 253 
 254         if ((inode->i_dev == c_dev) && (inode->i_ino == c_ino))
 255         {
 256                 for (i = 0; i < c_size; i++)
 257                 {
 258                         if (filp->f_pos == c_entry[i].f_pos)
 259                         {
 260                                 entry = &c_entry[i];
 261                                 c_last_returned_index = i;
 262                                 index = i;
 263                                 break;
 264                         }
 265                 }
 266                 if ((entry == NULL) && c_seen_eof)
 267                 {
 268                         return 0;
 269                 }
 270         }
 271 
 272         if (entry == NULL)
 273         {
 274                 DDPRINTK("ncp_readdir: Not found in cache.\n");
 275 
 276                 if (ncp_is_server_root(inode))
 277                 {
 278                         result = ncp_read_volume_list(server, filp->f_pos,
 279                                                       NCP_READDIR_CACHE_SIZE);
 280                         DPRINTK("ncp_read_volume_list returned %d\n", result);
 281 
 282                 }
 283                 else
 284                 {
 285                         result = ncp_do_readdir(server, inode, filp->f_pos,
 286                                                 NCP_READDIR_CACHE_SIZE,
 287                                                 c_entry);
 288                         DPRINTK("ncp_readdir returned %d\n", result);
 289                 }
 290 
 291                 if (result < 0)
 292                 {
 293                         c_dev = 0;
 294                         c_ino = 0;
 295                         return result;
 296                 }
 297 
 298                 if (result > 0)
 299                 {
 300                         c_seen_eof = (result < NCP_READDIR_CACHE_SIZE);
 301                         c_dev  = inode->i_dev;
 302                         c_ino  = inode->i_ino;
 303                         c_size = result;
 304                         entry = c_entry;
 305                         c_last_returned_index = 0;
 306                         index = 0;
 307 
 308                         for (i = 0; i < c_size; i++)
 309                         {
 310                                 str_lower(c_entry[i].i.entryName);
 311                         }
 312                 }
 313         }
 314 
 315         if (entry == NULL)
 316         {
 317                 /* Nothing found, even from a ncp call */
 318                 return 0;
 319         }
 320 
 321         while (index < c_size)
 322         {
 323                 /* We found it.  For getwd(), we have to return the
 324                    correct inode in d_ino if the inode is currently in
 325                    use. Otherwise the inode number does not
 326                    matter. (You can argue a lot about this..) */
 327 
 328                 ino_t ino;
 329 
 330                 if (ncp_single_volume(server))
 331                 {
 332                         ino = (ino_t)(entry->i.DosDirNum);
 333                 }
 334                 else
 335                 {
 336                         struct ncp_inode_info *ino_info;
 337                         ino_info = ncp_find_dir_inode(inode,
 338                                                       entry->i.entryName);
 339 
 340                         /* Some programs seem to be confused about a
 341                          * zero inode number, so we set it to one.
 342                          * Thanks to Gordon Chaffee for this one. */
 343                         if (ino_info == NULL)
 344                         {
 345                                 ino_info = (struct ncp_inode_info *) 1;
 346                         }
 347                         ino = (ino_t)(ino_info);
 348                 }
 349 
 350                 DDPRINTK("ncp_readdir: entry->path= %s\n", entry->i.entryName);
 351                 DDPRINTK("ncp_readdir: entry->f_pos = %ld\n", entry->f_pos);
 352 
 353                 if (filldir(dirent, entry->i.entryName, entry->i.nameLen,
 354                             entry->f_pos, ino) < 0)
 355                 {
 356                         break;
 357                 }
 358 
 359                 if (   (inode->i_dev != c_dev)
 360                     || (inode->i_ino != c_ino)
 361                     || (entry->f_pos != filp->f_pos))
 362                 {
 363                         /* Someone has destroyed the cache while we slept
 364                            in filldir */
 365                         break;
 366                 }
 367                 filp->f_pos += 1;
 368                 index += 1;
 369                 entry += 1;
 370         }
 371         return 0;
 372 }
 373 
 374 static int
 375 ncp_read_volume_list(struct ncp_server *server, int fpos, int cache_size)
     /* [previous][next][first][last][top][bottom][index][help] */
 376 {
 377         struct ncp_dirent *entry = c_entry;
 378 
 379         int total_count = 2;
 380         int i;
 381 
 382 #if 1
 383         if (fpos < 2)
 384         {
 385                 printk("OOPS, we expect fpos >= 2");
 386                 fpos = 2;
 387         }
 388 #endif
 389 
 390         for (i=0; i<NCP_NUMBER_OF_VOLUMES; i++)
 391         {
 392                 struct ncp_volume_info info;
 393 
 394                 if (ncp_get_volume_info_with_number(server, i, &info) != 0)
 395                 {
 396                         return total_count;
 397                 }
 398 
 399                 if (strlen(info.volume_name) > 0)
 400                 {
 401                         if (total_count < fpos)
 402                         {
 403                                 DPRINTK("ncp_read_volumes: skipped vol: %s\n",
 404                                         info.volume_name);
 405                         }
 406                         else if (total_count >= fpos + cache_size)
 407                         {
 408                                 return (total_count - fpos);
 409                         }
 410                         else
 411                         {
 412                                 DPRINTK("ncp_read_volumes: found vol: %s\n",
 413                                         info.volume_name);
 414 
 415                                 if (ncp_lookup_volume(server,
 416                                                       info.volume_name,
 417                                                       &(entry->i)) != 0)
 418                                 {
 419                                         DPRINTK("ncpfs: could not lookup vol "
 420                                                 "%s\n", info.volume_name);
 421                                         continue;
 422                                 }
 423 
 424                                 entry->f_pos = total_count;
 425                                 entry += 1;
 426                         }
 427                         total_count += 1;
 428                 }
 429         }
 430         return (total_count - fpos);
 431 }
 432 
 433 static int
 434 ncp_do_readdir(struct ncp_server *server, struct inode *dir, int fpos,
     /* [previous][next][first][last][top][bottom][index][help] */
 435                int cache_size, struct ncp_dirent *entry)
 436 {
 437         static struct nw_search_sequence seq;
 438         static struct inode *last_dir;
 439         static int total_count;
 440 
 441 #if 1
 442         if (fpos < 2)
 443         {
 444                 printk("OOPS, we expect fpos >= 2");
 445                 fpos = 2;
 446         }
 447 #endif
 448         DPRINTK("ncp_do_readdir: fpos = %d\n", fpos);
 449 
 450         if (fpos == 2)
 451         {
 452                 last_dir = NULL;
 453                 total_count = 2;
 454         }
 455 
 456         if ((fpos != total_count) || (dir != last_dir))
 457         {
 458                 total_count = 2;
 459                 last_dir = dir;
 460 
 461                 DPRINTK("ncp_do_readdir: re-used seq for %s\n",
 462                         NCP_ISTRUCT(dir)->entryName);
 463 
 464                 if (ncp_initialize_search(server, NCP_ISTRUCT(dir), &seq)!=0)
 465                 {
 466                         DPRINTK("ncp_init_search failed\n");
 467                         return total_count - fpos;
 468                 }
 469         }
 470 
 471         while (total_count < fpos + cache_size)
 472         {
 473                 if (ncp_search_for_file_or_subdir(server, &seq,
 474                                                   &(entry->i)) != 0)
 475                 {
 476                         return total_count - fpos;
 477                 }
 478 
 479                 if (total_count < fpos)
 480                 {
 481                         DPRINTK("ncp_do_readdir: skipped file: %s\n",
 482                                 entry->i.entryName);
 483                 }
 484                 else
 485                 {
 486                         DDPRINTK("ncp_do_r: file: %s, f_pos=%d,total_count=%d",
 487                                  entry->i.entryName, fpos, total_count);
 488                         entry->s = seq;
 489                         entry->f_pos = total_count;
 490                         entry += 1;
 491                 }
 492                 total_count += 1;
 493         }
 494         return (total_count - fpos);
 495 }
 496 
 497 void
 498 ncp_init_dir_cache(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 499 {
 500         c_dev   = 0;
 501         c_ino   = 0;
 502         c_entry = NULL;
 503 }
 504 
 505 void
 506 ncp_invalid_dir_cache(struct inode *ino)
     /* [previous][next][first][last][top][bottom][index][help] */
 507 {
 508         if ((ino->i_dev == c_dev) && (ino->i_ino == c_ino))
 509         {
 510                 c_dev = 0;
 511                 c_ino = 0;
 512                 c_seen_eof = 0;
 513         }
 514 }
 515 
 516 void
 517 ncp_free_dir_cache(void)
     /* [previous][next][first][last][top][bottom][index][help] */
 518 {
 519         DPRINTK("ncp_free_dir_cache: enter\n");
 520         
 521         if (c_entry == NULL)
 522         {
 523                 return;
 524         }
 525 
 526         ncp_kfree_s(c_entry,
 527                     sizeof(struct ncp_dirent) * NCP_READDIR_CACHE_SIZE);
 528         c_entry = NULL;
 529 
 530         DPRINTK("ncp_free_dir_cache: exit\n");
 531 }
 532 
 533 
 534 static struct inode *
 535 ncp_iget(struct inode *dir, struct nw_file_info *finfo)
     /* [previous][next][first][last][top][bottom][index][help] */
 536 {
 537         struct inode *inode;
 538         struct ncp_inode_info *new_inode_info;
 539         struct ncp_inode_info *root;
 540 
 541         if (dir == NULL)
 542         {
 543                 printk("ncp_iget: dir is NULL\n");
 544                 return NULL;
 545         }
 546 
 547         if (finfo == NULL)
 548         {
 549                 printk("ncp_iget: finfo is NULL\n");
 550                 return NULL;
 551         }
 552 
 553         new_inode_info = ncp_kmalloc(sizeof(struct ncp_inode_info),
 554                                      GFP_KERNEL);
 555 
 556         if (new_inode_info == NULL)
 557         {
 558                 printk("ncp_iget: could not alloc mem for %s\n",
 559                        finfo->i.entryName);
 560                 return NULL;
 561         }
 562 
 563         new_inode_info->state = NCP_INODE_LOOKED_UP;
 564         new_inode_info->nused = 0;
 565         new_inode_info->dir   = NCP_INOP(dir);
 566         new_inode_info->finfo = *finfo;
 567 
 568         NCP_INOP(dir)->nused += 1;
 569 
 570         /* We have to link the new inode_info into the doubly linked
 571            list of inode_infos to make a complete linear search
 572            possible. */
 573 
 574         root = &(NCP_SERVER(dir)->root);
 575 
 576         new_inode_info->prev = root;
 577         new_inode_info->next = root->next;
 578         root->next->prev = new_inode_info;
 579         root->next = new_inode_info;
 580         
 581         if (!(inode = iget(dir->i_sb, ncp_info_ino(NCP_SERVER(dir),
 582                                                    new_inode_info))))
 583         {
 584                 printk("ncp_iget: iget failed!");
 585                 return NULL;
 586         }
 587 
 588         return inode;
 589 }
 590 
 591 void
 592 ncp_free_inode_info(struct ncp_inode_info *i)
     /* [previous][next][first][last][top][bottom][index][help] */
 593 {
 594         if (i == NULL)
 595         {
 596                 printk("ncp_free_inode: i == NULL\n");
 597                 return;
 598         }
 599 
 600         i->state = NCP_INODE_CACHED;
 601         while ((i->nused == 0) && (i->state == NCP_INODE_CACHED))
 602         {
 603                 struct ncp_inode_info *dir = i->dir;
 604 
 605                 i->next->prev = i->prev;
 606                 i->prev->next = i->next;
 607 
 608                 DDPRINTK("ncp_free_inode_info: freeing %s\n",
 609                          i->finfo.i.entryName);
 610 
 611                 ncp_kfree_s(i, sizeof(struct ncp_inode_info));
 612 
 613                 if (dir == i) return;
 614 
 615                 (dir->nused)--;
 616                 i = dir;
 617         }
 618 }
 619         
 620 void
 621 ncp_init_root(struct ncp_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 622 {
 623         struct ncp_inode_info *root = &(server->root);
 624         struct nw_info_struct *i = &(root->finfo.i);
 625         unsigned short dummy;
 626 
 627         DPRINTK("ncp_init_root: server %s\n", server->m.server_name);
 628         DPRINTK("ncp_init_root: i = %x\n", (int)i);
 629 
 630         root->finfo.opened = 0;
 631         i->attributes  = aDIR;
 632         i->dataStreamSize = 1024;
 633         i->DosDirNum = 0;
 634         i->volNumber = NCP_NUMBER_OF_VOLUMES+1; /* illegal volnum */
 635         ncp_date_unix2dos(0, &(i->creationTime), &(i->creationDate));
 636         ncp_date_unix2dos(0, &(i->modifyTime), &(i->modifyDate));
 637         ncp_date_unix2dos(0, &dummy, &(i->lastAccessDate));
 638         i->nameLen = 0;
 639         i->entryName[0] = '\0';
 640 
 641         root->state = NCP_INODE_LOOKED_UP;
 642         root->nused = 1;
 643         root->dir   = root;
 644         root->next = root->prev = root;
 645         return;
 646 }
 647 
 648 int
 649 ncp_conn_logged_in(struct ncp_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 650 {
 651         if (server->m.mounted_vol[0] == '\0')
 652         {
 653                 return 0;
 654         }
 655 
 656         str_upper(server->m.mounted_vol);
 657         if (ncp_lookup_volume(server, server->m.mounted_vol,
 658                               &(server->root.finfo.i)) != 0)
 659         {
 660                 return -ENOENT;
 661         }
 662         str_lower(server->root.finfo.i.entryName);
 663 
 664         return 0;
 665 }
 666 
 667 void
 668 ncp_free_all_inodes(struct ncp_server *server)
     /* [previous][next][first][last][top][bottom][index][help] */
 669 {
 670         /* Here nothing should be to do. I do not know whether it's
 671            better to leave some memory allocated or be stuck in an
 672            endless loop */
 673 #if 1
 674         struct ncp_inode_info *root = &(server->root);
 675 
 676         if (root->next != root)
 677         {
 678                 printk("ncp_free_all_inodes: INODES LEFT!!!\n");
 679         }
 680 
 681         while (root->next != root)
 682         {
 683                 printk("ncp_free_all_inodes: freeing inode\n");
 684                 ncp_free_inode_info(root->next);
 685                 /* In case we have an endless loop.. */
 686                 schedule();
 687         }
 688 #endif        
 689         
 690         return;
 691 }
 692 
 693 /* We will search the inode that belongs to this name, currently by a
 694    complete linear search through the inodes belonging to this
 695    filesystem. This has to be fixed. */
 696 static struct ncp_inode_info *
 697 ncp_find_dir_inode(struct inode *dir, const char *name)
     /* [previous][next][first][last][top][bottom][index][help] */
 698 {
 699         struct ncp_server *server = NCP_SERVER(dir);
 700         struct nw_info_struct *dir_info = NCP_ISTRUCT(dir);
 701         struct ncp_inode_info *result = &(server->root);
 702 
 703         if (name == NULL)
 704         {
 705                 return NULL;
 706         }
 707 
 708         do
 709         {
 710                 if (   (result->dir->finfo.i.DosDirNum == dir_info->DosDirNum)
 711                     && (result->dir->finfo.i.volNumber == dir_info->volNumber)
 712                     && (strcmp(result->finfo.i.entryName, name) == 0)
 713                     /* The root dir is never looked up using this
 714                      * routine.  Without the following test a root
 715                      * directory 'sys' in a volume named 'sys' could
 716                      * never be looked up, because
 717                      * server->root->dir==server->root. */
 718                     && (result != &(server->root)))
 719                 {
 720                         return result;
 721                 }
 722                 result = result->next;
 723 
 724         }
 725         while (result != &(server->root));
 726 
 727         return NULL;
 728 }
 729 
 730 static int 
 731 ncp_lookup(struct inode *dir, const char *__name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 732            struct inode **result)
 733 {
 734         struct nw_file_info finfo;
 735         struct ncp_server *server;
 736         struct ncp_inode_info *result_info;
 737         int found_in_cache;
 738         char name[len+1];
 739 
 740         *result = NULL;
 741 
 742         if (!dir || !S_ISDIR(dir->i_mode))
 743         {
 744                 printk("ncp_lookup: inode is NULL or not a directory.\n");
 745                 iput(dir);
 746                 return -ENOENT;
 747         }
 748 
 749         server = NCP_SERVER(dir);
 750 
 751         if (!ncp_conn_valid(server))
 752         {
 753                 iput(dir);
 754                 return -EIO;
 755         }
 756 
 757         DPRINTK("ncp_lookup: %s, len %d\n", __name, len);
 758 
 759         /* Fast cheat for . */
 760         if (len == 0 || (len == 1 && __name[0] == '.'))
 761         {
 762                 *result = dir;
 763                 return 0;
 764         }
 765 
 766         /* ..and for .. */
 767         if (len == 2 && __name[0] == '.' && __name[1] == '.')
 768         {
 769                 struct ncp_inode_info *parent = NCP_INOP(dir)->dir;
 770 
 771                 if (parent->state == NCP_INODE_CACHED)
 772                 {
 773                         parent->state = NCP_INODE_LOOKED_UP;
 774                 }
 775 
 776                 *result = iget(dir->i_sb, ncp_info_ino(server, parent));
 777                 iput(dir);
 778                 if (*result == 0)
 779                 {
 780                         return -EACCES;
 781                 }
 782                 else
 783                 {
 784                         return 0;
 785                 }
 786         }
 787 
 788         memcpy(name, __name, len);
 789         name[len] = 0;
 790         result_info = ncp_find_dir_inode(dir, name);
 791 
 792         if (result_info != 0)
 793         {
 794                 if (result_info->state == NCP_INODE_CACHED)
 795                 {
 796                         result_info->state = NCP_INODE_LOOKED_UP;
 797                 }
 798 
 799                 /* Here we convert the inode_info address into an
 800                    inode number */
 801 
 802                 *result = iget(dir->i_sb, ncp_info_ino(server, result_info));
 803                 iput(dir);
 804 
 805                 if (*result == NULL)
 806                 {
 807                         return -EACCES;
 808                 }
 809 
 810                 return 0;
 811         }
 812 
 813         /* If the file is in the dir cache, we do not have to ask the
 814            server. */
 815 
 816         found_in_cache = 0;
 817 
 818         if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
 819         {
 820                 int first = c_last_returned_index;
 821                 int i;
 822 
 823                 i = first;
 824                 do
 825                 {
 826                         DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
 827                                  i, c_entry[i].i.entryName);
 828 
 829                         if (strcmp(c_entry[i].i.entryName, name) == 0)
 830                         {
 831                                 DPRINTK("ncp_lookup: found in cache!\n");
 832                                 finfo.i = c_entry[i].i;
 833                                 found_in_cache = 1;
 834                                 break;
 835                         }
 836                         i = (i + 1) % c_size;
 837                 }
 838                 while (i != first);
 839         }
 840 
 841         if (found_in_cache == 0)
 842         {
 843                 int res;
 844                 str_upper(name);
 845 
 846                 DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
 847                          NCP_ISTRUCT(dir)->entryName, name);
 848 
 849                 if (ncp_is_server_root(dir))
 850                 {
 851                         res = ncp_lookup_volume(server, name, &(finfo.i));
 852                 }
 853                 else
 854                 {
 855                         res = ncp_obtain_info(server,
 856                                               NCP_ISTRUCT(dir)->volNumber,
 857                                               NCP_ISTRUCT(dir)->DosDirNum,
 858                                               name, &(finfo.i));
 859                 }
 860                 if (res != 0)
 861                 {
 862                         iput(dir);
 863                         return -ENOENT;
 864                 }
 865         }
 866 
 867         finfo.opened = 0;
 868         str_lower(finfo.i.entryName);
 869 
 870         if (!(*result = ncp_iget(dir, &finfo)))
 871         {
 872                 iput(dir);
 873                 return -EACCES;
 874         }
 875 
 876         iput(dir);
 877         return 0;
 878 }
 879 
 880 static int 
 881 ncp_create(struct inode *dir, const char *name, int len, int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
 882            struct inode **result)
 883 {
 884         struct nw_file_info finfo;
 885         __u8 _name[len+1];
 886 
 887         *result = NULL;
 888 
 889         if (!dir || !S_ISDIR(dir->i_mode))
 890         {
 891                 printk("ncp_create: inode is NULL or not a directory\n");
 892                 iput(dir);
 893                 return -ENOENT;
 894         }
 895         if (!ncp_conn_valid(NCP_SERVER(dir)))
 896         {
 897                 iput(dir);
 898                 return -EIO;
 899         }
 900 
 901         strncpy(_name, name, len);
 902         _name[len] = '\0';
 903         str_upper(_name);
 904 
 905         if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
 906                                            NCP_ISTRUCT(dir), _name,
 907                                            OC_MODE_CREATE|OC_MODE_OPEN|
 908                                            OC_MODE_REPLACE,
 909                                            0, AR_READ|AR_WRITE,
 910                                            &finfo) != 0)
 911         {
 912                 iput(dir);
 913                 return -EACCES;
 914         }
 915 
 916         ncp_invalid_dir_cache(dir);
 917 
 918         str_lower(finfo.i.entryName);
 919         finfo.access = O_RDWR;
 920 
 921         if (!(*result = ncp_iget(dir, &finfo)) < 0)
 922         {
 923                 ncp_close_file(NCP_SERVER(dir), finfo.file_handle);
 924                 iput(dir);
 925                 return -EINVAL;
 926         }
 927 
 928         iput(dir);
 929         return 0;       
 930 }
 931 
 932 static int
 933 ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 934 {
 935         int error;
 936         struct nw_file_info new_dir;
 937         __u8 _name[len+1];
 938 
 939         if (   (name[0] == '.')
 940             && (   (len == 1)
 941                 || (   (len == 2)
 942                     && (name[1] == '.'))))
 943         {
 944                 return -EEXIST;
 945         }
 946 
 947         strncpy(_name, name, len);
 948         _name[len] = '\0';
 949         str_upper(_name);
 950 
 951         if (!dir || !S_ISDIR(dir->i_mode))
 952         {
 953                 printk("ncp_mkdir: inode is NULL or not a directory\n");
 954                 iput(dir);
 955                 return -ENOENT;
 956         }
 957         if (!ncp_conn_valid(NCP_SERVER(dir)))
 958         {
 959                 iput(dir);
 960                 return -EIO;
 961         }
 962 
 963         if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
 964                                            NCP_ISTRUCT(dir), _name,
 965                                            OC_MODE_CREATE, aDIR, 0xffff,
 966                                            &new_dir) != 0)
 967         {
 968                 error = -EACCES;
 969         }
 970         else
 971         {
 972                 error = 0;
 973                 ncp_invalid_dir_cache(dir);
 974         }
 975 
 976         iput(dir);
 977         return error;
 978 }
 979 
 980 static int
 981 ncp_rmdir(struct inode *dir, const char *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 982 {
 983         int error;
 984         __u8 _name[len+1];
 985 
 986         if (!dir || !S_ISDIR(dir->i_mode))
 987         {
 988                 printk("ncp_rmdir: inode is NULL or not a directory\n");
 989                 iput(dir);
 990                 return -ENOENT;
 991         }
 992         if (!ncp_conn_valid(NCP_SERVER(dir)))
 993         {
 994                 iput(dir);
 995                 return -EIO;
 996         }
 997         if (ncp_find_dir_inode(dir, name) != NULL)
 998         {
 999                 iput(dir);
1000                 error = -EBUSY;
1001         }
1002         else
1003         {
1004 
1005                 strncpy(_name, name, len);
1006                 _name[len] = '\0';
1007                 str_upper(_name);
1008 
1009                 if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
1010                                                     NCP_ISTRUCT(dir),
1011                                                     _name)) == 0)
1012                 {
1013                         ncp_invalid_dir_cache(dir);
1014                 }
1015                 else
1016                 {
1017                         error = -EACCES;
1018                 }
1019         }
1020         iput(dir);
1021         return error;
1022 }
1023 
1024 static int
1025 ncp_unlink(struct inode *dir, const char *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1026 {
1027         int error;
1028         __u8 _name[len+1];
1029 
1030         if (!dir || !S_ISDIR(dir->i_mode))
1031         {
1032                 printk("ncp_unlink: inode is NULL or not a directory\n");
1033                 iput(dir);
1034                 return -ENOENT;
1035         }
1036         if (!ncp_conn_valid(NCP_SERVER(dir)))
1037         {
1038                 iput(dir);
1039                 return -EIO;
1040         }
1041         if (ncp_find_dir_inode(dir, name) != NULL)
1042         {
1043                 iput(dir);
1044                 error = -EBUSY;
1045         }
1046         else
1047         {
1048                 strncpy(_name, name, len);
1049                 _name[len] = '\0';
1050                 str_upper(_name);
1051 
1052                 if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
1053                                                     NCP_ISTRUCT(dir),
1054                                                     _name)) == 0)
1055                 {
1056                         ncp_invalid_dir_cache(dir);
1057                 }
1058                 else
1059                 {
1060                         error = -EACCES;
1061                 }
1062         }
1063         iput(dir);
1064         return error;
1065 }
1066 
1067 static int
1068 ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
1069            struct inode *new_dir, const char *new_name, int new_len)
1070 {
1071         int res;
1072         char _old_name[old_len+1];
1073         char _new_name[new_len+1];
1074 
1075         if (!old_dir || !S_ISDIR(old_dir->i_mode))
1076         {
1077                 printk("ncp_rename: old inode is NULL or not a directory\n");
1078                 res = -ENOENT;
1079                 goto finished;
1080         }
1081 
1082         if (!ncp_conn_valid(NCP_SERVER(old_dir)))
1083         {
1084                 res = -EIO;
1085                 goto finished;
1086         }
1087 
1088         if (!new_dir || !S_ISDIR(new_dir->i_mode))
1089         {
1090                 printk("ncp_rename: new inode is NULL or not a directory\n");
1091                 res = -ENOENT;
1092                 goto finished;
1093         }
1094 
1095         if (   (ncp_find_dir_inode(old_dir, old_name) != NULL)
1096             || (ncp_find_dir_inode(new_dir, new_name) != NULL))
1097         {
1098                 res = -EBUSY;
1099                 goto finished;
1100         }
1101 
1102         strncpy(_old_name, old_name, old_len);
1103         _old_name[old_len] = '\0';
1104         str_upper(_old_name);
1105 
1106         strncpy(_new_name, new_name, new_len);
1107         _new_name[new_len] = '\0';
1108         str_upper(_new_name);
1109 
1110         res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
1111                                             NCP_ISTRUCT(old_dir), _old_name,
1112                                             NCP_ISTRUCT(new_dir), _new_name);
1113 
1114         if (res == 0)
1115         {
1116                 ncp_invalid_dir_cache(old_dir);
1117                 ncp_invalid_dir_cache(new_dir);
1118         }
1119         else
1120         {
1121                 res = -EACCES;
1122         }
1123         
1124  finished:
1125         iput(old_dir); 
1126         iput(new_dir);
1127         return res;
1128 }
1129 
1130 /* The following routines are taken directly from msdos-fs */
1131 
1132 /* Linear day numbers of the respective 1sts in non-leap years. */
1133 
1134 static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
1135                   /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
1136 
1137 
1138 extern struct timezone sys_tz;
1139 
1140 static int
1141 utc2local(int time)
     /* [previous][next][first][last][top][bottom][index][help] */
1142 {
1143         return time - sys_tz.tz_minuteswest*60;
1144 }
1145 
1146 static int
1147 local2utc(int time)
     /* [previous][next][first][last][top][bottom][index][help] */
1148 {
1149         return time + sys_tz.tz_minuteswest*60;
1150 }
1151 
1152 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1153 
1154 int
1155 ncp_date_dos2unix(unsigned short time,unsigned short date)
     /* [previous][next][first][last][top][bottom][index][help] */
1156 {
1157         int month,year,secs;
1158 
1159         month = ((date >> 5) & 15)-1;
1160         year = date >> 9;
1161         secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
1162             ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
1163             month < 2 ? 1 : 0)+3653);
1164                         /* days since 1.1.70 plus 80's leap day */
1165         return local2utc(secs);
1166 }
1167 
1168 
1169 /* Convert linear UNIX date to a MS-DOS time/date pair. */
1170 void
1171 ncp_date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
     /* [previous][next][first][last][top][bottom][index][help] */
1172 {
1173         int day,year,nl_day,month;
1174 
1175         unix_date = utc2local(unix_date);
1176         *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
1177             (((unix_date/3600) % 24) << 11);
1178         day = unix_date/86400-3652;
1179         year = day/365;
1180         if ((year+3)/4+365*year > day) year--;
1181         day -= (year+3)/4+365*year;
1182         if (day == 59 && !(year & 3)) {
1183                 nl_day = day;
1184                 month = 2;
1185         }
1186         else {
1187                 nl_day = (year & 3) || day <= 59 ? day : day-1;
1188                 for (month = 0; month < 12; month++)
1189                         if (day_n[month] > nl_day) break;
1190         }
1191         *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
1192 }

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