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

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