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_dir_read
  4. ncp_readdir
  5. ncp_read_volume_list
  6. ncp_do_readdir
  7. ncp_init_dir_cache
  8. ncp_invalid_dir_cache
  9. ncp_free_dir_cache
  10. ncp_iget
  11. ncp_free_inode_info
  12. ncp_init_root
  13. ncp_free_all_inodes
  14. ncp_find_inode
  15. ncp_lookup
  16. ncp_create
  17. ncp_mkdir
  18. ncp_rmdir
  19. ncp_unlink
  20. ncp_rename
  21. utc2local
  22. local2utc
  23. ncp_date_dos2unix
  24. ncp_date_unix2dos

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

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