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                                         printk("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                 {
 714                         return result;
 715                 }
 716                 result = result->next;
 717 
 718         }
 719         while (result != &(server->root));
 720 
 721         return NULL;
 722 }
 723 
 724 static int 
 725 ncp_lookup(struct inode *dir, const char *__name, int len,
     /* [previous][next][first][last][top][bottom][index][help] */
 726            struct inode **result)
 727 {
 728         struct nw_file_info finfo;
 729         struct ncp_server *server;
 730         struct ncp_inode_info *result_info;
 731         int found_in_cache;
 732         char name[len+1];
 733 
 734         *result = NULL;
 735 
 736         if (!dir || !S_ISDIR(dir->i_mode))
 737         {
 738                 printk("ncp_lookup: inode is NULL or not a directory.\n");
 739                 iput(dir);
 740                 return -ENOENT;
 741         }
 742 
 743         server = NCP_SERVER(dir);
 744 
 745         if (!ncp_conn_valid(server))
 746         {
 747                 iput(dir);
 748                 return -EIO;
 749         }
 750 
 751         DPRINTK("ncp_lookup: %s, len %d\n", __name, len);
 752 
 753         /* Fast cheat for . */
 754         if (len == 0 || (len == 1 && __name[0] == '.'))
 755         {
 756                 *result = dir;
 757                 return 0;
 758         }
 759 
 760         /* ..and for .. */
 761         if (len == 2 && __name[0] == '.' && __name[1] == '.')
 762         {
 763                 struct ncp_inode_info *parent = NCP_INOP(dir)->dir;
 764 
 765                 if (parent->state == NCP_INODE_CACHED)
 766                 {
 767                         parent->state = NCP_INODE_LOOKED_UP;
 768                 }
 769 
 770                 *result = iget(dir->i_sb, ncp_info_ino(server, parent));
 771                 iput(dir);
 772                 if (*result == 0)
 773                 {
 774                         return -EACCES;
 775                 }
 776                 else
 777                 {
 778                         return 0;
 779                 }
 780         }
 781 
 782         memcpy(name, __name, len);
 783         name[len] = 0;
 784         result_info = ncp_find_dir_inode(dir, name);
 785 
 786         if (result_info != 0)
 787         {
 788                 if (result_info->state == NCP_INODE_CACHED)
 789                 {
 790                         result_info->state = NCP_INODE_LOOKED_UP;
 791                 }
 792 
 793                 /* Here we convert the inode_info address into an
 794                    inode number */
 795 
 796                 *result = iget(dir->i_sb, ncp_info_ino(server, result_info));
 797                 iput(dir);
 798 
 799                 if (*result == NULL)
 800                 {
 801                         return -EACCES;
 802                 }
 803 
 804                 return 0;
 805         }
 806 
 807         /* If the file is in the dir cache, we do not have to ask the
 808            server. */
 809 
 810         found_in_cache = 0;
 811 
 812         if ((dir->i_dev == c_dev) && (dir->i_ino == c_ino))
 813         {
 814                 int first = c_last_returned_index;
 815                 int i;
 816 
 817                 i = first;
 818                 do
 819                 {
 820                         DDPRINTK("ncp_lookup: trying index: %d, name: %s\n",
 821                                  i, c_entry[i].i.entryName);
 822 
 823                         if (strcmp(c_entry[i].i.entryName, name) == 0)
 824                         {
 825                                 DPRINTK("ncp_lookup: found in cache!\n");
 826                                 finfo.i = c_entry[i].i;
 827                                 found_in_cache = 1;
 828                                 break;
 829                         }
 830                         i = (i + 1) % c_size;
 831                 }
 832                 while (i != first);
 833         }
 834 
 835         if (found_in_cache == 0)
 836         {
 837                 int res;
 838                 str_upper(name);
 839 
 840                 DDPRINTK("ncp_lookup: do_lookup on %s/%s\n",
 841                          NCP_ISTRUCT(dir)->entryName, name);
 842 
 843                 if (ncp_is_server_root(dir))
 844                 {
 845                         res = ncp_lookup_volume(server, name, &(finfo.i));
 846                 }
 847                 else
 848                 {
 849                         res = ncp_obtain_info(server,
 850                                               NCP_ISTRUCT(dir)->volNumber,
 851                                               NCP_ISTRUCT(dir)->DosDirNum,
 852                                               name, &(finfo.i));
 853                 }
 854                 if (res != 0)
 855                 {
 856                         iput(dir);
 857                         return -ENOENT;
 858                 }
 859         }
 860 
 861         finfo.opened = 0;
 862         str_lower(finfo.i.entryName);
 863 
 864         if (!(*result = ncp_iget(dir, &finfo)))
 865         {
 866                 iput(dir);
 867                 return -EACCES;
 868         }
 869 
 870         iput(dir);
 871         return 0;
 872 }
 873 
 874 static int 
 875 ncp_create(struct inode *dir, const char *name, int len, int mode,
     /* [previous][next][first][last][top][bottom][index][help] */
 876            struct inode **result)
 877 {
 878         struct nw_file_info finfo;
 879         __u8 _name[len+1];
 880 
 881         *result = NULL;
 882 
 883         if (!dir || !S_ISDIR(dir->i_mode))
 884         {
 885                 printk("ncp_create: inode is NULL or not a directory\n");
 886                 iput(dir);
 887                 return -ENOENT;
 888         }
 889         if (!ncp_conn_valid(NCP_SERVER(dir)))
 890         {
 891                 iput(dir);
 892                 return -EIO;
 893         }
 894 
 895         strncpy(_name, name, len);
 896         _name[len] = '\0';
 897         str_upper(_name);
 898 
 899         if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
 900                                            NCP_ISTRUCT(dir), _name,
 901                                            OC_MODE_CREATE|OC_MODE_OPEN|
 902                                            OC_MODE_REPLACE,
 903                                            0, AR_READ|AR_WRITE,
 904                                            &finfo) != 0)
 905         {
 906                 iput(dir);
 907                 return -EACCES;
 908         }
 909 
 910         ncp_invalid_dir_cache(dir);
 911 
 912         str_lower(finfo.i.entryName);
 913         finfo.access = O_RDWR;
 914 
 915         if (!(*result = ncp_iget(dir, &finfo)) < 0)
 916         {
 917                 ncp_close_file(NCP_SERVER(dir), finfo.file_handle);
 918                 iput(dir);
 919                 return -EINVAL;
 920         }
 921 
 922         iput(dir);
 923         return 0;       
 924 }
 925 
 926 static int
 927 ncp_mkdir(struct inode *dir, const char *name, int len, int mode)
     /* [previous][next][first][last][top][bottom][index][help] */
 928 {
 929         int error;
 930         struct nw_file_info new_dir;
 931         __u8 _name[len+1];
 932 
 933         if (   (name[0] == '.')
 934             && (   (len == 1)
 935                 || (   (len == 2)
 936                     && (name[1] == '.'))))
 937         {
 938                 return -EEXIST;
 939         }
 940 
 941         strncpy(_name, name, len);
 942         _name[len] = '\0';
 943         str_upper(_name);
 944 
 945         if (!dir || !S_ISDIR(dir->i_mode))
 946         {
 947                 printk("ncp_mkdir: inode is NULL or not a directory\n");
 948                 iput(dir);
 949                 return -ENOENT;
 950         }
 951         if (!ncp_conn_valid(NCP_SERVER(dir)))
 952         {
 953                 iput(dir);
 954                 return -EIO;
 955         }
 956 
 957         if (ncp_open_create_file_or_subdir(NCP_SERVER(dir),
 958                                            NCP_ISTRUCT(dir), _name,
 959                                            OC_MODE_CREATE, aDIR, 0xffff,
 960                                            &new_dir) != 0)
 961         {
 962                 error = -EACCES;
 963         }
 964         else
 965         {
 966                 error = 0;
 967                 ncp_invalid_dir_cache(dir);
 968         }
 969 
 970         iput(dir);
 971         return error;
 972 }
 973 
 974 static int
 975 ncp_rmdir(struct inode *dir, const char *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
 976 {
 977         int error;
 978         __u8 _name[len+1];
 979 
 980         if (!dir || !S_ISDIR(dir->i_mode))
 981         {
 982                 printk("ncp_rmdir: inode is NULL or not a directory\n");
 983                 iput(dir);
 984                 return -ENOENT;
 985         }
 986         if (!ncp_conn_valid(NCP_SERVER(dir)))
 987         {
 988                 iput(dir);
 989                 return -EIO;
 990         }
 991         if (ncp_find_dir_inode(dir, name) != NULL)
 992         {
 993                 iput(dir);
 994                 error = -EBUSY;
 995         }
 996         else
 997         {
 998 
 999                 strncpy(_name, name, len);
1000                 _name[len] = '\0';
1001                 str_upper(_name);
1002 
1003                 if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
1004                                                     NCP_ISTRUCT(dir),
1005                                                     _name)) == 0)
1006                 {
1007                         ncp_invalid_dir_cache(dir);
1008                 }
1009                 else
1010                 {
1011                         error = -EACCES;
1012                 }
1013         }
1014         iput(dir);
1015         return error;
1016 }
1017 
1018 static int
1019 ncp_unlink(struct inode *dir, const char *name, int len)
     /* [previous][next][first][last][top][bottom][index][help] */
1020 {
1021         int error;
1022         __u8 _name[len+1];
1023 
1024         if (!dir || !S_ISDIR(dir->i_mode))
1025         {
1026                 printk("ncp_unlink: inode is NULL or not a directory\n");
1027                 iput(dir);
1028                 return -ENOENT;
1029         }
1030         if (!ncp_conn_valid(NCP_SERVER(dir)))
1031         {
1032                 iput(dir);
1033                 return -EIO;
1034         }
1035         if (ncp_find_dir_inode(dir, name) != NULL)
1036         {
1037                 iput(dir);
1038                 error = -EBUSY;
1039         }
1040         else
1041         {
1042                 strncpy(_name, name, len);
1043                 _name[len] = '\0';
1044                 str_upper(_name);
1045 
1046                 if ((error = ncp_del_file_or_subdir(NCP_SERVER(dir),
1047                                                     NCP_ISTRUCT(dir),
1048                                                     _name)) == 0)
1049                 {
1050                         ncp_invalid_dir_cache(dir);
1051                 }
1052                 else
1053                 {
1054                         error = -EACCES;
1055                 }
1056         }
1057         iput(dir);
1058         return error;
1059 }
1060 
1061 static int
1062 ncp_rename(struct inode *old_dir, const char *old_name, int old_len,
     /* [previous][next][first][last][top][bottom][index][help] */
1063            struct inode *new_dir, const char *new_name, int new_len)
1064 {
1065         int res;
1066         char _old_name[old_len+1];
1067         char _new_name[new_len+1];
1068 
1069         if (!old_dir || !S_ISDIR(old_dir->i_mode))
1070         {
1071                 printk("ncp_rename: old inode is NULL or not a directory\n");
1072                 res = -ENOENT;
1073                 goto finished;
1074         }
1075 
1076         if (!ncp_conn_valid(NCP_SERVER(old_dir)))
1077         {
1078                 res = -EIO;
1079                 goto finished;
1080         }
1081 
1082         if (!new_dir || !S_ISDIR(new_dir->i_mode))
1083         {
1084                 printk("ncp_rename: new inode is NULL or not a directory\n");
1085                 res = -ENOENT;
1086                 goto finished;
1087         }
1088 
1089         if (   (ncp_find_dir_inode(old_dir, old_name) != NULL)
1090             || (ncp_find_dir_inode(new_dir, new_name) != NULL))
1091         {
1092                 res = -EBUSY;
1093                 goto finished;
1094         }
1095 
1096         strncpy(_old_name, old_name, old_len);
1097         _old_name[old_len] = '\0';
1098         str_upper(_old_name);
1099 
1100         strncpy(_new_name, new_name, new_len);
1101         _new_name[new_len] = '\0';
1102         str_upper(_new_name);
1103 
1104         res = ncp_ren_or_mov_file_or_subdir(NCP_SERVER(old_dir),
1105                                             NCP_ISTRUCT(old_dir), _old_name,
1106                                             NCP_ISTRUCT(new_dir), _new_name);
1107 
1108         if (res == 0)
1109         {
1110                 ncp_invalid_dir_cache(old_dir);
1111                 ncp_invalid_dir_cache(new_dir);
1112         }
1113         else
1114         {
1115                 res = -EACCES;
1116         }
1117         
1118  finished:
1119         iput(old_dir); 
1120         iput(new_dir);
1121         return res;
1122 }
1123 
1124 /* The following routines are taken directly from msdos-fs */
1125 
1126 /* Linear day numbers of the respective 1sts in non-leap years. */
1127 
1128 static int day_n[] = { 0,31,59,90,120,151,181,212,243,273,304,334,0,0,0,0 };
1129                   /* JanFebMarApr May Jun Jul Aug Sep Oct Nov Dec */
1130 
1131 
1132 extern struct timezone sys_tz;
1133 
1134 static int
1135 utc2local(int time)
     /* [previous][next][first][last][top][bottom][index][help] */
1136 {
1137         return time - sys_tz.tz_minuteswest*60;
1138 }
1139 
1140 static int
1141 local2utc(int time)
     /* [previous][next][first][last][top][bottom][index][help] */
1142 {
1143         return time + sys_tz.tz_minuteswest*60;
1144 }
1145 
1146 /* Convert a MS-DOS time/date pair to a UNIX date (seconds since 1 1 70). */
1147 
1148 int
1149 ncp_date_dos2unix(unsigned short time,unsigned short date)
     /* [previous][next][first][last][top][bottom][index][help] */
1150 {
1151         int month,year,secs;
1152 
1153         month = ((date >> 5) & 15)-1;
1154         year = date >> 9;
1155         secs = (time & 31)*2+60*((time >> 5) & 63)+(time >> 11)*3600+86400*
1156             ((date & 31)-1+day_n[month]+(year/4)+year*365-((year & 3) == 0 &&
1157             month < 2 ? 1 : 0)+3653);
1158                         /* days since 1.1.70 plus 80's leap day */
1159         return local2utc(secs);
1160 }
1161 
1162 
1163 /* Convert linear UNIX date to a MS-DOS time/date pair. */
1164 void
1165 ncp_date_unix2dos(int unix_date,unsigned short *time, unsigned short *date)
     /* [previous][next][first][last][top][bottom][index][help] */
1166 {
1167         int day,year,nl_day,month;
1168 
1169         unix_date = utc2local(unix_date);
1170         *time = (unix_date % 60)/2+(((unix_date/60) % 60) << 5)+
1171             (((unix_date/3600) % 24) << 11);
1172         day = unix_date/86400-3652;
1173         year = day/365;
1174         if ((year+3)/4+365*year > day) year--;
1175         day -= (year+3)/4+365*year;
1176         if (day == 59 && !(year & 3)) {
1177                 nl_day = day;
1178                 month = 2;
1179         }
1180         else {
1181                 nl_day = (year & 3) || day <= 59 ? day : day-1;
1182                 for (month = 0; month < 12; month++)
1183                         if (day_n[month] > nl_day) break;
1184         }
1185         *date = nl_day-day_n[month-1]+1+(month << 5)+(year << 9);
1186 }

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