root/source3/smbd/files.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. get_gen_count
  2. file_new
  3. file_close_conn
  4. file_close_pid
  5. file_init
  6. file_close_user
  7. file_walk_table
  8. file_dump_open_table
  9. file_find_fd
  10. file_find_dif
  11. file_find_fsp
  12. file_find_di_first
  13. file_find_di_next
  14. file_find_print
  15. file_find_subpath
  16. file_sync_all
  17. file_free
  18. file_fnum
  19. file_fsp
  20. dup_file_fsp

   1 /* 
   2    Unix SMB/CIFS implementation.
   3    Files[] structure handling
   4    Copyright (C) Andrew Tridgell 1998
   5    
   6    This program is free software; you can redistribute it and/or modify
   7    it under the terms of the GNU General Public License as published by
   8    the Free Software Foundation; either version 3 of the License, or
   9    (at your option) any later version.
  10    
  11    This program is distributed in the hope that it will be useful,
  12    but WITHOUT ANY WARRANTY; without even the implied warranty of
  13    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  14    GNU General Public License for more details.
  15    
  16    You should have received a copy of the GNU General Public License
  17    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  18 */
  19 
  20 #include "includes.h"
  21 #include "smbd/globals.h"
  22 
  23 #define VALID_FNUM(fnum)   (((fnum) >= 0) && ((fnum) < real_max_open_files))
  24 
  25 #define FILE_HANDLE_OFFSET 0x1000
  26 
  27 /****************************************************************************
  28  Return a unique number identifying this fsp over the life of this pid.
  29 ****************************************************************************/
  30 
  31 static unsigned long get_gen_count(void)
     /* [<][>][^][v][top][bottom][index][help] */
  32 {
  33         if ((++file_gen_counter) == 0)
  34                 return ++file_gen_counter;
  35         return file_gen_counter;
  36 }
  37 
  38 /****************************************************************************
  39  Find first available file slot.
  40 ****************************************************************************/
  41 
  42 NTSTATUS file_new(struct smb_request *req, connection_struct *conn,
     /* [<][>][^][v][top][bottom][index][help] */
  43                   files_struct **result)
  44 {
  45         int i;
  46         files_struct *fsp;
  47 
  48         /* we want to give out file handles differently on each new
  49            connection because of a common bug in MS clients where they try to
  50            reuse a file descriptor from an earlier smb connection. This code
  51            increases the chance that the errant client will get an error rather
  52            than causing corruption */
  53         if (first_file == 0) {
  54                 first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files;
  55         }
  56 
  57         /* TODO: Port the id-tree implementation from Samba4 */
  58 
  59         i = bitmap_find(file_bmap, first_file);
  60         if (i == -1) {
  61                 DEBUG(0,("ERROR! Out of file structures\n"));
  62                 /* TODO: We have to unconditionally return a DOS error here,
  63                  * W2k3 even returns ERRDOS/ERRnofids for ntcreate&x with
  64                  * NTSTATUS negotiated */
  65                 return NT_STATUS_TOO_MANY_OPENED_FILES;
  66         }
  67 
  68         fsp = SMB_MALLOC_P(files_struct);
  69         if (!fsp) {
  70                 return NT_STATUS_NO_MEMORY;
  71         }
  72 
  73         ZERO_STRUCTP(fsp);
  74 
  75         fsp->fh = SMB_MALLOC_P(struct fd_handle);
  76         if (!fsp->fh) {
  77                 SAFE_FREE(fsp);
  78                 return NT_STATUS_NO_MEMORY;
  79         }
  80 
  81         ZERO_STRUCTP(fsp->fh);
  82 
  83         fsp->fh->ref_count = 1;
  84         fsp->fh->fd = -1;
  85 
  86         fsp->conn = conn;
  87         fsp->fh->gen_id = get_gen_count();
  88         GetTimeOfDay(&fsp->open_time);
  89 
  90         first_file = (i+1) % real_max_open_files;
  91 
  92         bitmap_set(file_bmap, i);
  93         files_used++;
  94 
  95         fsp->fnum = i + FILE_HANDLE_OFFSET;
  96         SMB_ASSERT(fsp->fnum < 65536);
  97 
  98         string_set(&fsp->fsp_name,"");
  99         
 100         DLIST_ADD(Files, fsp);
 101 
 102         DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
 103                  i, fsp->fnum, files_used));
 104 
 105         if (req != NULL) {
 106                 req->chain_fsp = fsp;
 107         }
 108 
 109         /* A new fsp invalidates the positive and
 110           negative fsp_fi_cache as the new fsp is pushed
 111           at the start of the list and we search from
 112           a cache hit to the *end* of the list. */
 113 
 114         ZERO_STRUCT(fsp_fi_cache);
 115 
 116         conn->num_files_open++;
 117 
 118         *result = fsp;
 119         return NT_STATUS_OK;
 120 }
 121 
 122 /****************************************************************************
 123  Close all open files for a connection.
 124 ****************************************************************************/
 125 
 126 void file_close_conn(connection_struct *conn)
     /* [<][>][^][v][top][bottom][index][help] */
 127 {
 128         files_struct *fsp, *next;
 129         
 130         for (fsp=Files;fsp;fsp=next) {
 131                 next = fsp->next;
 132                 if (fsp->conn == conn) {
 133                         close_file(NULL, fsp, SHUTDOWN_CLOSE);
 134                 }
 135         }
 136 }
 137 
 138 /****************************************************************************
 139  Close all open files for a pid and a vuid.
 140 ****************************************************************************/
 141 
 142 void file_close_pid(uint16 smbpid, int vuid)
     /* [<][>][^][v][top][bottom][index][help] */
 143 {
 144         files_struct *fsp, *next;
 145         
 146         for (fsp=Files;fsp;fsp=next) {
 147                 next = fsp->next;
 148                 if ((fsp->file_pid == smbpid) && (fsp->vuid == vuid)) {
 149                         close_file(NULL, fsp, SHUTDOWN_CLOSE);
 150                 }
 151         }
 152 }
 153 
 154 /****************************************************************************
 155  Initialise file structures.
 156 ****************************************************************************/
 157 
 158 #define MAX_OPEN_FUDGEFACTOR 20
 159 
 160 void file_init(void)
     /* [<][>][^][v][top][bottom][index][help] */
 161 {
 162         int request_max_open_files = lp_max_open_files();
 163         int real_lim;
 164 
 165         /*
 166          * Set the max_open files to be the requested
 167          * max plus a fudgefactor to allow for the extra
 168          * fd's we need such as log files etc...
 169          */
 170         real_lim = set_maxfiles(request_max_open_files + MAX_OPEN_FUDGEFACTOR);
 171 
 172         real_max_open_files = real_lim - MAX_OPEN_FUDGEFACTOR;
 173 
 174         if (real_max_open_files + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536)
 175                 real_max_open_files = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
 176 
 177         if(real_max_open_files != request_max_open_files) {
 178                 DEBUG(1,("file_init: Information only: requested %d \
 179 open files, %d are available.\n", request_max_open_files, real_max_open_files));
 180         }
 181 
 182         SMB_ASSERT(real_max_open_files > 100);
 183 
 184         file_bmap = bitmap_allocate(real_max_open_files);
 185         
 186         if (!file_bmap) {
 187                 exit_server("out of memory in file_init");
 188         }
 189 }
 190 
 191 /****************************************************************************
 192  Close files open by a specified vuid.
 193 ****************************************************************************/
 194 
 195 void file_close_user(int vuid)
     /* [<][>][^][v][top][bottom][index][help] */
 196 {
 197         files_struct *fsp, *next;
 198 
 199         for (fsp=Files;fsp;fsp=next) {
 200                 next=fsp->next;
 201                 if (fsp->vuid == vuid) {
 202                         close_file(NULL, fsp, SHUTDOWN_CLOSE);
 203                 }
 204         }
 205 }
 206 
 207 /*
 208  * Walk the files table until "fn" returns non-NULL
 209  */
 210 
 211 struct files_struct *file_walk_table(
     /* [<][>][^][v][top][bottom][index][help] */
 212         struct files_struct *(*fn)(struct files_struct *fsp,
 213                                    void *private_data),
 214         void *private_data)
 215 {
 216         struct files_struct *fsp, *next;
 217 
 218         for (fsp = Files; fsp; fsp = next) {
 219                 struct files_struct *ret;
 220                 next = fsp->next;
 221                 ret = fn(fsp, private_data);
 222                 if (ret != NULL) {
 223                         return ret;
 224                 }
 225         }
 226         return NULL;
 227 }
 228 
 229 /****************************************************************************
 230  Debug to enumerate all open files in the smbd.
 231 ****************************************************************************/
 232 
 233 void file_dump_open_table(void)
     /* [<][>][^][v][top][bottom][index][help] */
 234 {
 235         int count=0;
 236         files_struct *fsp;
 237 
 238         for (fsp=Files;fsp;fsp=fsp->next,count++) {
 239                 DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, gen = %lu, fileid=%s\n",
 240                         count, fsp->fnum, fsp->fsp_name, fsp->fh->fd, (unsigned long)fsp->fh->gen_id,
 241                           file_id_string_tos(&fsp->file_id)));
 242         }
 243 }
 244 
 245 /****************************************************************************
 246  Find a fsp given a file descriptor.
 247 ****************************************************************************/
 248 
 249 files_struct *file_find_fd(int fd)
     /* [<][>][^][v][top][bottom][index][help] */
 250 {
 251         int count=0;
 252         files_struct *fsp;
 253 
 254         for (fsp=Files;fsp;fsp=fsp->next,count++) {
 255                 if (fsp->fh->fd == fd) {
 256                         if (count > 10) {
 257                                 DLIST_PROMOTE(Files, fsp);
 258                         }
 259                         return fsp;
 260                 }
 261         }
 262 
 263         return NULL;
 264 }
 265 
 266 /****************************************************************************
 267  Find a fsp given a device, inode and file_id.
 268 ****************************************************************************/
 269 
 270 files_struct *file_find_dif(struct file_id id, unsigned long gen_id)
     /* [<][>][^][v][top][bottom][index][help] */
 271 {
 272         int count=0;
 273         files_struct *fsp;
 274 
 275         for (fsp=Files;fsp;fsp=fsp->next,count++) {
 276                 /* We can have a fsp->fh->fd == -1 here as it could be a stat open. */
 277                 if (file_id_equal(&fsp->file_id, &id) &&
 278                     fsp->fh->gen_id == gen_id ) {
 279                         if (count > 10) {
 280                                 DLIST_PROMOTE(Files, fsp);
 281                         }
 282                         /* Paranoia check. */
 283                         if ((fsp->fh->fd == -1) &&
 284                             (fsp->oplock_type != NO_OPLOCK) &&
 285                             (fsp->oplock_type != FAKE_LEVEL_II_OPLOCK)) {
 286                                 DEBUG(0,("file_find_dif: file %s file_id = %s, gen = %u \
 287 oplock_type = %u is a stat open with oplock type !\n", fsp->fsp_name, 
 288                                          file_id_string_tos(&fsp->file_id),
 289                                          (unsigned int)fsp->fh->gen_id,
 290                                          (unsigned int)fsp->oplock_type ));
 291                                 smb_panic("file_find_dif");
 292                         }
 293                         return fsp;
 294                 }
 295         }
 296 
 297         return NULL;
 298 }
 299 
 300 /****************************************************************************
 301  Check if an fsp still exists.
 302 ****************************************************************************/
 303 
 304 files_struct *file_find_fsp(files_struct *orig_fsp)
     /* [<][>][^][v][top][bottom][index][help] */
 305 {
 306         files_struct *fsp;
 307 
 308         for (fsp=Files;fsp;fsp=fsp->next) {
 309                 if (fsp == orig_fsp)
 310                         return fsp;
 311         }
 312 
 313         return NULL;
 314 }
 315 
 316 /****************************************************************************
 317  Find the first fsp given a device and inode.
 318  We use a singleton cache here to speed up searching from getfilepathinfo
 319  calls.
 320 ****************************************************************************/
 321 
 322 files_struct *file_find_di_first(struct file_id id)
     /* [<][>][^][v][top][bottom][index][help] */
 323 {
 324         files_struct *fsp;
 325 
 326         if (file_id_equal(&fsp_fi_cache.id, &id)) {
 327                 /* Positive or negative cache hit. */
 328                 return fsp_fi_cache.fsp;
 329         }
 330 
 331         fsp_fi_cache.id = id;
 332 
 333         for (fsp=Files;fsp;fsp=fsp->next) {
 334                 if (file_id_equal(&fsp->file_id, &id)) {
 335                         /* Setup positive cache. */
 336                         fsp_fi_cache.fsp = fsp;
 337                         return fsp;
 338                 }
 339         }
 340 
 341         /* Setup negative cache. */
 342         fsp_fi_cache.fsp = NULL;
 343         return NULL;
 344 }
 345 
 346 /****************************************************************************
 347  Find the next fsp having the same device and inode.
 348 ****************************************************************************/
 349 
 350 files_struct *file_find_di_next(files_struct *start_fsp)
     /* [<][>][^][v][top][bottom][index][help] */
 351 {
 352         files_struct *fsp;
 353 
 354         for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
 355                 if (file_id_equal(&fsp->file_id, &start_fsp->file_id)) {
 356                         return fsp;
 357                 }
 358         }
 359 
 360         return NULL;
 361 }
 362 
 363 /****************************************************************************
 364  Find a fsp that is open for printing.
 365 ****************************************************************************/
 366 
 367 files_struct *file_find_print(void)
     /* [<][>][^][v][top][bottom][index][help] */
 368 {
 369         files_struct *fsp;
 370 
 371         for (fsp=Files;fsp;fsp=fsp->next) {
 372                 if (fsp->print_file) {
 373                         return fsp;
 374                 }
 375         } 
 376 
 377         return NULL;
 378 }
 379 
 380 /****************************************************************************
 381  Find any fsp open with a pathname below that of an already open path.
 382 ****************************************************************************/
 383 
 384 bool file_find_subpath(files_struct *dir_fsp)
     /* [<][>][^][v][top][bottom][index][help] */
 385 {
 386         files_struct *fsp;
 387         size_t dlen;
 388         char *d_fullname = talloc_asprintf(talloc_tos(),
 389                                         "%s/%s",
 390                                         dir_fsp->conn->connectpath,
 391                                         dir_fsp->fsp_name);
 392         if (!d_fullname) {
 393                 return false;
 394         }
 395 
 396         dlen = strlen(d_fullname);
 397 
 398         for (fsp=Files;fsp;fsp=fsp->next) {
 399                 char *d1_fullname;
 400 
 401                 if (fsp == dir_fsp) {
 402                         continue;
 403                 }
 404 
 405                 d1_fullname = talloc_asprintf(talloc_tos(),
 406                                         "%s/%s",
 407                                         fsp->conn->connectpath,
 408                                         fsp->fsp_name);
 409 
 410                 /*
 411                  * If the open file has a path that is a longer
 412                  * component, then it's a subpath.
 413                  */
 414                 if (strnequal(d_fullname, d1_fullname, dlen) &&
 415                                 (d1_fullname[dlen] == '/')) {
 416                         TALLOC_FREE(d1_fullname);
 417                         TALLOC_FREE(d_fullname);
 418                         return true;
 419                 }
 420                 TALLOC_FREE(d1_fullname);
 421         }
 422 
 423         TALLOC_FREE(d_fullname);
 424         return false;
 425 }
 426 
 427 /****************************************************************************
 428  Sync open files on a connection.
 429 ****************************************************************************/
 430 
 431 void file_sync_all(connection_struct *conn)
     /* [<][>][^][v][top][bottom][index][help] */
 432 {
 433         files_struct *fsp, *next;
 434 
 435         for (fsp=Files;fsp;fsp=next) {
 436                 next=fsp->next;
 437                 if ((conn == fsp->conn) && (fsp->fh->fd != -1)) {
 438                         sync_file(conn, fsp, True /* write through */);
 439                 }
 440         }
 441 }
 442 
 443 /****************************************************************************
 444  Free up a fsp.
 445 ****************************************************************************/
 446 
 447 void file_free(struct smb_request *req, files_struct *fsp)
     /* [<][>][^][v][top][bottom][index][help] */
 448 {
 449         DLIST_REMOVE(Files, fsp);
 450 
 451         string_free(&fsp->fsp_name);
 452 
 453         TALLOC_FREE(fsp->fake_file_handle);
 454 
 455         if (fsp->fh->ref_count == 1) {
 456                 SAFE_FREE(fsp->fh);
 457         } else {
 458                 fsp->fh->ref_count--;
 459         }
 460 
 461         if (fsp->notify) {
 462                 notify_remove(fsp->conn->notify_ctx, fsp);
 463                 TALLOC_FREE(fsp->notify);
 464         }
 465 
 466         /* Ensure this event will never fire. */
 467         TALLOC_FREE(fsp->oplock_timeout);
 468 
 469         /* Ensure this event will never fire. */
 470         TALLOC_FREE(fsp->update_write_time_event);
 471 
 472         bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
 473         files_used--;
 474 
 475         DEBUG(5,("freed files structure %d (%d used)\n",
 476                  fsp->fnum, files_used));
 477 
 478         fsp->conn->num_files_open--;
 479 
 480         if ((req != NULL) && (fsp == req->chain_fsp)) {
 481                 req->chain_fsp = NULL;
 482         }
 483 
 484         /* Closing a file can invalidate the positive cache. */
 485         if (fsp == fsp_fi_cache.fsp) {
 486                 ZERO_STRUCT(fsp_fi_cache);
 487         }
 488 
 489         /* Drop all remaining extensions. */
 490         while (fsp->vfs_extension) {
 491                 vfs_remove_fsp_extension(fsp->vfs_extension->owner, fsp);
 492         }
 493 
 494         /* this is paranoia, just in case someone tries to reuse the
 495            information */
 496         ZERO_STRUCTP(fsp);
 497 
 498         SAFE_FREE(fsp);
 499 }
 500 
 501 /****************************************************************************
 502  Get an fsp from a 16 bit fnum.
 503 ****************************************************************************/
 504 
 505 files_struct *file_fnum(uint16 fnum)
     /* [<][>][^][v][top][bottom][index][help] */
 506 {
 507         files_struct *fsp;
 508         int count=0;
 509 
 510         for (fsp=Files;fsp;fsp=fsp->next, count++) {
 511                 if (fsp->fnum == fnum) {
 512                         if (count > 10) {
 513                                 DLIST_PROMOTE(Files, fsp);
 514                         }
 515                         return fsp;
 516                 }
 517         }
 518         return NULL;
 519 }
 520 
 521 /****************************************************************************
 522  Get an fsp from a packet given the offset of a 16 bit fnum.
 523 ****************************************************************************/
 524 
 525 files_struct *file_fsp(struct smb_request *req, uint16 fid)
     /* [<][>][^][v][top][bottom][index][help] */
 526 {
 527         files_struct *fsp;
 528 
 529         if ((req != NULL) && (req->chain_fsp != NULL)) {
 530                 return req->chain_fsp;
 531         }
 532 
 533         fsp = file_fnum(fid);
 534         if ((fsp != NULL) && (req != NULL)) {
 535                 req->chain_fsp = fsp;
 536         }
 537         return fsp;
 538 }
 539 
 540 /****************************************************************************
 541  Duplicate the file handle part for a DOS or FCB open.
 542 ****************************************************************************/
 543 
 544 void dup_file_fsp(struct smb_request *req, files_struct *from,
     /* [<][>][^][v][top][bottom][index][help] */
 545                       uint32 access_mask, uint32 share_access,
 546                       uint32 create_options, files_struct *to)
 547 {
 548         SAFE_FREE(to->fh);
 549 
 550         to->fh = from->fh;
 551         to->fh->ref_count++;
 552 
 553         to->file_id = from->file_id;
 554         to->initial_allocation_size = from->initial_allocation_size;
 555         to->mode = from->mode;
 556         to->file_pid = from->file_pid;
 557         to->vuid = from->vuid;
 558         to->open_time = from->open_time;
 559         to->access_mask = access_mask;
 560         to->share_access = share_access;
 561         to->oplock_type = from->oplock_type;
 562         to->can_lock = from->can_lock;
 563         to->can_read = (access_mask & (FILE_READ_DATA)) ? True : False;
 564         if (!CAN_WRITE(from->conn)) {
 565                 to->can_write = False;
 566         } else {
 567                 to->can_write = (access_mask & (FILE_WRITE_DATA | FILE_APPEND_DATA)) ? True : False;
 568         }
 569         to->print_file = from->print_file;
 570         to->modified = from->modified;
 571         to->is_directory = from->is_directory;
 572         to->aio_write_behind = from->aio_write_behind;
 573         string_set(&to->fsp_name,from->fsp_name);
 574 }

/* [<][>][^][v][top][bottom][index][help] */