//static BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) static BOOL read_from_write_cache(files_struct *fsp,char *data,SMB_BIG_UINT pos,size_t n) /* modified end pling 11/25/2009 */ { write_cache *wcp = fsp->wcp; if(!wcp) return False; if(n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size) return False; memcpy(data, wcp->data + (pos - wcp->offset), n); DO_PROFILE_INC(writecache_read_hits); return True; }
static bool read_from_write_cache(files_struct *fsp,char *data,SMB_OFF_T pos,size_t n) { write_cache *wcp = fsp->wcp; if(!wcp) { return False; } if( n > wcp->data_size || pos < wcp->offset || pos + n > wcp->offset + wcp->data_size) { return False; } memcpy(data, wcp->data + (pos - wcp->offset), n); DO_PROFILE_INC(writecache_read_hits); return True; }
static bool become_uid(uid_t uid) { /* Check for dodgy uid values */ if (uid == (uid_t)-1 || ((sizeof(uid_t) == 2) && (uid == (uid_t)65535))) { if (!become_uid_done) { DEBUG(1,("WARNING: using uid %d is a security risk\n", (int)uid)); become_uid_done = true; } } /* Set effective user id */ set_effective_uid(uid); DO_PROFILE_INC(uid_changes); return True; }
ssize_t write_file(struct smb_request *req, files_struct *fsp, const char *data, SMB_OFF_T pos, size_t n) { write_cache *wcp = fsp->wcp; ssize_t total_written = 0; int write_path = -1; if (fsp->print_file) { uint32_t t; int ret; ret = print_spool_write(fsp, data, n, pos, &t); if (ret) { errno = ret; return -1; } return t; } if (!fsp->can_write) { errno = EPERM; return -1; } if (!fsp->modified) { fsp->modified = True; if (SMB_VFS_FSTAT(fsp, &fsp->fsp_name->st) == 0) { trigger_write_time_update(fsp); if (!fsp->posix_open && (lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn))) { int dosmode = dos_mode(fsp->conn, fsp->fsp_name); if (!IS_DOS_ARCHIVE(dosmode)) { file_set_dosmode(fsp->conn, fsp->fsp_name, dosmode | FILE_ATTRIBUTE_ARCHIVE, NULL, false); } } /* * If this is the first write and we have an exclusive oplock then setup * the write cache. */ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) { setup_write_cache(fsp, fsp->fsp_name->st.st_ex_size); wcp = fsp->wcp; } } } #ifdef WITH_PROFILE DO_PROFILE_INC(writecache_total_writes); if (!fsp->oplock_type) { DO_PROFILE_INC(writecache_non_oplock_writes); } #endif /* * If this file is level II oplocked then we need * to grab the shared memory lock and inform all * other files with a level II lock that they need * to flush their read caches. We keep the lock over * the shared memory area whilst doing this. */ /* This should actually be improved to span the write. */ contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE); contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE); #ifdef WITH_PROFILE if (profile_p && profile_p->writecache_total_writes % 500 == 0) { DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", profile_p->writecache_init_writes, profile_p->writecache_abutted_writes, profile_p->writecache_total_writes, profile_p->writecache_non_oplock_writes, profile_p->writecache_allocated_write_caches, profile_p->writecache_num_write_caches, profile_p->writecache_direct_writes, profile_p->writecache_num_perfect_writes, profile_p->writecache_read_hits )); DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n", profile_p->writecache_flushed_writes[SEEK_FLUSH], profile_p->writecache_flushed_writes[READ_FLUSH], profile_p->writecache_flushed_writes[WRITE_FLUSH], profile_p->writecache_flushed_writes[READRAW_FLUSH], profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH], profile_p->writecache_flushed_writes[CLOSE_FLUSH], profile_p->writecache_flushed_writes[SYNC_FLUSH] )); }
static void exit_server_common(enum server_exit_reason how, const char *reason) { struct smbXsrv_client *client = global_smbXsrv_client; struct smbXsrv_connection *xconn = NULL; struct smbd_server_connection *sconn = NULL; struct messaging_context *msg_ctx = server_messaging_context(); if (client != NULL) { sconn = client->sconn; /* * Here we typically have just one connection */ xconn = client->connections; } if (!exit_firsttime) exit(0); exit_firsttime = false; change_to_root_user(); if (xconn != NULL) { /* * This is typically the disconnect for the only * (or with multi-channel last) connection of the client */ if (NT_STATUS_IS_OK(xconn->transport.status)) { switch (how) { case SERVER_EXIT_ABNORMAL: xconn->transport.status = NT_STATUS_INTERNAL_ERROR; break; case SERVER_EXIT_NORMAL: xconn->transport.status = NT_STATUS_LOCAL_DISCONNECT; break; } } TALLOC_FREE(xconn->smb1.negprot.auth_context); } change_to_root_user(); if (sconn != NULL) { if (lp_log_writeable_files_on_exit()) { bool found = false; files_forall(sconn, log_writeable_file_fn, &found); } } change_to_root_user(); if (xconn != NULL) { NTSTATUS status; /* * Note: this is a no-op for smb2 as * conn->tcon_table is empty */ status = smb1srv_tcon_disconnect_all(xconn); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Server exit (%s)\n", (reason ? reason : "normal exit"))); DEBUG(0, ("exit_server_common: " "smb1srv_tcon_disconnect_all() failed (%s) - " "triggering cleanup\n", nt_errstr(status))); } status = smbXsrv_session_logoff_all(xconn); if (!NT_STATUS_IS_OK(status)) { DEBUG(0,("Server exit (%s)\n", (reason ? reason : "normal exit"))); DEBUG(0, ("exit_server_common: " "smbXsrv_session_logoff_all() failed (%s) - " "triggering cleanup\n", nt_errstr(status))); } } change_to_root_user(); /* 3 second timeout. */ print_notify_send_messages(msg_ctx, 3); #ifdef USE_DMAPI /* Destroy Samba DMAPI session only if we are master smbd process */ if (am_parent) { if (!dmapi_destroy_session()) { DEBUG(0,("Unable to close Samba DMAPI session\n")); } } #endif if (am_parent) { rpc_wkssvc_shutdown(); rpc_dssetup_shutdown(); #ifdef DEVELOPER rpc_rpcecho_shutdown(); #endif rpc_netdfs_shutdown(); rpc_initshutdown_shutdown(); rpc_eventlog_shutdown(); rpc_ntsvcs_shutdown(); rpc_svcctl_shutdown(); rpc_spoolss_shutdown(); rpc_srvsvc_shutdown(); rpc_winreg_shutdown(); rpc_netlogon_shutdown(); rpc_samr_shutdown(); rpc_lsarpc_shutdown(); } /* * we need to force the order of freeing the following, * because smbd_msg_ctx is not a talloc child of smbd_server_conn. */ if (client != NULL) { struct smbXsrv_connection *next; for (; xconn != NULL; xconn = next) { next = xconn->next; DLIST_REMOVE(client->connections, xconn); talloc_free(xconn); DO_PROFILE_INC(disconnect); } TALLOC_FREE(client->sconn); } sconn = NULL; xconn = NULL; client = NULL; netlogon_creds_cli_close_global_db(); TALLOC_FREE(global_smbXsrv_client); smbprofile_dump(); server_messaging_context_free(); server_event_context_free(); TALLOC_FREE(smbd_memcache_ctx); locking_end(); printing_end(); if (how != SERVER_EXIT_NORMAL) { smb_panic(reason); /* Notreached. */ exit(1); } else { DEBUG(3,("Server exit (%s)\n", (reason ? reason : "normal exit"))); if (am_parent) { pidfile_unlink(lp_pid_directory(), "smbd"); } gencache_stabilize(); } exit(0); }
ssize_t write_file(files_struct *fsp, const char *data, SMB_OFF_T pos, size_t n) { write_cache *wcp = fsp->wcp; ssize_t total_written = 0; int write_path = -1; if (fsp->print_file) { #ifdef AVM_NO_PRINTING errno = EBADF; return -1; #else fstring sharename; uint32 jobid; if (!rap_to_pjobid(fsp->rap_print_jobid, sharename, &jobid)) { DEBUG(3,("write_file: Unable to map RAP jobid %u to jobid.\n", (unsigned int)fsp->rap_print_jobid )); errno = EBADF; return -1; } return print_job_write(SNUM(fsp->conn), jobid, data, pos, n); #endif /* AVM_NO_PRINTING */ } if (!fsp->can_write) { errno = EPERM; return(0); } if (!fsp->modified) { SMB_STRUCT_STAT st; fsp->modified = True; if (SMB_VFS_FSTAT(fsp,fsp->fh->fd,&st) == 0) { int dosmode = dos_mode(fsp->conn,fsp->fsp_name,&st); if ((lp_store_dos_attributes(SNUM(fsp->conn)) || MAP_ARCHIVE(fsp->conn)) && !IS_DOS_ARCHIVE(dosmode)) { file_set_dosmode(fsp->conn,fsp->fsp_name,dosmode | aARCH,&st, False); } /* * If this is the first write and we have an exclusive oplock then setup * the write cache. */ if (EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && !wcp) { setup_write_cache(fsp, st.st_size); wcp = fsp->wcp; } } } #ifdef WITH_PROFILE DO_PROFILE_INC(writecache_total_writes); if (!fsp->oplock_type) { DO_PROFILE_INC(writecache_non_oplock_writes); } #endif /* * If this file is level II oplocked then we need * to grab the shared memory lock and inform all * other files with a level II lock that they need * to flush their read caches. We keep the lock over * the shared memory area whilst doing this. */ release_level_2_oplocks_on_change(fsp); #ifdef WITH_PROFILE if (profile_p && profile_p->writecache_total_writes % 500 == 0) { DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", profile_p->writecache_init_writes, profile_p->writecache_abutted_writes, profile_p->writecache_total_writes, profile_p->writecache_non_oplock_writes, profile_p->writecache_allocated_write_caches, profile_p->writecache_num_write_caches, profile_p->writecache_direct_writes, profile_p->writecache_num_perfect_writes, profile_p->writecache_read_hits )); DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n", profile_p->writecache_flushed_writes[SEEK_FLUSH], profile_p->writecache_flushed_writes[READ_FLUSH], profile_p->writecache_flushed_writes[WRITE_FLUSH], profile_p->writecache_flushed_writes[READRAW_FLUSH], profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH], profile_p->writecache_flushed_writes[CLOSE_FLUSH], profile_p->writecache_flushed_writes[SYNC_FLUSH] )); }
ssize_t write_file(struct smb_request *req, files_struct *fsp, const char *data, off_t pos, size_t n) { struct write_cache *wcp = fsp->wcp; ssize_t total_written = 0; int write_path = -1; if (fsp->print_file) { uint32_t t; int ret; ret = print_spool_write(fsp, data, n, pos, &t); if (ret) { errno = ret; return -1; } return t; } if (!fsp->can_write) { errno = EPERM; return -1; } /* * If this is the first write and we have an exclusive oplock * then setup the write cache. */ if (!fsp->modified && EXCLUSIVE_OPLOCK_TYPE(fsp->oplock_type) && (wcp == NULL)) { setup_write_cache(fsp, fsp->fsp_name->st.st_ex_size); wcp = fsp->wcp; } mark_file_modified(fsp); #ifdef WITH_PROFILE DO_PROFILE_INC(writecache_total_writes); if (!fsp->oplock_type) { DO_PROFILE_INC(writecache_non_oplock_writes); } #endif /* * If this file is level II oplocked then we need * to grab the shared memory lock and inform all * other files with a level II lock that they need * to flush their read caches. We keep the lock over * the shared memory area whilst doing this. */ /* This should actually be improved to span the write. */ contend_level2_oplocks_begin(fsp, LEVEL2_CONTEND_WRITE); contend_level2_oplocks_end(fsp, LEVEL2_CONTEND_WRITE); #ifdef WITH_PROFILE if (profile_p && profile_p->writecache_total_writes % 500 == 0) { DEBUG(3,("WRITECACHE: initwrites=%u abutted=%u total=%u \ nonop=%u allocated=%u active=%u direct=%u perfect=%u readhits=%u\n", profile_p->writecache_init_writes, profile_p->writecache_abutted_writes, profile_p->writecache_total_writes, profile_p->writecache_non_oplock_writes, profile_p->writecache_allocated_write_caches, profile_p->writecache_num_write_caches, profile_p->writecache_direct_writes, profile_p->writecache_num_perfect_writes, profile_p->writecache_read_hits )); DEBUG(3,("WRITECACHE: Flushes SEEK=%d, READ=%d, WRITE=%d, READRAW=%d, OPLOCK=%d, CLOSE=%d, SYNC=%d\n", profile_p->writecache_flushed_writes[SEEK_FLUSH], profile_p->writecache_flushed_writes[READ_FLUSH], profile_p->writecache_flushed_writes[WRITE_FLUSH], profile_p->writecache_flushed_writes[READRAW_FLUSH], profile_p->writecache_flushed_writes[OPLOCK_RELEASE_FLUSH], profile_p->writecache_flushed_writes[CLOSE_FLUSH], profile_p->writecache_flushed_writes[SYNC_FLUSH] )); }
bool stat_cache_lookup(connection_struct *conn, bool posix_paths, char **pp_name, char **pp_dirpath, char **pp_start, SMB_STRUCT_STAT *pst) { char *chk_name; size_t namelen; bool sizechanged = False; unsigned int num_components = 0; char *translated_path; size_t translated_path_length; DATA_BLOB data_val; char *name; TALLOC_CTX *ctx = talloc_tos(); struct smb_filename smb_fname; int ret; *pp_dirpath = NULL; *pp_start = *pp_name; if (!lp_stat_cache()) { return False; } name = *pp_name; namelen = strlen(name); DO_PROFILE_INC(statcache_lookups); /* * Don't lookup trivial valid directory entries. */ if ((*name == '\0') || ISDOT(name) || ISDOTDOT(name)) { return False; } if (conn->case_sensitive) { chk_name = talloc_strdup(ctx,name); if (!chk_name) { DEBUG(0, ("stat_cache_lookup: strdup failed!\n")); return False; } } else { chk_name = talloc_strdup_upper(ctx,name); if (!chk_name) { DEBUG(0, ("stat_cache_lookup: talloc_strdup_upper failed!\n")); return False; } /* * In some language encodings the length changes * if we uppercase. We need to treat this differently * below. */ if (strlen(chk_name) != namelen) { sizechanged = True; } } while (1) { char *sp; data_val = data_blob_null; if (memcache_lookup( smbd_memcache(), STAT_CACHE, data_blob_const(chk_name, strlen(chk_name)), &data_val)) { break; } DEBUG(10,("stat_cache_lookup: lookup failed for name [%s]\n", chk_name )); /* * Didn't find it - remove last component for next try. */ if (!(sp = strrchr_m(chk_name, '/'))) { /* * We reached the end of the name - no match. */ DO_PROFILE_INC(statcache_misses); TALLOC_FREE(chk_name); return False; } *sp = '\0'; /* * Count the number of times we have done this, we'll * need it when reconstructing the string. */ if (sizechanged) { num_components++; } if ((*chk_name == '\0') || ISDOT(chk_name) || ISDOTDOT(chk_name)) { DO_PROFILE_INC(statcache_misses); TALLOC_FREE(chk_name); return False; } } translated_path = talloc_strdup(ctx,(char *)data_val.data); if (!translated_path) { smb_panic("talloc failed"); } translated_path_length = data_val.length - 1; DEBUG(10,("stat_cache_lookup: lookup succeeded for name [%s] " "-> [%s]\n", chk_name, translated_path )); DO_PROFILE_INC(statcache_hits); ZERO_STRUCT(smb_fname); smb_fname.base_name = translated_path; if (posix_paths) { ret = SMB_VFS_LSTAT(conn, &smb_fname); } else { ret = SMB_VFS_STAT(conn, &smb_fname); } if (ret != 0) { /* Discard this entry - it doesn't exist in the filesystem. */ memcache_delete(smbd_memcache(), STAT_CACHE, data_blob_const(chk_name, strlen(chk_name))); TALLOC_FREE(chk_name); TALLOC_FREE(translated_path); return False; } *pst = smb_fname.st; if (!sizechanged) { memcpy(*pp_name, translated_path, MIN(namelen, translated_path_length)); } else { if (num_components == 0) { name = talloc_strndup(ctx, translated_path, translated_path_length); } else { char *sp; sp = strnrchr_m(name, '/', num_components); if (sp) { name = talloc_asprintf(ctx,"%.*s%s", (int)translated_path_length, translated_path, sp); } else { name = talloc_strndup(ctx, translated_path, translated_path_length); } } if (name == NULL) { /* * TODO: Get us out of here with a real error message */ smb_panic("talloc failed"); } TALLOC_FREE(*pp_name); *pp_name = name; } /* set pointer for 'where to start' on fixing the rest of the name */ *pp_start = &name[translated_path_length]; if (**pp_start == '/') { ++*pp_start; } *pp_dirpath = translated_path; TALLOC_FREE(chk_name); return (namelen == translated_path_length); }