/** * Run the file load file processors * * @param context DiskDeviceContext * @param state FileState * @param segment FileSegment */ protected final void runFileLoadedProcessors( DiskDeviceContext context, FileState state, FileSegment segment) { // Check if there are any file processors configured if (m_fileProcessors == null || m_fileProcessors.numberOfProcessors() == 0) return; try { // Run all of the file load processors for (int i = 0; i < m_fileProcessors.numberOfProcessors(); i++) { // Get the current file processor FileProcessor fileProc = m_fileProcessors.getProcessorAt(i); // Run the file processor fileProc.processLoadedFile(context, state, segment); } // Make sure the file segment is closed after processing segment.closeFile(); } catch (Exception ex) { // DEBUG if (Debug.EnableError && hasDebug()) { Debug.println("$$ Load file processor exception"); Debug.println(ex); } } }
/** * File state cache is closing down, any resources attached to the file state must be released. * * @param state FileState */ public void fileStateClosed(FileState state) { // DEBUG if (state == null) { Debug.println("%%%%% FileLoader.fileStateClosed() state=NULL %%%%%"); return; } // Check if the file state has an associated file FileSegmentInfo segInfo = (FileSegmentInfo) state.findAttribute(DBFileSegmentInfo); if (segInfo != null && segInfo.isQueued() == false && segInfo.hasStatus() != FileSegmentInfo.SaveWait) { try { // Delete the temporary file segInfo.deleteTemporaryFile(); // Debug if (Debug.EnableInfo && hasDebug()) Debug.println("$$ Deleted temporary file " + segInfo.getTemporaryFile() + " [CLOSED] $$"); } catch (IOException ex) { } } }
/** Finalize, check if there are any deferred requests in the list */ public void finalize() { if (m_deferredRequests != null && m_deferredRequests.size() > 0) { // Dump out the list of leaked deferred requests Debug.println("** Deferred requests found during per node finalize, perNode=" + this); for (DeferredRequest deferReq : m_deferredRequests) Debug.println("** Leaked deferred request=" + deferReq); } }
/** * Fail any deferred requests that are attached to this oplock, and clear the deferred list * * @return int Number of deferred requests that were failed */ public int failDeferredRequests() { // Check if there are any deferred requests if (m_deferredRequests == null) return 0; int failCnt = 0; synchronized (m_deferredRequests) { for (DeferredRequest deferReq : m_deferredRequests) { // Get the deferred session/packet details SMBSrvSession sess = deferReq.getDeferredSession(); SMBSrvPacket pkt = deferReq.getDeferredPacket(); try { // Return an error for the deferred file open request if (sess.sendAsyncErrorResponseSMB(pkt, SMBStatus.NTAccessDenied, SMBStatus.NTErr) == true) { // Update the failed request count failCnt++; // DEBUG if (Debug.EnableDbg && sess.hasDebug(SMBSrvSession.DBG_OPLOCK)) Debug.println("Oplock break timeout, oplock=" + this); } else if (Debug.EnableDbg && sess.hasDebug(SMBSrvSession.DBG_OPLOCK)) Debug.println("Failed to send open reject, oplock break timed out, oplock=" + this); } catch (IOException ex) { } finally { // Make sure the packet is released back to the memory pool if (pkt != null) sess.getPacketPool().releasePacket(pkt); } } // Clear the deferred request list m_deferredRequests.clear(); } // Return the count of failed requests return failCnt; }
/** * Add a LANA listener * * @param lana int * @param l LanaListener */ public final synchronized void addLanaListener(int lana, LanaListener l) { // Range check the LANA id if (lana < 0 || lana > 255) return; // Check if the listener array has been allocated if (m_listeners == null) { int len = LanaListenerArraySize; if (lana >= len) len = (lana + 4) & 0x00FC; m_listeners = new LanaListener[len]; } else if (lana >= m_listeners.length) { // Extend the LANA listener array LanaListener[] newArray = new LanaListener[(lana + 4) & 0x00FC]; // Copy the existing array to the extended array System.arraycopy(m_listeners, 0, newArray, 0, m_listeners.length); m_listeners = newArray; } // Add the LANA listener m_listeners[lana] = l; // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println("[SMB] Win32 NetBIOS register listener for LANA " + lana); }
/** * Process the set request * * @param rpc RpcPacket * @return RpcPacket */ private final RpcPacket procSet(RpcPacket rpc) { // Get the call parameters int progId = rpc.unpackInt(); int verId = rpc.unpackInt(); int proto = rpc.unpackInt(); int port = rpc.unpackInt(); // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println( "[PortMap] Set port program=" + Rpc.getServiceName(progId) + ", version=" + verId + ", protocol=" + (proto == Rpc.TCP ? "TCP" : "UDP") + ", port=" + port); // Check if the port is already mapped PortMapping portMap = findPortMapping(progId, verId, proto); int portAdded = Rpc.False; if (portMap == null) { // Add a mapping for the new service portMap = new PortMapping(progId, verId, proto, port); if (addPortMapping(portMap) == true) portAdded = Rpc.True; } // Check if the service is on the same port as the current port mapping, and it is not // an attempt to set the port mapper service port. else if (progId != PortMapper.ProgramId && portMap.getPort() == port) { // Settings are the same as the existing service settings so accept it portAdded = Rpc.True; } // Build the response header rpc.buildResponseHeader(); // Pack a boolean indicating if the port was added, or not rpc.packInt(portAdded); rpc.setLength(); // Return the response return rpc; }
/** * Delete the specified file data * * @param fname String * @param fid int * @param stid int * @exception IOException */ public void deleteFile(String fname, int fid, int stid) throws IOException { // Delete the file data from the database try { // Find the associated file state FileState fstate = m_stateCache.findFileState(fname, false); if (fstate != null) { // Get the file segment details FileSegmentInfo fileSegInfo = (FileSegmentInfo) fstate.removeAttribute(DBFileSegmentInfo); if (fileSegInfo != null) { try { // Change the file segment status fileSegInfo.setQueued(false); fileSegInfo.setStatus(FileSegmentInfo.Initial); // Delete the temporary file fileSegInfo.deleteTemporaryFile(); } catch (Exception ex) { // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println( "## ObjIdLoader failed to delete temp file " + fileSegInfo.getTemporaryFile()); } } } } catch (Exception ex) { // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println("## ObjIdLoader deleteFile() error, " + ex.toString()); } }
/** * Decrement the file open count * * @return int */ public final synchronized int decrementOpenCount() { // Debug if (m_openCount <= 0) Debug.println("@@@@@ File close name=" + getPath() + ", count=" + m_openCount + " <<ERROR>>"); else m_openCount--; return m_openCount; }
/** * Requeue deferred requests to the thread pool for processing, oplock has been released * * @return int Number of deferred requests requeued */ public int requeueDeferredRequests() { // Check if there are any deferred requests if (m_deferredRequests == null) return 0; int requeueCnt = 0; synchronized (m_deferredRequests) { for (DeferredRequest deferReq : m_deferredRequests) { // Get the deferred session/packet details SMBSrvSession sess = deferReq.getDeferredSession(); SMBSrvPacket pkt = deferReq.getDeferredPacket(); // DEBUG if (Debug.EnableDbg && sess.hasDebug(SMBSrvSession.DBG_OPLOCK)) Debug.println( "Release oplock, queued deferred request to thread pool sess=" + sess.getUniqueId() + ", pkt=" + pkt); try { // Queue the deferred request to the thread pool for processing sess.getThreadPool().queueRequest(new CIFSThreadRequest(sess, pkt)); } catch (Throwable ex) { // Failed to queue the request to the thread pool, release the deferred packet back to the // memory pool sess.getPacketPool().releasePacket(pkt); } } // Clear the deferred request list m_deferredRequests.clear(); } // Return the count of requeued requests return requeueCnt; }
/** Static initializer used to load the native code library */ static { // Check if we are running under 64 bit Windows String dllName = "Win32Utils"; if (X64.isWindows64()) dllName = "Win32Utilsx64"; // Load the Win32 utils library try { System.loadLibrary(dllName); } catch (Exception ex) { Debug.println(ex); } }
/** * Process the unset request * * @param rpc RpcPacket * @return RpcPacket */ private final RpcPacket procUnSet(RpcPacket rpc) { // Get the call parameters int progId = rpc.unpackInt(); int verId = rpc.unpackInt(); int proto = rpc.unpackInt(); int port = rpc.unpackInt(); // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println( "[PortMap] UnSet port program=" + Rpc.getServiceName(progId) + ", version=" + verId + ", protocol=" + (proto == Rpc.TCP ? "TCP" : "UDP") + ", port=" + port); // Check if the port is mapped, and it is not an attempt to remove a portmapper portt PortMapping portMap = findPortMapping(progId, verId, proto); int portRemoved = Rpc.False; if (portMap != null && progId != PortMapper.ProgramId) { // Remove the port mapping if (removePortMapping(portMap) == true) portRemoved = Rpc.True; } // Build the response header rpc.buildResponseHeader(); // Pack a boolean indicating if the port was removed, or not rpc.packInt(portRemoved); rpc.setLength(); // Return the response return rpc; }
protected final void shutdownHostAnnouncers() { if (m_hostAnnouncers.size() > 0) { for (int idx = 0; idx < m_hostAnnouncers.size(); idx++) { // Get the current host announcer HostAnnouncer hostAnnouncer = (HostAnnouncer) m_hostAnnouncers.get(idx); hostAnnouncer.shutdownAnnouncer(); // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println("[NetBIOS] Shutting down host announcer " + hostAnnouncer.getName()); } } }
/** Create a new temporary sub-directory */ private final void createNewTempDirectory() { // Create the starting temporary sub-directory m_curTempName = m_tempDirName + getTempDirectoryPrefix() + m_curTempIdx++; m_curTempDir = new File(m_curTempName); if (m_curTempDir.exists() == false) m_curTempDir.mkdir(); // Clear the temporary file count m_tempCount = 0; // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println("ObjIdLoader Created new temp directory - " + m_curTempName); }
/** Start the portmapper server */ public void startServer() { try { // Create the UDP RPC handler to accept incoming requests m_udpHandler = new UdpRpcDatagramHandler("PortMap", "Port", this, this, null, getPort(), MaxRequestSize); m_udpHandler.initializeSessionHandler(this); // Start the UDP request listener is a seperate thread Thread udpThread = new Thread(m_udpHandler); udpThread.setName("PortMap_UDP"); udpThread.start(); // Create the TCP RPC handler to accept incoming requests m_tcpHandler = new TcpRpcSessionHandler("PortMap", "Port", this, this, null, getPort(), MaxRequestSize); m_tcpHandler.initializeSessionHandler(this); // Start the UDP request listener is a seperate thread Thread tcpThread = new Thread(m_tcpHandler); tcpThread.setName("PortMap_TCP"); tcpThread.start(); // Add port mapper entries for the portmapper service PortMapping portMap = new PortMapping(PortMapper.ProgramId, PortMapper.VersionId, Rpc.UDP, getPort()); addPortMapping(portMap); portMap = new PortMapping(PortMapper.ProgramId, PortMapper.VersionId, Rpc.TCP, getPort()); addPortMapping(portMap); } catch (Exception ex) { Debug.println(ex); } }
/** * Process the get port request * * @param rpc RpcPacket * @return RpcPacket */ private final RpcPacket procGetPort(RpcPacket rpc) { // Get the call parameters int progId = rpc.unpackInt(); int verId = rpc.unpackInt(); int proto = rpc.unpackInt(); // Find the required port mapping PortMapping portMap = findPortMapping(progId, verId, proto); // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println( "[PortMap] Get port program=" + Rpc.getServiceName(progId) + ", version=" + verId + ", protocol=" + (proto == Rpc.TCP ? "TCP" : "UDP") + ", port=" + (portMap != null ? portMap.getPort() : 0)); // Build the response header rpc.buildResponseHeader(); // Pack the port number of the requested RPC service, or zero if not found rpc.packInt(portMap != null ? portMap.getPort() : 0); rpc.setLength(); // Return the response return rpc; }
/** * Add a deferred session/packet, whilst an oplock break is in progress * * @param deferredSess SMBSrvSession * @param deferredPkt SMBSrvPacket * @exception DeferFailedException If the session/packet cannot be deferred */ public void addDeferredSession(SMBSrvSession deferredSess, SMBSrvPacket deferredPkt) throws DeferFailedException { // Allocate the deferred request list, if required if (m_deferredRequests == null) { synchronized (this) { if (m_deferredRequests == null) m_deferredRequests = new ArrayList<DeferredRequest>(MaxDeferredRequests); } } // Add the request to the list if there are spare slots synchronized (m_deferredRequests) { if (m_deferredRequests.size() < MaxDeferredRequests) { // Add the deferred request to the list m_deferredRequests.add(new DeferredRequest(deferredSess, deferredPkt)); // Update the deferred processing count for the CIFS packet deferredPkt.incrementDeferredCount(); // Set the time that the oplock break was sent to the client, if this is the first deferred // request if (m_deferredRequests.size() == 1) m_oplockBreakTime = System.currentTimeMillis(); // DEBUG if (Debug.EnableDbg && deferredSess.hasDebug(SMBSrvSession.DBG_OPLOCK)) Debug.println( "Added deferred request, list=" + m_deferredRequests.size() + ", oplock=" + this); } else throw new DeferFailedException("No more deferred slots available on oplock"); } }
/** * Process the dump request * * @param rpc RpcPacket * @return RpcPacket */ private final RpcPacket procDump(RpcPacket rpc) { // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println("[PortMap] Dump ports request from " + rpc.getClientDetails()); // Build the response rpc.buildResponseHeader(); // Pack the active port mappings structures Enumeration enm = m_mappings.elements(); while (enm.hasMoreElements()) { // Get the current port mapping PortMapping portMap = (PortMapping) enm.nextElement(); // Pack the port mapping structure rpc.packInt(Rpc.True); rpc.packPortMapping(portMap); } // Pack the end of list structure, set the response length rpc.packInt(Rpc.False); rpc.setLength(); // Return the response return rpc; }
/** Thread method */ public void run() { // Clear the shutdown flag m_shutdown = false; // If Winsock NetBIOS is not enabled then initialize the sockets interface ServerConfiguration config = m_server.getConfiguration(); CIFSConfigSection cifsConfig = (CIFSConfigSection) config.getConfigSection(CIFSConfigSection.SectionName); if (cifsConfig.useWinsockNetBIOS() == false) { try { NetBIOSSocket.initializeSockets(); } catch (WinsockNetBIOSException ex) { // DEBUG if (Debug.EnableError && hasDebug()) { Debug.println("[SMB] Win32 NetBIOS initialization error"); Debug.println(ex); } // Shutdown the LANA monitor thread m_shutdown = true; } } // Loop until shutdown BitSet curLanas = new BitSet(); while (m_shutdown == false) { // Wait for a network address change event Win32NetBIOS.waitForNetworkAddressChange(); // Check if the monitor has been closed if (m_shutdown == true) continue; // Clear the current active LANA bit set curLanas.clear(); // Get the available LANA list int[] lanas = Win32NetBIOS.LanaEnumerate(); if (lanas != null) { // Check if there are any new LANAs available Win32NetBIOSSessionSocketHandler sessHandler = null; for (int i = 0; i < lanas.length; i++) { // Get the current LANA id, check if it's a known LANA int lana = lanas[i]; curLanas.set(lana, true); if (m_lanas.get(lana) == false) { // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println("[SMB] Win32 NetBIOS found new LANA, " + lana); // Create a single Win32 NetBIOS session handler using the specified LANA sessHandler = new Win32NetBIOSSessionSocketHandler(m_server, lana, hasDebug()); try { sessHandler.initializeSessionHandler(m_server); } catch (Exception ex) { // DEBUG if (Debug.EnableError && hasDebug()) { Debug.println( "[SMB] Win32 NetBIOS failed to create session handler for LANA " + lana); Debug.println(ex); } // Clear the session handler sessHandler = null; } // If the session handler was initialized successfully add it to the // SMB/CIFS server if (sessHandler != null) { // Add the session handler to the SMB/CIFS server // m_server.addSessionHandler(sessHandler); // Run the NetBIOS session handler in a seperate thread Thread nbThread = new Thread(sessHandler); nbThread.setName("Win32NB_Handler_" + lana); nbThread.start(); // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println("[SMB] Win32 NetBIOS created session handler on LANA " + lana); // Check if a host announcer should be enabled if (cifsConfig.hasWin32EnableAnnouncer()) { // Create a host announcer Win32NetBIOSHostAnnouncer hostAnnouncer = new Win32NetBIOSHostAnnouncer( sessHandler, cifsConfig.getDomainName(), cifsConfig.getWin32HostAnnounceInterval()); // Add the host announcer to the SMB/CIFS server list addHostAnnouncer(hostAnnouncer); hostAnnouncer.start(); // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println("[SMB] Win32 NetBIOS host announcer enabled on LANA " + lana); } // Set the LANA in the available LANA list, and set the current status // to online m_lanas.set(lana); m_lanaSts.set(lana, true); } } else { // Check if the LANA has just come back online if (m_lanaSts.get(lana) == false) { // Change the LANA status to indicate the LANA is back online m_lanaSts.set(lana, true); // Inform the listener that the LANA is back online if (m_listeners != null && lana < m_listeners.length && m_listeners[lana] != null) m_listeners[lana].lanaStatusChange(lana, true); // DEBUG if (Debug.EnableError && hasDebug()) Debug.println("[SMB] Win32 NetBIOS LANA online - " + lana); } } } // Check if there are any LANAs that have gone offline for (int i = 0; i < m_lanaSts.length(); i++) { if (curLanas.get(i) == false && m_lanaSts.get(i) == true) { // DEBUG if (Debug.EnableError && hasDebug()) Debug.println("[SMB] Win32 NetBIOS LANA offline - " + i); // Change the LANA status m_lanaSts.set(i, false); // Check if there is an associated listener for the LANA if (m_listeners != null && m_listeners[i] != null) { // Notify the LANA listener that the LANA is now offline m_listeners[i].lanaStatusChange(i, false); } } } } else if (m_lanaSts.length() == 0) { // No network devices, sleep for a while as waitForNetworkAddressChange() does not // wait // if there are no network devices try { Thread.sleep(10000); } catch (InterruptedException e) { } } } }
/** * Create a file segment to load/save the file data * * @param state FileState * @param params FileOpenParams * @param fname String * @param fid int * @param stid int * @param did int * @return CachedNetworkFile * @exception IOException */ private final CachedNetworkFile createNetworkFile( FileState state, FileOpenParams params, String fname, int fid, int stid, int did) throws IOException { // The file state is used to synchronize the creation of the file segment as there may be other // sessions opening the file at the same time. We have to be careful that only one thread // creates the // file segment. FileSegment fileSeg = null; CachedNetworkFile netFile = null; synchronized (state) { // Check if the file segment has been attached to the file state FileSegmentInfo fileSegInfo = (FileSegmentInfo) state.findAttribute(DBFileSegmentInfo); if (fileSegInfo == null) { // Check if we need to create a new temporary sub-drectory if (m_tempCount++ >= m_tempMax) createNewTempDirectory(); // Create a unique temporary file name StringBuffer tempName = new StringBuffer(); tempName.append(getTempFilePrefix()); tempName.append(fid); if (stid > 0) { tempName.append("_"); tempName.append(stid); // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println("## Temp file for stream ##"); } tempName.append(".tmp"); // Create a new file segment fileSegInfo = new FileSegmentInfo(); fileSeg = FileSegment.createSegment( fileSegInfo, tempName.toString(), m_curTempDir, params.isReadOnlyAccess() == false); // Add the segment to the file state cache state.addAttribute(DBFileSegmentInfo, fileSegInfo); // Check if the file is zero length, if so then set the file segment state to indicate it is // available DBFileInfo finfo = (DBFileInfo) state.findAttribute(FileState.FileInformation); if (finfo != null && finfo.getSize() == 0) fileSeg.setStatus(FileSegmentInfo.Available); } else { // Create the file segment to map to the existing temporary file fileSeg = new FileSegment(fileSegInfo, params.isReadOnlyAccess() == false); // Check if the temporary file exists, if not then create it File tempFile = new File(fileSeg.getTemporaryFile()); if (tempFile.exists() == false) { // Create the temporary file tempFile.createNewFile(); // Reset the file segment state to indicate a file load is required fileSeg.setStatus(FileSegmentInfo.Initial); } } // Create the new network file netFile = new CachedNetworkFile( fname, fid, stid, did, m_stateCache.getFileStateProxy(state), fileSeg, this); netFile.setGrantedAccess( params.isReadOnlyAccess() ? NetworkFile.READONLY : NetworkFile.READWRITE); netFile.setSequentialOnly(params.isSequentialAccessOnly()); netFile.setAttributes(params.getAttributes()); netFile.setFullName(params.getPath()); if (stid != 0) netFile.setStreamName(params.getStreamName()); } // Return the network file return netFile; }
/** * Store a file * * @param req FileRequest * @return int * @exception Exception */ public int storeFile(FileRequest req) throws Exception { // Check for a single file request int saveSts = StsError; SingleFileRequest saveReq = (SingleFileRequest) req; // Check if the temporary file still exists, if not then the file has been deleted from the // filesystem File tempFile = new File(saveReq.getTemporaryFile()); FileSegment fileSeg = findFileSegmentForPath(saveReq.getVirtualPath()); if (tempFile.exists() == false || fileSeg == null) { // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println(" Temporary file deleted"); // Return an error status return StsError; } // Run any file store processors runFileStoreProcessors(m_dbCtx, saveReq.getFileState(), fileSeg); // Update the segment status, and clear the updated flag fileSeg.setStatus(FileSegmentInfo.Saving); fileSeg.getInfo().setUpdated(false); // Save the file data try { // Save the file data and get the assigned object id String objectId = saveFileData(saveReq.getFileId(), saveReq.getStreamId(), fileSeg, req.getAttributes()); // Save the object id to the mapping database getDBObjectIdInterface().saveObjectId(saveReq.getFileId(), saveReq.getStreamId(), objectId); // Indicate that the save was successful saveSts = StsSuccess; } catch (DBException ex) { // DEBUG if (Debug.EnableError && hasDebug()) Debug.println(ex); // Indicate the file save failed saveSts = StsError; } catch (IOException ex) { // DEBUG if (Debug.EnableError && hasDebug()) Debug.println(ex); // Indicate the file save failed saveSts = StsError; } // Update the segment status if (saveSts == StsSuccess) fileSeg.setStatus(FileSegmentInfo.Saved, false); else fileSeg.setStatus(FileSegmentInfo.Error, false); // Return the data save status return saveSts; }
/** Run the CIFS request */ public void runRequest() { // Check if the session is still alive if (m_sess.isShutdown() == false) { SMBSrvPacket smbPkt = null; try { // Get the packet handler and read in the CIFS request WinsockNetBIOSPacketHandler pktHandler = (WinsockNetBIOSPacketHandler) m_sess.getPacketHandler(); smbPkt = pktHandler.readPacket(); // Clear the read in progress flag for the session m_sess.setReadInProgress(false); // DEBUG // Debug.println("[SMB] Read packet, sess=" + m_sess.getUniqueId() + " ,pkt=" + smbPkt); // If the request packet is not valid then close the session if (smbPkt == null) { // Close the session m_sess.hangupSession("Client closed socket"); } else { // Re-enable read events for this socket channel // m_reqHandler.requeueSocketEvent( m_socketEvent, // pktHandler.getSocket().getSocket()); } // Process the CIFS request m_sess.processPacket(smbPkt); smbPkt = null; // Process any asynchronous packets (oplock breaks and change notifications) int asyncCnt = m_sess.sendQueuedAsyncResponses(); // DEBUG if (asyncCnt > 0 && Debug.EnableInfo && m_sess.hasDebug(SMBSrvSession.DBG_SOCKET)) Debug.println( "Sent queued async packets (JNI/NIO) count=" + asyncCnt + ", sess=" + m_sess.getUniqueId() + ", addr=" + m_sess.getRemoteAddress().getHostAddress()); } catch (Throwable ex) { Debug.println(ex); } finally { // Make sure the request packet is returned to the pool if (smbPkt != null) m_sess.getPacketPool().releasePacket(smbPkt); } } }
/** * Close the network file * * @param sess SrvSession * @param netFile NetworkFile * @exception IOException */ public void closeFile(SrvSession sess, NetworkFile netFile) throws IOException { // Close the cached network file if (netFile instanceof CachedNetworkFile) { // Get the cached network file CachedNetworkFile cacheFile = (CachedNetworkFile) netFile; cacheFile.closeFile(); // Get the file segment details FileSegment fileSeg = cacheFile.getFileSegment(); // Check if the file data has been updated, if so then queue a file save if (fileSeg.isUpdated() && netFile.hasDeleteOnClose() == false) { // Set the modified date/time and file size for the file File tempFile = new File(fileSeg.getTemporaryFile()); netFile.setModifyDate(tempFile.lastModified()); netFile.setFileSize(tempFile.length()); // Queue a file save request to save the data back to the repository, if not already queued if (fileSeg.isSaveQueued() == false) { // Create a file save request for the updated file segment SingleFileRequest fileReq = new SingleFileRequest( FileRequest.SAVE, cacheFile.getFileId(), cacheFile.getStreamId(), fileSeg.getInfo(), netFile.getFullName(), cacheFile.getFileState()); // Check if there are any attributes to be added to the file request if (hasRequiredAttributes() && sess != null) { // Check if the user name is required if (m_reqAttributes.containsString(FileRequest.AttrUserName)) { // Add the user name attribute ClientInfo cInfo = sess.getClientInformation(); String userName = ""; if (cInfo != null && cInfo.getUserName() != null) userName = cInfo.getUserName(); fileReq.addAttribute(new NameValue(FileRequest.AttrUserName, userName)); } // Check if the protocol type is required if (m_reqAttributes.containsString(FileRequest.AttrProtocol)) { // Add the protocol type attribute fileReq.addAttribute(new NameValue(FileRequest.AttrProtocol, sess.getProtocolName())); } } // Set the file segment status fileSeg.setStatus(FileSegmentInfo.SaveWait, true); // Queue the file save request queueFileRequest(fileReq); } else if (Debug.EnableInfo && hasDebug()) { // DEBUG Debug.println("## FileLoader Save already queued for " + fileSeg); } } // Update the cache timeout for the temporary file if there are no references to the file. If // the file was // opened for sequential access only it will be expired quicker. else if (cacheFile.getFileState().getOpenCount() == 0) { // If the file was opened for sequential access only then we can delete it from the // temporary area // sooner long tmo = System.currentTimeMillis(); if (cacheFile.isSequentialOnly()) tmo += SequentialFileExpire; else tmo += m_stateCache.getFileStateExpireInterval(); // Set the file state expiry, the local file data will be deleted when the file state // expires (if there // are still no references to the file). cacheFile.getFileState().setExpiryTime(tmo); } // If the database is not online and the file is marked for delete then queue a delete file // request to do // the // delete when the database is back online if (m_dbCtx.isAvailable() == false && netFile.hasDeleteOnClose()) { // Queue an offline delete request for the file DeleteFileRequest deleteReq = new DeleteFileRequest( cacheFile.getFileId(), cacheFile.getStreamId(), fileSeg.getTemporaryFile(), cacheFile.getFullNameStream(), cacheFile.getFileState()); m_dbCtx.addOfflineFileDelete(deleteReq); // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println("## FileLoader queued offline delete, " + deleteReq); } } }
/** * Create a network file for the specified file * * @param params FileOpenParams * @param fid int * @param stid int * @param did int * @param create boolean * @param dir boolean * @exception IOException * @exception FileNotFoundException */ public NetworkFile openFile( FileOpenParams params, int fid, int stid, int did, boolean create, boolean dir) throws IOException, FileNotFoundException { // Split the file name to get the name only String[] paths = FileName.splitPath(params.getPath()); String name = paths[1]; if (params.isStream()) name = name + params.getStreamName(); // Find, or create, the file state for the file/directory FileState fstate = m_stateCache.findFileState(params.getFullPath(), true); fstate.setExpiryTime(System.currentTimeMillis() + m_stateCache.getFileStateExpireInterval()); // Check if the file is a directory DBNetworkFile netFile = null; if (dir == false) { // Create the network file and associated file segment CachedNetworkFile cacheFile = createNetworkFile(fstate, params, name, fid, stid, did); netFile = cacheFile; // Check if the file is being opened for sequential access and the data has not yet been // loaded FileSegment fileSeg = cacheFile.getFileSegment(); if (create == true || params.isOverwrite() == true) { // Indicate that the file data is available, this is a new file or the existing file is // being // overwritten so there is no data to load. fileSeg.setStatus(FileSegmentInfo.Available); } else if (params.isSequentialAccessOnly() && fileSeg.isDataLoading() == false) { synchronized (cacheFile.getFileState()) { // Create the temporary file cacheFile.openFile(create); cacheFile.closeFile(); // Queue a file data load request if (fileSeg.isDataLoading() == false) queueFileRequest( new SingleFileRequest( FileRequest.LOAD, cacheFile.getFileId(), cacheFile.getStreamId(), fileSeg.getInfo(), cacheFile.getFullName(), fstate)); } // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println( "ObjIdLoader Queued file load, SEQUENTIAL access, file=" + cacheFile.getFullName()); } } else { // Create a placeholder network file for the directory netFile = new DirectoryNetworkFile(name, fid, did, m_stateCache.getFileStateProxy(fstate)); // Debug if (Debug.EnableInfo && hasDebug()) Debug.println("ObjIdLoader.openFile() DIR name=" + name + ", state=" + fstate); } // Return the network file return netFile; }
/** * Start the file loader * * @param ctx DeviceContext */ public void startLoader(DeviceContext ctx) { // Get the file state cache from the context m_stateCache = getContext().getStateCache(); // Add the file loader as a file state listener so that we can cleanup temporary data files m_stateCache.addStateListener(this); // Get the database interface DBQueueInterface dbQueue = null; if (getContext().getDBInterface() instanceof DBQueueInterface) dbQueue = (DBQueueInterface) getContext().getDBInterface(); else throw new RuntimeException("Database interface does not implement queue interface"); // Perform a queue cleanup before starting the thread pool. This will check the temporary cache // area and delete // files that are not part of a queued save/transaction save request. FileRequestQueue recoveredQueue = null; try { // Cleanup the temporary cache area and queue recoveredQueue = dbQueue.performQueueCleanup(m_tempDir, TempDirPrefix, TempFilePrefix, JarFilePrefix); // DEBUG if (recoveredQueue != null && Debug.EnableInfo && hasDebug()) Debug.println( "[DBLoader] Cleanup recovered " + recoveredQueue.numberOfRequests() + " pending save files"); } catch (DBException ex) { // DEBUG if (Debug.EnableError && hasDebug()) Debug.println(ex); } // Check if there are any file save requests pending in the queue database FileRequestQueue saveQueue = new FileRequestQueue(); try { dbQueue.loadFileRequests(1, FileRequest.SAVE, saveQueue, 1); } catch (DBException ex) { } // Create the background load/save thread pool m_backgroundLoader = new BackgroundLoadSave("DBLdr", dbQueue, m_stateCache, this); m_backgroundLoader.setReadWorkers(m_readWorkers); m_backgroundLoader.setWriteWorkers(m_writeWorkers); m_backgroundLoader.setDebug(m_threadDebug); // Start the file loader threads, start the request loading if there are pending file save // requests m_backgroundLoader.startThreads(saveQueue.numberOfRequests()); // Queue the recovered file save requests if (recoveredQueue != null) { // Queue the file save requests while (recoveredQueue.numberOfRequests() > 0) queueFileRequest(recoveredQueue.removeRequestNoWait()); } }
/** * File state has expired. The listener can control whether the file state is removed from the * cache, or not. * * @param state FileState * @return true to remove the file state from the cache, or false to leave the file state in the * cache */ public boolean fileStateExpired(FileState state) { // Check if the file state has an associated file segment FileSegmentInfo segInfo = (FileSegmentInfo) state.findAttribute(DBFileSegmentInfo); boolean expire = true; if (segInfo != null) { // Check if the file has a request queued if (segInfo.isQueued() == false) { try { // Delete the temporary file and reset the segment status so that the data may be loaded // again // if required. if (segInfo.hasStatus() != FileSegmentInfo.Initial) { // Delete the temporary file try { segInfo.deleteTemporaryFile(); } catch (IOException ex) { // DEBUG if (Debug.EnableError) { Debug.println("Delete temp file error: " + ex.toString()); File tempFile = new File(segInfo.getTemporaryFile()); Debug.println( " TempFile file=" + tempFile.getAbsolutePath() + ", exists=" + tempFile.exists()); Debug.println(" FileState state=" + state); Debug.println(" FileSegmentInfo segInfo=" + segInfo); Debug.println(" StateCache size=" + m_stateCache.numberOfStates()); } } // Remove the file segment, reset the file segment back to the initial state state.removeAttribute(DBFileSegmentInfo); segInfo.setStatus(FileSegmentInfo.Initial); // Reset the file state to indicate file data load required state.setDataStatus(FileState.FILE_LOADWAIT); // Check if the temporary file sub-directory is now empty, and it is not the current // temporary // sub-directory if (segInfo.getTemporaryFile().startsWith(m_curTempName) == false) { // Check if the sub-directory is empty File tempFile = new File(segInfo.getTemporaryFile()); File subDir = tempFile.getParentFile(); String[] files = subDir.list(); if (files == null || files.length == 0) { // Delete the sub-directory subDir.delete(); // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println( "$$ Deleted temporary directory " + subDir.getPath() + ", curTempName=" + m_curTempName + ", tempFile=" + segInfo.getTemporaryFile()); } } // Indicate that the file state should not be deleted expire = false; // Debug if (Debug.EnableInfo && hasDebug()) Debug.println( "$$ Deleted temporary file " + segInfo.getTemporaryFile() + " [EXPIRED] $$"); } // If the file state is not to be deleted reset the file state expiration timer if (expire == false) state.setExpiryTime( System.currentTimeMillis() + m_stateCache.getFileStateExpireInterval()); } catch (Exception ex) { // DEBUG if (Debug.EnableError) { Debug.println("$$ " + ex.toString()); Debug.println(" state=" + state); } } } else { // DEBUG if (hasDebug()) { File tempFile = new File(segInfo.getTemporaryFile()); if (tempFile.exists() == false) { Debug.println("== Skipped file state, queued " + state); Debug.println(" File seg=" + segInfo); } } // File state is queued, do not expire expire = false; } } else if (state.isDirectory()) { // Nothing to do when it's a directory, just allow it to expire expire = true; } else if (Debug.EnableInfo && hasDebug()) Debug.println("$$ Expiring state=" + state); // Return true if the file state can be expired return expire; }
/** * Load a file * * @param req FileRequest * @return int * @exception Exception */ public int loadFile(FileRequest req) throws Exception { // DEBUG long startTime = 0L; SingleFileRequest loadReq = (SingleFileRequest) req; if (Debug.EnableInfo && hasDebug()) { Debug.println( "## ObjIdLoader loadFile() req=" + loadReq.toString() + ", thread=" + Thread.currentThread().getName()); startTime = System.currentTimeMillis(); } // Check if the temporary file still exists, if not then the file has been deleted from the // filesystem File tempFile = new File(loadReq.getTemporaryFile()); FileSegment fileSeg = findFileSegmentForPath(loadReq.getVirtualPath()); if (tempFile.exists() == false || fileSeg == null) { // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println(" Temporary file deleted"); // Return an error status fileSeg.setStatus(FileSegmentInfo.Error, false); return StsError; } // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println( "## ObjIdLoader fileSeg=" + fileSeg.getTemporaryFile() + ", virtPath=" + loadReq.getVirtualPath()); // Load the file data int loadSts = StsRequeue; String objectId = null; int fileId = loadReq.getFileId(); int strmId = loadReq.getStreamId(); try { // Update the segment status fileSeg.setStatus(FileSegmentInfo.Loading); // Get the object id for the file objectId = getDBObjectIdInterface().loadObjectId(fileId, strmId); if (objectId != null) { // Load the file data loadFileData(fileId, strmId, objectId, fileSeg); // Set the load status loadSts = StsSuccess; // DEBUG if (Debug.EnableInfo && hasDebug()) { long endTime = System.currentTimeMillis(); Debug.println( "## ObjIdLoader loaded fid=" + loadReq.getFileId() + ", stream=" + loadReq.getStreamId() + ", time=" + (endTime - startTime) + "ms"); } } else { // DEBUG if (Debug.EnableInfo && hasDebug()) Debug.println( "## ObjIdLoader No object id mapping for fid=" + loadReq.getFileId() + ", stream=" + loadReq.getStreamId()); // Indicate a load success loadSts = StsSuccess; } } catch (DBException ex) { // DEBUG if (Debug.EnableError && hasDebug()) Debug.println(ex); // Indicate the file load failed loadSts = StsError; } catch (FileOfflineException ex) { // DEBUG if (Debug.EnableError && hasDebug()) Debug.println(ex); // Indicate the file load failed loadSts = StsError; } catch (IOException ex) { // DEBUG if (Debug.EnableError && hasDebug()) Debug.println(ex); // Indicate the file load failed loadSts = StsRequeue; } catch (Exception ex) { // DEBUG if (Debug.EnableError && hasDebug()) Debug.println(ex); // Indicate the file load failed loadSts = StsError; } // Clear the last modified date/time of the temporary file to indicate it has not been updated tempFile.setLastModified(0L); // Check if the file was loaded successfully if (loadSts == StsSuccess) { // Signal that the file data is available fileSeg.signalDataAvailable(); // Update the file status fileSeg.setStatus(FileSegmentInfo.Available, false); // Run the file load processors runFileLoadedProcessors(getContext(), loadReq.getFileState(), fileSeg); } else if (loadSts == StsError) { // Set the file status to indicate error to any client reading threads fileSeg.setStatus(FileSegmentInfo.Error, false); // Wakeup any threads waiting on data for this file fileSeg.setReadableLength(0L); fileSeg.signalDataAvailable(); // Delete the temporary file fileSeg.deleteTemporaryFile(); } // Return the load file status return loadSts; }
/** * Process a \PIPE\LANMAN transaction request. * * @param tbuf Transaction setup, parameter and data buffers * @param sess SMB server session that received the transaction. * @param trans Packet to use for reply * @return true if the transaction has been handled, else false. * @exception java.io.IOException The exception description. * @exception org.alfresco.aifs.smb.SMBSrvException The exception description. */ public static final boolean processRequest( TransactBuffer tbuf, SMBSrvSession sess, SMBSrvPacket trans) throws IOException, SMBSrvException { // Create a transaction packet SMBSrvTransPacket tpkt = new SMBSrvTransPacket(trans.getBuffer()); // Get the transaction command code, parameter descriptor and data descriptor strings from // the parameter block. DataBuffer paramBuf = tbuf.getParameterBuffer(); int cmd = paramBuf.getShort(); String prmDesc = paramBuf.getString(false); String dataDesc = paramBuf.getString(false); // Debug if (Debug.EnableInfo && sess.hasDebug(SMBSrvSession.DBG_IPC)) sess.debugPrintln( "\\PIPE\\LANMAN\\ transact request, cmd=" + cmd + ", prm=" + prmDesc + ", data=" + dataDesc); // Call the required transaction handler boolean processed = false; switch (cmd) { // Share case PacketType.RAPShareEnum: processed = procNetShareEnum(sess, tbuf, prmDesc, dataDesc, tpkt); break; // Get share information case PacketType.RAPShareGetInfo: processed = procNetShareGetInfo(sess, tbuf, prmDesc, dataDesc, tpkt); break; // Workstation information case PacketType.RAPWkstaGetInfo: processed = procNetWkstaGetInfo(sess, tbuf, prmDesc, dataDesc, tpkt); break; // Server information case PacketType.RAPServerGetInfo: processed = procNetServerGetInfo(sess, tbuf, prmDesc, dataDesc, tpkt); break; // Print queue information case PacketType.NetPrintQGetInfo: processed = procNetPrintQGetInfo(sess, tbuf, prmDesc, dataDesc, tpkt); break; // No handler default: // Debug if (Debug.EnableInfo && sess.hasDebug(SMBSrvSession.DBG_IPC)) sess.debugPrintln( "No handler for \\PIPE\\LANMAN\\ request, cmd=" + cmd + ", prm=" + prmDesc + ", data=" + dataDesc); break; } // Check if the transaction packet has allocated an associated packet from the pool, we need to // copy the associated packet // to the outer request packet so that it is released back to the pool. if (tpkt.hasAssociatedPacket()) { Debug.println( "[SMB] PipeLanManHandler allocated associated packet, len=" + tpkt.getAssociatedPacket().getBufferLength()); // Copy the associated packet to the outer request packet trans.setAssociatedPacket(tpkt.getAssociatedPacket()); tpkt.setAssociatedPacket(null); } // Return the transaction processed status return processed; }