#include "includes.h"
static int real_max_open_files;
#define VALID_FNUM(fnum) (((fnum) >= 0) && ((fnum) < real_max_open_files))
#define FILE_HANDLE_OFFSET 0x1000
static struct bitmap *file_bmap;
static files_struct *Files;
static files_struct *chain_fsp = NULL;
static files_struct *oplock_save_chain_fsp = NULL;
static int files_used;
static unsigned long get_gen_count(void)
{
static unsigned long file_gen_counter;
if ((++file_gen_counter) == 0)
return ++file_gen_counter;
return file_gen_counter;
}
files_struct *file_new(connection_struct *conn)
{
int i;
static int first_file;
files_struct *fsp, *next;
if (first_file == 0) {
first_file = (sys_getpid() ^ (int)time(NULL)) % real_max_open_files;
}
i = bitmap_find(file_bmap, first_file);
if (i == -1) {
for (fsp=Files;fsp;fsp=next) {
next=fsp->next;
if (attempt_close_oplocked_file(fsp)) {
return file_new(conn);
}
}
DEBUG(0,("ERROR! Out of file structures\n"));
unix_ERR_class = ERRSRV;
unix_ERR_code = ERRnofids;
return NULL;
}
fsp = (files_struct *)malloc(sizeof(*fsp));
if (!fsp) {
unix_ERR_class = ERRSRV;
unix_ERR_code = ERRnofids;
return NULL;
}
ZERO_STRUCTP(fsp);
fsp->fd = -1;
fsp->conn = conn;
fsp->file_id = get_gen_count();
GetTimeOfDay(&fsp->open_time);
first_file = (i+1) % real_max_open_files;
bitmap_set(file_bmap, i);
files_used++;
fsp->fnum = i + FILE_HANDLE_OFFSET;
SMB_ASSERT(fsp->fnum < 65536);
string_set(&fsp->fsp_name,"");
DLIST_ADD(Files, fsp);
DEBUG(5,("allocated file structure %d, fnum = %d (%d used)\n",
i, fsp->fnum, files_used));
chain_fsp = fsp;
return fsp;
}
void file_close_conn(connection_struct *conn)
{
files_struct *fsp, *next;
for (fsp=Files;fsp;fsp=next) {
next = fsp->next;
if (fsp->conn == conn) {
close_file(fsp,False);
}
}
}
void file_close_pid(uint16 smbpid)
{
files_struct *fsp, *next;
for (fsp=Files;fsp;fsp=next) {
next = fsp->next;
if (fsp->file_pid == smbpid) {
close_file(fsp,False);
}
}
}
#define MAX_OPEN_FUDGEFACTOR 20
void file_init(void)
{
int request_max_open_files = lp_max_open_files();
int real_lim;
real_lim = set_maxfiles(request_max_open_files + MAX_OPEN_FUDGEFACTOR);
real_max_open_files = real_lim - MAX_OPEN_FUDGEFACTOR;
if (real_max_open_files + FILE_HANDLE_OFFSET + MAX_OPEN_PIPES > 65536)
real_max_open_files = 65536 - FILE_HANDLE_OFFSET - MAX_OPEN_PIPES;
if(real_max_open_files != request_max_open_files) {
DEBUG(1,("file_init: Information only: requested %d \
open files, %d are available.\n", request_max_open_files, real_max_open_files));
}
SMB_ASSERT(real_max_open_files > 100);
file_bmap = bitmap_allocate(real_max_open_files);
if (!file_bmap) {
exit_server("out of memory in file_init");
}
set_pipe_handle_offset(real_max_open_files);
}
void file_close_user(int vuid)
{
files_struct *fsp, *next;
for (fsp=Files;fsp;fsp=next) {
next=fsp->next;
if (fsp->vuid == vuid) {
close_file(fsp,False);
}
}
}
void file_dump_open_table(void)
{
int count=0;
files_struct *fsp;
for (fsp=Files;fsp;fsp=fsp->next,count++) {
DEBUG(10,("Files[%d], fnum = %d, name %s, fd = %d, fileid = %lu, dev = %x, inode = %.0f\n",
count, fsp->fnum, fsp->fsp_name, fsp->fd, (unsigned long)fsp->file_id,
(unsigned int)fsp->dev, (double)fsp->inode ));
}
}
files_struct *file_find_fd(int fd)
{
int count=0;
files_struct *fsp;
for (fsp=Files;fsp;fsp=fsp->next,count++) {
if (fsp->fd == fd) {
if (count > 10) {
DLIST_PROMOTE(Files, fsp);
}
return fsp;
}
}
return NULL;
}
files_struct *file_find_dif(SMB_DEV_T dev, SMB_INO_T inode, unsigned long file_id)
{
int count=0;
files_struct *fsp;
for (fsp=Files;fsp;fsp=fsp->next,count++) {
if (fsp->dev == dev &&
fsp->inode == inode &&
fsp->file_id == file_id ) {
if (count > 10) {
DLIST_PROMOTE(Files, fsp);
}
if (fsp->fd == -1 && fsp->oplock_type != NO_OPLOCK) {
DEBUG(0,("file_find_dif: file %s dev = %x, inode = %.0f, file_id = %u \
oplock_type = %u is a stat open with oplock type !\n", fsp->fsp_name, (unsigned int)fsp->dev,
(double)fsp->inode, (unsigned int)fsp->file_id,
(unsigned int)fsp->oplock_type ));
smb_panic("file_find_dif\n");
}
return fsp;
}
}
return NULL;
}
files_struct *file_find_fsp(files_struct *orig_fsp)
{
files_struct *fsp;
for (fsp=Files;fsp;fsp=fsp->next) {
if (fsp == orig_fsp)
return fsp;
}
return NULL;
}
files_struct *file_find_di_first(SMB_DEV_T dev, SMB_INO_T inode)
{
files_struct *fsp;
for (fsp=Files;fsp;fsp=fsp->next) {
if ( fsp->fd != -1 &&
fsp->dev == dev &&
fsp->inode == inode )
return fsp;
}
return NULL;
}
files_struct *file_find_di_next(files_struct *start_fsp)
{
files_struct *fsp;
for (fsp = start_fsp->next;fsp;fsp=fsp->next) {
if ( fsp->fd != -1 &&
fsp->dev == start_fsp->dev &&
fsp->inode == start_fsp->inode )
return fsp;
}
return NULL;
}
files_struct *file_find_print(void)
{
files_struct *fsp;
for (fsp=Files;fsp;fsp=fsp->next) {
if (fsp->print_file) return fsp;
}
return NULL;
}
void file_sync_all(connection_struct *conn)
{
files_struct *fsp, *next;
for (fsp=Files;fsp;fsp=next) {
next=fsp->next;
if ((conn == fsp->conn) && (fsp->fd != -1)) {
sync_file(conn,fsp);
}
}
}
void file_free(files_struct *fsp)
{
DLIST_REMOVE(Files, fsp);
string_free(&fsp->fsp_name);
if (fsp->fake_file_handle) {
destroy_fake_file_handle(&fsp->fake_file_handle);
}
bitmap_clear(file_bmap, fsp->fnum - FILE_HANDLE_OFFSET);
files_used--;
DEBUG(5,("freed files structure %d (%d used)\n",
fsp->fnum, files_used));
ZERO_STRUCTP(fsp);
if (fsp == chain_fsp) chain_fsp = NULL;
SAFE_FREE(fsp);
}
files_struct *file_fsp(char *buf, int where)
{
int fnum, count=0;
files_struct *fsp;
if (chain_fsp)
return chain_fsp;
if (!buf)
return NULL;
fnum = SVAL(buf, where);
for (fsp=Files;fsp;fsp=fsp->next, count++) {
if (fsp->fnum == fnum) {
chain_fsp = fsp;
if (count > 10) {
DLIST_PROMOTE(Files, fsp);
}
return fsp;
}
}
return NULL;
}
void file_chain_reset(void)
{
chain_fsp = NULL;
}
void file_chain_save(void)
{
oplock_save_chain_fsp = chain_fsp;
}
void file_chain_restore(void)
{
chain_fsp = oplock_save_chain_fsp;
}