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

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