Esempio n. 1
0
static int
put_file_func (CameraFilesystem *fs, const char *folder, const char *filename, CameraFile *file,
	       void *data, GPContext *context)
{
	Camera *camera = data;

	/*
	 * Upload the file to the camera. Use gp_file_get_data_and_size etc.
	 */
	int result = -EPROTO;
	time_t startTime = time(NULL);
	enum {
		START,
		DATA,
		END,
		FINISHED
	} state;
	int src = -1;
	int r;
	int update = 0;
	struct stat srcStat;
	__u64 fileSize;
	__u64 byteCount = 0;
	const char *filename;
	char *path;
	struct tf_packet reply;

	if(0 != fstat(src, &srcStat))
	{
		gp_log (GP_LOG_ERROR, "topfield", "ERROR: Can not examine source file: %s\n",
			strerror(errno));
		result = errno;
		goto out;
	}

	fileSize = srcStat.st_size;
	if(fileSize == 0)
	{
		gp_log (GP_LOG_ERROR, "topfield", "ERROR: Source file is empty - not transfering.\n");
		result = -ENODATA;
		goto out;
	}

	path = get_path (camera, folder, filename);
	r = send_cmd_hdd_file_send(camera, PUT, path, context);
	if(r < 0)
		goto out;

	state = START;
	while(0 < get_tf_packet(camera, &reply, context)) {
		update = (update + 1) % 16;
		switch (get_u32(&reply.cmd)) {
		case SUCCESS:
			switch (state) {
			case START: {
				/* Send start */
				struct typefile *tf = (struct typefile *) packet.data;

				put_u16(&packet.length, PACKET_HEAD_SIZE + 114);
				put_u32(&packet.cmd, DATA_HDD_FILE_START);
				time_to_tfdt(srcStat.st_mtime, &tf->stamp);
				tf->filetype = 2;
				put_u64(&tf->size, srcStat.st_size);
				strncpy((char *) tf->name, path, 94);
				tf->name[94] = '\0';
				tf->unused = 0;
				tf->attrib = 0;
				gp_log (GP_LOG_DEBUG, "topfield", "%s: DATA_HDD_FILE_START\n", __func__);
				r = send_tf_packet(camera, &packet, context);
				if(r < 0)
				{
					gp_log (GP_LOG_ERROR, "topfield", "ERROR: Incomplete send.\n");
					goto out;
				}
				state = DATA;
				break;
			}

			case DATA: {
				int payloadSize = sizeof(packet.data) - 9;
				ssize_t w = read(src, &packet.data[8], payloadSize);

				/* Detect a Topfield protcol bug and prevent the sending of packets
				   that are a multiple of 512 bytes. */
				if((w > 4) && (((((PACKET_HEAD_SIZE + 8 + w) + 1) & ~1) % 0x200) == 0)) {
					lseek(src, -4, SEEK_CUR);
					w -= 4;
					payloadSize -= 4;
				}

				put_u16(&packet.length, PACKET_HEAD_SIZE + 8 + w);
				put_u32(&packet.cmd, DATA_HDD_FILE_DATA);
				put_u64(packet.data, byteCount);
				byteCount += w;

				/* Detect EOF and transition to END */
				if((w < 0) || (byteCount >= fileSize)) {
					state = END;
				}

				if(w > 0) {
					gp_log (GP_LOG_DEBUG, "topfield", "%s: DATA_HDD_FILE_DATA\n", __func__);
					r = send_tf_packet(camera, &packet, context);
					if(r < w) {
						gp_log (GP_LOG_ERROR, "topfield", "ERROR: Incomplete send.\n");
						goto out;
					}
				}

				if(!update && !quiet) {
					progressStats(fileSize, byteCount, startTime);
				}
				break;
			}

			case END:
				/* Send end */
				put_u16(&packet.length, PACKET_HEAD_SIZE);
				put_u32(&packet.cmd, DATA_HDD_FILE_END);
				gp_log (GP_LOG_DEBUG, "topfield", "%s: DATA_HDD_FILE_END\n", __func__);
				r = send_tf_packet(camera, &packet, context);
				if(r < 0) {
					gp_log (GP_LOG_ERROR, "topfield", "ERROR: Incomplete send.\n");
					goto out;
				}
				state = FINISHED;
				break;

			case FINISHED:
				result = 0;
				goto out;
				break;
			}
			break;

		case FAIL:
			gp_log (GP_LOG_ERROR, "topfield", "ERROR: Device reports %s\n", decode_error(&reply));
			goto out;
			break;

		default:
			gp_log (GP_LOG_ERROR, "topfield", "ERROR: Unhandled packet (%d)\n", get_u32(&reply.cmd));
			break;
		}
	}
	finalStats(byteCount, startTime);
out:
	close(src);
	return result;
}
Esempio n. 2
0
int do_hdd_file_get(int fd, char *srcPath, char *dstPath)
{
    int result = -EPROTO;
    time_t startTime = time(NULL);
    enum
    {
        START,
        DATA,
        ABORT
    } state;
    int dst = -1;
    int r;
    int update = 0;
    __u64 byteCount = 0;
    struct utimbuf mod_utime_buf = { 0, 0 };

    dst = open64(dstPath, O_WRONLY | O_CREAT | O_TRUNC,
                 S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH);
    if(dst < 0)
    {
        fprintf(stderr, "ERROR: Can not open destination file: %s\n",
                strerror(errno));
        return errno;
    }

    r = send_cmd_hdd_file_send(fd, GET, srcPath);
    if(r < 0)
    {
        goto out;
    }

    state = START;
    while(0 < (r = get_tf_packet(fd, &reply)))
    {
        update = (update + 1) % 16;
        switch (get_u32(&reply.cmd))
        {
            case DATA_HDD_FILE_START:
                if(state == START)
                {
                    struct typefile *tf = (struct typefile *) reply.data;

                    byteCount = get_u64(&tf->size);
                    mod_utime_buf.actime = mod_utime_buf.modtime =
                        tfdt_to_time(&tf->stamp);

                    send_success(fd);
                    state = DATA;
                }
                else
                {
                    fprintf(stderr,
                            "ERROR: Unexpected DATA_HDD_FILE_START packet in state %d\n",
                            state);
                    send_cancel(fd);
                    state = ABORT;
                }
                break;

            case DATA_HDD_FILE_DATA:
                if(state == DATA)
                {
                    __u64 offset = get_u64(reply.data);
                    __u16 dataLen =
                        get_u16(&reply.length) - (PACKET_HEAD_SIZE + 8);
                    ssize_t w;

                    if(!update && !quiet)
                    {
                        progressStats(byteCount, offset + dataLen, startTime);
                    }

                    if(r < get_u16(&reply.length))
                    {
                        fprintf(stderr,
                                "ERROR: Short packet %d instead of %d\n", r,
                                get_u16(&reply.length));
                        /* TODO: Fetch the rest of the packet */
                    }

                    w = write(dst, &reply.data[8], dataLen);
                    if(w < dataLen)
                    {
                        /* Can't write data - abort transfer */
                        fprintf(stderr, "ERROR: Can not write data: %s\n",
                                strerror(errno));
                        send_cancel(fd);
                        state = ABORT;
                    }
                }
                else
                {
                    fprintf(stderr,
                            "ERROR: Unexpected DATA_HDD_FILE_DATA packet in state %d\n",
                            state);
                    send_cancel(fd);
                    state = ABORT;
                }
                break;

            case DATA_HDD_FILE_END:
                send_success(fd);
                result = 0;
                goto out;
                break;

            case FAIL:
                fprintf(stderr, "ERROR: Device reports %s\n",
                        decode_error(&reply));
                send_cancel(fd);
                state = ABORT;
                break;

            case SUCCESS:
                goto out;
                break;

            default:
                fprintf(stderr, "ERROR: Unhandled packet (cmd 0x%x)\n",
                        get_u32(&reply.cmd));
        }
    }
    utime(dstPath, &mod_utime_buf);
    finalStats(byteCount, startTime);

  out:
    close(dst);
    return result;
}
Esempio n. 3
0
void Sem::ContainSim::run( void )
{
    // Status names
    const char *StatusName[] =
    {
        "Unreported",
        "Reported",
        "Attacked",
        "Contained",
        "Overrun",
        "Exhausted",
        "Sim Overflow",
        "Size Limit Exceeded",
        "Time Limit Exceeded"
    };
    
    const char *TacticName[] =
    {
        "Head",
        "Rear"
    };
    double at, elapsed, factor;

    // Log levels : 0=none, 1=major events, 2=stepwise
    int logLevel = 0;
    // Repeat simulation until [m_minSteps::m_maxSteps] steps achieved,
    // or if retry==TRUE, until sufficient resources are able to contain fire
    double area, dx, dy, suma, sumb, sumDT;
    double totalArea;
//    double maxArea = 500.0;
    bool rerun = true;
    bool MAXSTEPS_EXCEEDED=false;
    m_pass = 0;
    
    
    while ( rerun )
    {
        m_left->containLog( ( logLevel >= 1 ), "\nPass %d Begins:\n", m_pass );
        // Simulate until forces overrun, fire contained, or maxSteps reached
        int iLeft = 0;              // First index of left half values
        m_u[iLeft] = m_left->m_u;
        m_h[iLeft] = m_left->m_h;
        m_x[iLeft] = m_left->m_x;
        m_y[iLeft] = m_left->m_y;
        //int iRight = m_maxSteps;  // First index of right half values
        elapsed = m_left->m_attackTime;
        m_left->containLog( ( logLevel == 2 ),
            "%d: u=%12.10f,  h=%12.10f,  t=%f\n",
            iLeft, m_left->m_u, m_left->m_h, elapsed );

        // This is the main simulation loop!
        m_finalSweep = m_finalLine = m_finalPerim = 0.0;
        totalArea=0.0;
        suma = sumb = sumDT = 0.0;
        while ( m_left->m_status != Sem::Contain::Overrun
             && m_left->m_status != Sem::Contain::Contained
             && m_left->m_step    < m_maxSteps
             && totalArea <  m_maxFireSize
             && m_left->m_currentTime < m_maxFireTime		 		// MAF
             && m_left->m_currentTime < m_left->m_exhausted)		// MAF
        {
            // Store angle and head position in the proper array element
            m_left->step();

            // Store the new angle, head position, and coordinate values
            iLeft++;
                       
            m_u[iLeft] = m_left->m_u;
            m_h[iLeft] = m_left->m_h;
            m_x[iLeft] = m_left->m_x;
            m_y[iLeft] = m_left->m_y;
            elapsed = m_left->m_currentTime;//m_time; // MAF
//            m_left->containLog( (logLevel == 2 ),
//                "%d: u=%12.10f,  h=%12.10f,  t=%12.10f\n",
//                iLeft, m_u[iLeft], m_h[iLeft], elapsed );
            // Update the extent
            m_xMin = ( m_x[iLeft] < m_xMin ) ? m_x[iLeft] : m_xMin;
            m_xMax = ( m_x[iLeft] > m_xMax ) ? m_x[iLeft] : m_xMax;
            m_yMax = ( m_y[iLeft] > m_yMax ) ? m_y[iLeft] : m_yMax;

            // Line constructed and area swept during this simulation step
            dy = fabs( m_y[iLeft-1] - m_y[iLeft] );
            dx = fabs( m_x[iLeft-1] - m_x[iLeft] );
            m_p[iLeft-1] = sqrt( ( dy * dy ) + ( dx * dx ) );
            // Accumulate line constructed for BOTH flanks (ch)
            m_finalLine += 2.0 * m_p[iLeft-1];
            // Accumulate area of containment (apply trapazoidal rule)
            suma += ( m_y[iLeft-1] * m_x[iLeft] );
            sumb += ( m_x[iLeft-1] * m_y[iLeft] );
            area = ( suma > sumb )
                 ? ( 0.5 * ( suma - sumb ) )
                 : ( 0.5 * ( sumb - suma ) );
			
			// Calculate the area using the trapizoidal rule
			sumDT = 0;
			for ( int i = 1; i <= iLeft; i++ )	
				sumDT = (m_x[i] - m_x[i-1]) * (m_y[i] + m_y[i-1]) + sumDT;

			if ( sumDT < 0 )
				sumDT = -1.0 * sumDT;
				
			area = sumDT * .5;
			
			// Add in the area for the uncontained portion of the fire DT 1/2013
			double UCarea = UncontainedArea( m_h[iLeft], fireLwRatioAtReport(), m_x[iLeft], m_y[iLeft], tactic() );
			area = area + UCarea;
			
            // Accumulate area for BOTH flanks (ac)
            m_a[iLeft-1] = 0.2 * area;
            totalArea = m_a[iLeft-1];
            m_left->containLog( (logLevel == 2 ),
                "%d: u=%12.10f,  h=%12.10f,  x=%12.10f, y=%12.10f, t=%12.10f, UCA=%12.10f, CA=%12.1f, TA=%12.10f, TP=%12.10f\n",
                iLeft, m_u[iLeft], m_h[iLeft], m_x[iLeft], m_y[iLeft], elapsed, UCarea*0.2, (area-UCarea)*0.2, totalArea, m_finalLine );
        }
        // BEHAVEPLUS FIX: Adjust the last x-coordinate for contained head attacks
        if ( m_left->m_status == Sem::Contain::Contained
          && m_left->m_tactic == Sem::Contain::HeadAttack )
        {
            m_x[m_left->m_step] -= 2. * m_left->m_attackDist;
		}

        suma += ( m_y[m_left->m_step] * m_x[0] );
        sumb += ( m_x[m_left->m_step] * m_y[0] );
        m_finalSweep = ( suma > sumb )
                     ? ( 0.5 * ( suma - sumb ) )
                     : ( 0.5 * ( sumb - suma ) );
        m_finalSweep *= 0.20;

		// Calculate the area using the trapizoidal rule
		sumDT = 0;
		for ( int i = 1; i <= m_left->m_step; i++ )	
			sumDT = (m_x[i] - m_x[i-1]) * (m_y[i] + m_y[i-1]) + sumDT;

		if ( sumDT < 0 )
			sumDT = -1.0 * sumDT;
				
		area = sumDT * .5;

		// Add in the area for the uncontained portion of the fire DT 1/2013
		double UCarea = UncontainedArea( m_h[m_left->m_step], fireLwRatioAtReport(), m_x[m_left->m_step], m_y[m_left->m_step], tactic() );
		area = area + UCarea;
			
        // Accumulate area for BOTH flanks (ac)
        m_finalSweep = 0.2 * area;

        // Cases 1-3: forces are overrun by fire...
        if ( m_left->m_status == Sem::Contain::Overrun )
        {
            // Case 1: No retry allowed, simulation is complete
            if ( ! m_retry )
            {
                rerun = false;
                m_left->containLog( ( logLevel >= 1 ),
                    "Pass %d Result 1: Overrun\n"
                    "    - resources overrun at %3.1f minutes (%d steps)\n"
                    "    - re-run is FALSE\n"
                    "    - FIRE ESCAPES at %3.1f minutes\n",
                    m_pass, elapsed, m_left->m_step, elapsed );
            }
            // Case 2: Try initial attack after more forces have arrived
            else if ( ( at = m_force->nextArrival( m_left->m_attackTime,
                m_left->m_exhausted, LeftFlank ) ) > 0.01 )
            {
                m_left->containLog( ( logLevel >= 1 ),
                    "Pass %d Result 2: Retry\n"
                    "    - resources overrun at %3.1f minutes (%d steps)\n"
                    "    - Pass %d will wait for IA until %3.1f minutes\n"
                    "    - when line building rate will be %3.2f ch/h\n"
                    "    - RE-RUN\n",
                    m_pass, elapsed, m_left->m_step, m_pass+1,
                    at, m_force->productionRate( at, LeftFlank ) );
                m_pass++;
                m_left->m_attackTime = at;
                m_left->reset();
                rerun = true;
            }
            // Case 3: All resources exhausted
            else
            {
                // No more forces available, so we're done
                rerun = false;
                m_left->containLog( ( logLevel >= 1 ),
                    "Pass %d Result 3: Exhausted\n"
                    "    - resources exhausted at %3.1f minutes (%d steps)\n"
                    "    - FIRE ESCAPES at %3.1f minutes\n",
                    m_pass, elapsed, m_left->m_step, elapsed );
                m_left->m_status = Sem::Contain::Exhausted;
            }
        }
        
        // New Case 3: to set rerun to false when the outrun fires are 
        // removed  DT 7/8/10
        else if (m_left->m_currentTime >= m_left->m_exhausted)
        {
                // No more forces available, so we're done
                rerun = false;
                m_left->containLog( ( logLevel >= 1 ),
                    "Pass %d Result 3: Exhausted\n"
                    "    - resources exhausted at %3.1f minutes (%d steps)\n"
                    "    - FIRE ESCAPES at %3.1f minutes\n",
                    m_pass, elapsed, m_left->m_step, elapsed );
                m_left->m_status = Sem::Contain::Exhausted;
        }
        
        // Case 4: maximum number of steps was exceeded
        // (should never happen as long as m_distStep is calculated from
        // m_exhausted, m_reportRate, ... )
        else if ( iLeft >= m_maxSteps )
        {
            // Make the distance step size bigger and rerun the simulation
            // MAF 9/29/2010, remove factor calc, just reverse previous factor and redo
		  //factor = (double) m_maxSteps / (double) m_minSteps;
		  factor = 2.0;	
            m_left->containLog( ( logLevel >= 1 ),
                "Pass %d Result 4: Less Precision\n"
                "    - fire uncontained at %f minutes\n"
                "    - %d steps exceeds maximum of %d steps\n"
                "    - increasing Eta from %f to %f chains for next Pass %d\n"
                "    - RE-RUN\n",
                m_pass, elapsed, m_left->m_step, m_maxSteps,
                m_left->m_distStep, (m_left->m_distStep*factor), m_pass+1 );
            m_left->m_distStep *= factor;
            m_pass++;
            
		  if(MAXSTEPS_EXCEEDED==false)
		  {	m_left->reset();
			rerun = true;
		  }
		  else
			rerun=false;
		  MAXSTEPS_EXCEEDED=true;
        }
        // Cases 5-6: fire is contained...
        else if ( m_left->m_status == Sem::Contain::Contained )
        {
            // Case 5: there were insufficient simulation steps...
            if (  iLeft < m_minSteps && MAXSTEPS_EXCEEDED==false) // MAF 9/29/2010 added MAXSTEPS_EXCEEDED check
            {
                // Make the distance step size smaller and rerun the simulation
                // Need to make sure that with the new smaller step we will not
                // exceed the MAX steps - otherwise we end up looping
                // Diane 08/10 decrease the step size at a slower rate  
                factor = 0.5 ; // (double) ( m_left->m_step + 1 ) / ((double) m_minSteps*1.25);
                m_left->containLog( ( logLevel >= 1 ),
                    "Pass %d Result 5: More Precision\n"
                    "    - fire contained at %3.1f minutes\n"
                    "    - %d steps is less than minimum of %d steps\n"
                    "    - decreasing Eta from %f to %f chains for Pass %d\n"
                    "    - RE-RUN\n",
                    m_pass, elapsed, m_left->m_step, m_minSteps,
                    m_left->m_distStep, (m_left->m_distStep * factor), m_pass+1 );
                m_left->m_distStep *= factor;
                m_pass++;
                
                // Diane 08/10 decrease the step size at a slower rate 
                //if(m_pass<10)
                //{
                	m_left->reset();
                	rerun = true;
                //}
                //else
                //	rerun=false;
            }
            // Case 6: fire contained within the simulation step range
            else
            {
                m_left->containLog( ( logLevel >= 1 ),
                    "Pass %d Result 6: Contained\n"
                    "    - FIRE CONTAINED at %3.1f minutes (%d steps)\n",
                    m_pass, elapsed, m_left->m_step );
                rerun = false;
            }
        }
        //Add check for maximum Area
        else if(totalArea >= m_maxFireSize){    	        
                at = m_force->nextArrival( m_left->m_attackTime,
                m_left->m_exhausted, LeftFlank );
        /*//////////////////////////////////////////////////////////////////////////
        	Removed DT 6/2010 Stop when fire exceeds maximum size
                if (at > .01){
                	rerun = true;
                	m_left->m_attackTime = at;
                	m_left->containLog( ( logLevel >= 1 ),
                    "Pass %d Result max area exceeded: Retry\n"
                    "    - Maximum Area of %d exceeded at %3.1f minutes (%d steps)\n"
                    "    - Pass %d will wait for IA until %3.1f minutes\n"
                    "    - when line building rate will be %3.2f ch/h\n"
                    "    - RE-RUN\n",
                    m_pass,m_maxFireSize, elapsed, m_left->m_step, m_pass+1,
                    at, m_force->productionRate( at, LeftFlank ) );
               	 	m_pass++;               
                	m_left->reset();               	
                }else{
         */
//                	cout << m_pass << " "  << totalArea << " " <<m_maxFireSize << " " << "\n";
 					m_left->containLog( ( logLevel >= 1 ),
                    "Pass %d total fire size of %3.2f acres exceeds max fire size of %d acres at time %3.1f minutes\n",                    
                    m_pass, totalArea, m_maxFireSize, elapsed);               	
                	rerun = false;
                	//Production rate is not longer increasing
                	m_left->m_status = Sem::Contain::SizeLimitExceeded;
 //               } 
       
        }
		// time limit exceeded
		//------------------------------------------------------------------
		//  MAF 6/2010
		//------------------------------------------------------------------
		else if(((m_left->m_currentTime) > (m_maxFireTime-1)))
			 {     m_left->m_currentTime=m_maxFireTime;
    	           m_left->m_status = Sem::Contain::TimeLimitExceeded;

				   rerun=false;
			 }
        // Case 7: anything else (should never get here!)...
        else
        {
            m_left->containLog( ( logLevel >= 1 ),
                "Pass %d Result 7:\n"
                "    - unknown condition at %3.1f minutes (%d steps)\n"
                "    - RE-RUN\n",
                m_pass, elapsed, m_left->m_step );
            rerun = true;
        }
    }
    // Special case for contained head tactic with non-zero offset
    if ( m_left->m_status == Sem::Contain::Contained
      && m_left->m_tactic == Sem::Contain::HeadAttack
      && m_left->m_attackDist > 0.01 )
    {
    }
    
    //special case for time limit
    //if the time is greater than the max time, then the fire escapes
    //all resources that arrive prior to the max time are considered used
    //always subtract 1 minute from the fire time, we don't get a correct state
    //otherwise because the simulation forces all resources to end work before the
    //fire time limit is reached
    //if ((m_left->m_time) > (m_maxFireTime-1)) {
    //	m_left->m_time=m_maxFireTime;
    //	m_left->m_status = Sem::Contain::TimeLimitExceeded;
    //}
    
    //------------------------------------------------------------------
    //  MAF 6/2010
    //------------------------------------------------------------------
    if ((m_left->m_currentTime) > (m_maxFireTime-1)) {
     	m_left->m_currentTime=m_maxFireTime;
     	m_left->m_status = Sem::Contain::TimeLimitExceeded;
     }
     
    // Simulation complete: display results
    finalStats();
    m_left->containLog( ( logLevel > 0 ),
        "\n    Pass %d Step Size  : %f ch\n", m_pass, m_left->m_distStep );
    m_left->containLog( ( logLevel > 0 ),
        "    Tactic            : %8s\n", TacticName[m_left->m_tactic] );
    m_left->containLog( ( logLevel > 0 ),
        "    Simulation Steps  : %8d\n", m_left->m_step+1 );
    m_left->containLog( ( logLevel > 0 ),
        "    Simulation Time   : %8.2f min\n", m_finalTime );
    m_left->containLog( ( logLevel > 0 ),
        "    Simulation Result : %s\n", StatusName[m_left->m_status] );
    m_left->containLog( ( logLevel > 0 ),
        "    Containment Line  : %8.4f ch\n", m_finalLine );
    m_left->containLog( ( logLevel > 0 ),
        "    Containment Size  : %8.4f ac\n", m_finalSize );
    m_left->containLog( ( logLevel > 0 ),
        "    Resources Used    : %8d\n", m_used );
    m_left->containLog( ( logLevel > 0 ),
        "    Resource Cost     : %8.0f\n\n", m_finalCost );
    return;
}
Esempio n. 4
0
int do_hdd_file_put(int fd, char *srcPath, char *dstPath)
{
    int result = -EPROTO;
    time_t startTime = time(NULL);
    enum
    {
        START,
        DATA,
        END,
        FINISHED
    } state;
    int src = -1;
    int r;
    int update = 0;
    struct stat64 srcStat;
    __u64 fileSize;
    __u64 byteCount = 0;

    trace(4, fprintf(stderr, "%s\n", __func__));

    src = open64(srcPath, O_RDONLY);
    if(src < 0)
    {
        fprintf(stderr, "ERROR: Can not open source file: %s\n",
                strerror(errno));
        return errno;
    }

    if(0 != fstat64(src, &srcStat))
    {
        fprintf(stderr, "ERROR: Can not examine source file: %s\n",
                strerror(errno));
        result = errno;
        goto out;
    }

    fileSize = srcStat.st_size;
    if(fileSize == 0)
    {
        fprintf(stderr, "ERROR: Source file is empty - not transfering.\n");
        result = -ENODATA;
        goto out;
    }

    r = send_cmd_hdd_file_send(fd, PUT, dstPath);
    if(r < 0)
    {
        goto out;
    }

    state = START;
    while(0 < get_tf_packet(fd, &reply))
    {
        update = (update + 1) % 16;
        switch (get_u32(&reply.cmd))
        {
            case SUCCESS:
                switch (state)
                {
                    case START:
                    {
                        /* Send start */
                        struct typefile *tf = (struct typefile *) packet.data;

                        put_u16(&packet.length, PACKET_HEAD_SIZE + 114);
                        put_u32(&packet.cmd, DATA_HDD_FILE_START);
                        time_to_tfdt(srcStat.st_mtime, &tf->stamp);
                        tf->filetype = 2;
                        put_u64(&tf->size, srcStat.st_size);
                        strncpy((char *) tf->name, dstPath, 94);
                        tf->name[94] = '\0';
                        tf->unused = 0;
                        tf->attrib = 0;
                        trace(3,
                              fprintf(stderr, "%s: DATA_HDD_FILE_START\n",
                                      __func__));
                        r = send_tf_packet(fd, &packet);
                        if(r < 0)
                        {
                            fprintf(stderr, "ERROR: Incomplete send.\n");
                            goto out;
                        }
                        state = DATA;
                        break;
                    }

                    case DATA:
                    {
                        int payloadSize = sizeof(packet.data) - 9;
                        ssize_t w = read(src, &packet.data[8], payloadSize);

                        /* Detect a Topfield protcol bug and prevent the sending of packets
                           that are a multiple of 512 bytes. */
                        if((w > 4)
                           &&
                           (((((PACKET_HEAD_SIZE + 8 + w) +
                               1) & ~1) % 0x200) == 0))
                        {
                            lseek64(src, -4, SEEK_CUR);
                            w -= 4;
                            payloadSize -= 4;
                        }

                        put_u16(&packet.length, PACKET_HEAD_SIZE + 8 + w);
                        put_u32(&packet.cmd, DATA_HDD_FILE_DATA);
                        put_u64(packet.data, byteCount);
                        byteCount += w;

                        /* Detect EOF and transition to END */
                        if((w < 0) || (byteCount >= fileSize))
                        {
                            state = END;
                        }

                        if(w > 0)
                        {
                            trace(3,
                                  fprintf(stderr, "%s: DATA_HDD_FILE_DATA\n",
                                          __func__));
                            r = send_tf_packet(fd, &packet);
                            if(r < w)
                            {
                                fprintf(stderr, "ERROR: Incomplete send.\n");
                                goto out;
                            }
                        }

                        if(!update && !quiet)
                        {
                            progressStats(fileSize, byteCount, startTime);
                        }
                        break;
                    }

                    case END:
                        /* Send end */
                        put_u16(&packet.length, PACKET_HEAD_SIZE);
                        put_u32(&packet.cmd, DATA_HDD_FILE_END);
                        trace(3,
                              fprintf(stderr, "%s: DATA_HDD_FILE_END\n",
                                      __func__));
                        r = send_tf_packet(fd, &packet);
                        if(r < 0)
                        {
                            fprintf(stderr, "ERROR: Incomplete send.\n");
                            goto out;
                        }
                        state = FINISHED;
                        break;

                    case FINISHED:
                        result = 0;
                        goto out;
                        break;
                }
                break;

            case FAIL:
                fprintf(stderr, "ERROR: Device reports %s\n",
                        decode_error(&reply));
                goto out;
                break;

            default:
                fprintf(stderr, "ERROR: Unhandled packet\n");
                break;
        }
    }
    finalStats(byteCount, startTime);

  out:
    close(src);
    return result;
}