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 2 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, write to the Free Software 18 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. 19*/ 20 21#include "includes.h" 22 23static int real_max_open_files; 24 25#define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < real_max_open_files)) 26 27#define FILE_HANDLE_OFFSET 0x1000 28 29static struct bitmap *file_bmap; 30 31static files_struct *Files; 32 33/* a fsp to use when chaining */ 34static files_struct *chain_fsp = NULL; 35/* a fsp to use to save when breaking an oplock. */ 36static files_struct *oplock_save_chain_fsp = NULL; 37 38static int files_used; 39 40/* A singleton cache to speed up searching by dev/inode. */ 41static struct fsp_singleton_cache { 42 files_struct *fsp; 43 SMB_DEV_T dev; 44 SMB_INO_T inode; 45} fsp_fi_cache; 46 47/**************************************************************************** 48 Return a unique number identifying this fsp over the life of this pid. 49****************************************************************************/ 50 51static unsigned long get_gen_count(void) 52{ 53 static unsigned long file_gen_counter; 54 55 if ((++file_gen_counter) == 0) 56 return ++file_gen_counter; 57 return file_gen_counter; 58} 59 60/**************************************************************************** 61 Find first available file slot. 62****************************************************************************/ 63 64files_struct *file_new(connection_struct *conn) 65{ 66 int i; 67 static int first_file; 68 files_struct *fsp, *next; 69 70 /* we want to give out file handles differently on each new 71 connection because of a common bug in MS clients where they try to 72 reuse a file descriptor from an earlier smb connection. This code 73 increases the chance that the errant client will get an error rather 74 than causing corruption */ 75 if (first_file == 0) { 76 first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files; 77 } 78 79 i = bitmap_find(file_bmap, first_file); 80 if (i == -1) { 81 /* 82 * Before we give up, go through the open files 83 * and see if there are any files opened with a 84 * batch oplock. If so break the oplock and then 85 * re-use that entry (if it becomes closed). 86 * This may help as NT/95 clients tend to keep 87 * files batch oplocked for quite a long time 88 * after they have finished with them. 89 */ 90 for (fsp=Files;fsp;fsp=next) { 91 next=fsp->next; 92 if (attempt_close_oplocked_file(fsp)) { 93 return file_new(conn); 94 } 95 } 96 97 DEBUG(0,("ERROR! Out of file structures\n")); 98 unix_ERR_class = ERRSRV; 99 unix_ERR_code = ERRnofids; 100 return NULL; 101 } 102 103 fsp = SMB_MALLOC_P(files_struct); 104 if (!fsp) { 105 unix_ERR_class = ERRSRV; 106 unix_ERR_code = ERRnofids; 107 return NULL; 108 } 109 110 ZERO_STRUCTP(fsp); 111 fsp->fd = -1; 112 fsp->conn = conn; 113 fsp->file_id = get_gen_count(); 114 GetTimeOfDay(&fsp->open_time); 115 116 first_file = (i+1) % real_max_open_files; 117 118 bitmap_set(file_bmap, i); 119 files_used++; 120 121 fsp->fnum = i + FILE_HANDLE_OFFSET; 122 SMB_ASSERT(fsp->fnum < 65536); 123 124 string_set(&fsp->fsp_name,""); 125 126 DLIST_ADD(Files, fsp); 127 128 DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n", 129 i, fsp->fnum, files_used)); 130 131 chain_fsp = fsp; 132 133 /* A new fsp invalidates a negative fsp_fi_cache. */ 134 if (fsp_fi_cache.fsp == NULL) { 135 ZERO_STRUCT(fsp_fi_cache); 136 } 137 138 return fsp; 139} 140 141/**************************************************************************** 142 Close all open files for a connection. 143****************************************************************************/ 144 145void file_close_conn(connection_struct *conn) 146{ 147 files_struct *fsp, *next; 148 149 for (fsp=Files;fsp;fsp=next) { 150 next = fsp->next; 151 if (fsp->conn == conn) { 152 close_file(fsp,False); 153 } 154 } 155} 156 157/**************************************************************************** 158 Close all open files for a pid. 159****************************************************************************/ 160 161void file_close_pid(uint16 smbpid) 162{ 163 files_struct *fsp, *next; 164 165 for (fsp=Files;fsp;fsp=next) { 166 next = fsp->next; 167 if (fsp->file_pid == smbpid) { 168 close_file(fsp,False); 169 } 170 } 171} 172 173/**************************************************************************** 174 Initialise file structures. 175****************************************************************************/ 176 177#define MAX_OPEN_FUDGEFACTOR 20 178 179void file_init(void) 180{ 181 int request_max_open_files = lp_max_open_files(); 182 int real_lim; 183 184 /* 185 * Set the max_open files to be the requested 186 * max plus a fudgefactor to allow for the extra 187 * fd's we need such as log files etc... 188 */ 189 real_lim = set_maxfiles(request_max_open_files + MAX_OPEN_FUDGEFACTOR); 190 191 real_max_open_files = real_lim - MAX_OPEN_FUDGEFACTOR; 192 193 if (real_max_open_files + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536) 194 real_max_open_files = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES; 195 196 if(real_max_open_files != request_max_open_files) { 197 DEBUG(1,("file_init: Information only: requested %d \ 198open files, %d are available.\n", request_max_open_files, real_max_open_files)); 199 } 200 201 SMB_ASSERT(real_max_open_files > 100); 202 203 file_bmap = bitmap_allocate(real_max_open_files); 204 205 if (!file_bmap) { 206 exit_server("out of memory in file_init"); 207 } 208 209 /* 210 * Ensure that pipe_handle_oppset is set correctly. 211 */ 212 set_pipe_handle_offset(real_max_open_files); 213} 214 215/**************************************************************************** 216 Close files open by a specified vuid. 217****************************************************************************/ 218 219void file_close_user(int vuid) 220{ 221 files_struct *fsp, *next; 222 223 for (fsp=Files;fsp;fsp=next) { 224 next=fsp->next; 225 if (fsp->vuid == vuid) { 226 close_file(fsp,False); 227 } 228 } 229} 230 231void file_dump_open_table(void) 232{ 233 int count=0; 234 files_struct *fsp; 235 236 for (fsp=Files;fsp;fsp=fsp->next,count++) { 237 DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, fileid = %lu, dev = %x, inode = %.0f\n", 238 count, fsp->fnum, fsp->fsp_name, fsp->fd, (unsigned long)fsp->file_id, 239 (unsigned int)fsp->dev, (double)fsp->inode )); 240 } 241} 242 243/**************************************************************************** 244 Find a fsp given a file descriptor. 245****************************************************************************/ 246 247files_struct *file_find_fd(int fd) 248{ 249 int count=0; 250 files_struct *fsp; 251 252 for (fsp=Files;fsp;fsp=fsp->next,count++) { 253 if (fsp->fd == fd) { 254 if (count > 10) { 255 DLIST_PROMOTE(Files, fsp); 256 } 257 return fsp; 258 } 259 } 260 261 return NULL; 262} 263 264/**************************************************************************** 265 Find a fsp given a device, inode and file_id. 266****************************************************************************/ 267 268files_struct *file_find_dif(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id) 269{ 270 int count=0; 271 files_struct *fsp; 272 273 for (fsp=Files;fsp;fsp=fsp->next,count++) { 274 /* We can have a fsp->fd == -1 here as it could be a stat open. */ 275 if (fsp->dev == dev && 276 fsp->inode == inode && 277 fsp->file_id == file_id ) { 278 if (count > 10) { 279 DLIST_PROMOTE(Files, fsp); 280 } 281 /* Paranoia check. */ 282 if (fsp->fd == -1 && fsp->oplock_type != NO_OPLOCK) { 283 DEBUG(0,("file_find_dif: file %s dev = %x, inode = %.0f, file_id = %u \ 284oplock_type = %u is a stat open with oplock type !\n", fsp->fsp_name, (unsigned int)fsp->dev, 285 (double)fsp->inode, (unsigned int)fsp->file_id, 286 (unsigned int)fsp->oplock_type )); 287 smb_panic("file_find_dif\n"); 288 } 289 return fsp; 290 } 291 } 292 293 return NULL; 294} 295 296/**************************************************************************** 297 Check if an fsp still exists. 298****************************************************************************/ 299 300files_struct *file_find_fsp(files_struct *orig_fsp) 301{ 302 files_struct *fsp; 303 304 for (fsp=Files;fsp;fsp=fsp->next) { 305 if (fsp == orig_fsp) 306 return fsp; 307 } 308 309 return NULL; 310} 311 312/**************************************************************************** 313 Find the first fsp given a device and inode. 314 We use a singleton cache here to speed up searching from getfilepathinfo 315 calls. 316****************************************************************************/ 317 318files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode) 319{ 320 files_struct *fsp; 321 322 if (fsp_fi_cache.dev == dev && fsp_fi_cache.inode == inode) { 323 /* Positive or negative cache hit. */ 324 return fsp_fi_cache.fsp; 325 } 326 327 fsp_fi_cache.dev = dev; 328 fsp_fi_cache.inode = inode; 329 330 for (fsp=Files;fsp;fsp=fsp->next) { 331 if ( fsp->fd != -1 && 332 fsp->dev == dev && 333 fsp->inode == inode ) { 334 /* Setup positive cache. */ 335 fsp_fi_cache.fsp = fsp; 336 return fsp; 337 } 338 } 339 340 /* Setup negative cache. */ 341 fsp_fi_cache.fsp = NULL; 342 return NULL; 343} 344 345/**************************************************************************** 346 Find the next fsp having the same device and inode. 347****************************************************************************/ 348 349files_struct *file_find_di_next(files_struct *start_fsp) 350{ 351 files_struct *fsp; 352 353 for (fsp = start_fsp->next;fsp;fsp=fsp->next) { 354 if ( fsp->fd != -1 && 355 fsp->dev == start_fsp->dev && 356 fsp->inode == start_fsp->inode ) 357 return fsp; 358 } 359 360 return NULL; 361} 362 363/**************************************************************************** 364 Find a fsp that is open for printing. 365****************************************************************************/ 366 367files_struct *file_find_print(void) 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 Set a pending modtime across all files with a given dev/ino pair. 382 Record the owner of that modtime. 383****************************************************************************/ 384 385void fsp_set_pending_modtime(files_struct *tfsp, time_t pmod) 386{ 387 files_struct *fsp; 388 389 if (null_mtime(pmod)) { 390 return; 391 } 392 393 for (fsp = Files;fsp;fsp=fsp->next) { 394 if ( fsp->fd != -1 && 395 fsp->dev == tfsp->dev && 396 fsp->inode == tfsp->inode ) { 397 fsp->pending_modtime = pmod; 398 fsp->pending_modtime_owner = False; 399 } 400 } 401 402 tfsp->pending_modtime_owner = True; 403} 404 405/**************************************************************************** 406 Sync open files on a connection. 407****************************************************************************/ 408 409void file_sync_all(connection_struct *conn) 410{ 411 files_struct *fsp, *next; 412 413 for (fsp=Files;fsp;fsp=next) { 414 next=fsp->next; 415 if ((conn == fsp->conn) && (fsp->fd != -1)) { 416 sync_file(conn,fsp); 417 } 418 } 419} 420 421/**************************************************************************** 422 Free up a fsp. 423****************************************************************************/ 424 425void file_free(files_struct *fsp) 426{ 427 DLIST_REMOVE(Files, fsp); 428 429 string_free(&fsp->fsp_name); 430 431 if (fsp->fake_file_handle) { 432 destroy_fake_file_handle(&fsp->fake_file_handle); 433 } 434 435 bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET); 436 files_used--; 437 438 DEBUG(5,("freed files structure %d (%d used)\n", 439 fsp->fnum, files_used)); 440 441 /* this is paranoia, just in case someone tries to reuse the 442 information */ 443 ZERO_STRUCTP(fsp); 444 445 if (fsp == chain_fsp) { 446 chain_fsp = NULL; 447 } 448 449 /* Closing a file can invalidate the positive cache. */ 450 if (fsp == fsp_fi_cache.fsp) { 451 ZERO_STRUCT(fsp_fi_cache); 452 } 453 454 SAFE_FREE(fsp); 455} 456 457/**************************************************************************** 458 Get a fsp from a packet given the offset of a 16 bit fnum. 459****************************************************************************/ 460 461files_struct *file_fsp(char *buf, int where) 462{ 463 int fnum, count=0; 464 files_struct *fsp; 465 466 if (chain_fsp) 467 return chain_fsp; 468 469 if (!buf) 470 return NULL; 471 fnum = SVAL(buf, where); 472 473 for (fsp=Files;fsp;fsp=fsp->next, count++) { 474 if (fsp->fnum == fnum) { 475 chain_fsp = fsp; 476 if (count > 10) { 477 DLIST_PROMOTE(Files, fsp); 478 } 479 return fsp; 480 } 481 } 482 return NULL; 483} 484 485/**************************************************************************** 486 Reset the chained fsp - done at the start of a packet reply. 487****************************************************************************/ 488 489void file_chain_reset(void) 490{ 491 chain_fsp = NULL; 492} 493 494/**************************************************************************** 495Save the chained fsp - done when about to do an oplock break. 496****************************************************************************/ 497 498void file_chain_save(void) 499{ 500 oplock_save_chain_fsp = chain_fsp; 501} 502 503/**************************************************************************** 504Restore the chained fsp - done after an oplock break. 505****************************************************************************/ 506 507void file_chain_restore(void) 508{ 509 chain_fsp = oplock_save_chain_fsp; 510} 511