Example #1
0
/*
 * Given an offset in a file, find the disk block number that
 * contains that block.
 *
 * Parameters:
 *	disk_block_p:	out
 */
static int
block_map(struct open_file *f, daddr_t file_block, daddr_t *disk_block_p)
{
	struct file *fp = (struct file *)f->f_fsdata;
	struct fs *fs = fp->f_fs;
	int level;
	int idx;
	daddr_t ind_block_num;
	daddr_t *ind_p;
	int rc;

	/*
	 * Index structure of an inode:
	 *
	 * di_db[0..NDADDR-1]	hold block numbers for blocks
	 *			0..NDADDR-1
	 *
	 * di_ib[0]		index block 0 is the single indirect block
	 *			holds block numbers for blocks
	 *			NDADDR .. NDADDR + NINDIR(fs)-1
	 *
	 * di_ib[1]		index block 1 is the double indirect block
	 *			holds block numbers for INDEX blocks for blocks
	 *			NDADDR + NINDIR(fs) ..
	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 - 1
	 *
	 * di_ib[2]		index block 2 is the triple indirect block
	 *			holds block numbers for double-indirect
	 *			blocks for blocks
	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2 ..
	 *			NDADDR + NINDIR(fs) + NINDIR(fs)**2
	 *				+ NINDIR(fs)**3 - 1
	 */

	if (file_block < NDADDR) {
		/* Direct block. */
		*disk_block_p = fp->f_di.di_db[file_block];
		return (0);
	}

	file_block -= NDADDR;

	/*
	 * nindir[0] = NINDIR
	 * nindir[1] = NINDIR**2
	 * nindir[2] = NINDIR**3
	 *	etc
	 */
	for (level = 0; level < NIADDR; level++) {
		if (file_block < fp->f_nindir[level])
			break;
		file_block -= fp->f_nindir[level];
	}
	if (level == NIADDR) {
		/* Block number too high */
		return (EFBIG);
	}

	ind_block_num = fp->f_di.di_ib[level];

	for (; level >= 0; level--) {
		if (ind_block_num == 0) {
			*disk_block_p = 0;	/* missing */
			return (0);
		}

		if (fp->f_blkno[level] != ind_block_num) {
			if (fp->f_blk[level] == NULL)
				fp->f_blk[level] =
					malloc(fs->fs_bsize);
			twiddle();
			rc = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
				fsbtodb(fp->f_fs, ind_block_num),
				fs->fs_bsize,
				fp->f_blk[level],
				&fp->f_blksize[level]);
			if (rc)
				return (rc);
			if (fp->f_blksize[level] != fs->fs_bsize)
				return (EIO);
			fp->f_blkno[level] = ind_block_num;
		}

		ind_p = (daddr_t *)fp->f_blk[level];

		if (level > 0) {
			idx = file_block / fp->f_nindir[level - 1];
			file_block %= fp->f_nindir[level - 1];
		} else
			idx = file_block;

		ind_block_num = ind_p[idx];
	}

	*disk_block_p = ind_block_num;

	return (0);
}
Example #2
0
static void prepareACK(void)
{
 struct udphdr *udpheader;
 struct tftp_t *tftppacket;
 Int16 tftpopcode;
 Int32 tftpdata_length;
 volatile Int16 block_received=0;
#ifdef CONFIG_NFBI
    IMG_HEADER_T header;
    int ret;
    extern int check_system_image(unsigned long addr,IMG_HEADER_Tp pHeader);
#endif

    if (!tftpd_is_ready)
        return;

	//dprintf("Receive TFTP Data\n");
 
 udpheader = (struct udphdr *)&nic.packet[ETH_HLEN+ sizeof(struct iphdr)];
 if(udpheader->dest==htons(SERVER_port))
   {
    /*memorize CLIENT port*/
    CLIENT_port=  ntohs(udpheader->src); 
    tftppacket = (struct tftp_t *)&nic.packet[ETH_HLEN];
    /*no need to check opcode, this is a Data packet*/     
    /*parse the TFTP block number*/	
    block_received=tftppacket->u.data.block;
//prom_printf("line=%d:		block_received=%d\n", __LINE__,  block_received); // for debug
    
    if(block_received != (block_expected))
    {
     //prom_printf("line=%d: block_received=%d, block_expected=%d\n", __LINE__,  block_received,  block_expected); // for debug
     prom_printf("TFTP #\n");
     /*restore the block number*/
     tftpd_send_ack(block_expected-1);    
    }
    else 
     {      
          
      tftpdata_length=ntohs(udpheader->len)-4-sizeof(struct udphdr);
      /*put the image into memory address*/
      memcpy((void *)address_to_store, tftppacket->u.data.download, tftpdata_length);


	// ddump(address_to_store, tftpdata_length);
      //prom_printf("a %x. l %x\n",address_to_store,tftpdata_length);
      
      address_to_store=address_to_store+tftpdata_length;
      /*use this to count the image bytes*/
      file_length_to_server=file_length_to_server+tftpdata_length;
      /*this is for receiving one packet*/
      //prom_printf("%x.\n",address_to_store);
      twiddle();
      //prom_printf(" <- ");
      //prom_printf("%x. %x. %x\n",block_expected,address_to_store,tftpdata_length);
      
      tftpd_send_ack(block_expected);               
      block_expected=block_expected+1;
//prom_printf("line=%d:		block_expected=%d\n", __LINE__,  block_expected); // for debug
      
      /*remember to check if it is the last packet*/      
      if(tftpdata_length < TFTP_DEFAULTSIZE_PACKET)
        {
         prom_printf("\n**TFTP Client Upload File Size = %X Bytes at %X\n",file_length_to_server,image_address);          
         /*change the boot state back to orignal, and some variables also*/
         nic.packet = eth_packet;
         nic.packetlen = 0;        
         block_expected =0;   
//prom_printf("line=%d:		block_expected=%d\n", __LINE__,  block_expected); // for debug
				 
         /*reset the file position*/
         //image_address=FILESTART;
         address_to_store=image_address;
         file_length_to_client=file_length_to_server;
         /*file_length_to_server can not be reset,only when another WRQ */
         /*and export to file_length_to_client for our SDRAM direct RRQ*/
         it_is_EOF=0;
         bootState=BOOT_STATE0_INIT_ARP;
         /*Cyrus Tsai*/
         one_tftp_lock=0; 
         SERVER_port++;
         
 	 prom_printf( "\nSuccess!\n%s", "<RealTek>" );
 	      
#ifdef CONFIG_NFBI
        ret = check_system_image((unsigned long)image_address,&header);
    	if(ret == 1)
	    {
			//prom_printf("\nheader.startAddr=%X header.len=%d image_address=%x\n", header.startAddr, header.len, image_address);
			// move image to SDRAM
			//memcpy((void*)header.startAddr, (void*)(0x80700000+sizeof(header)), header.len-2);
			
			jump_to_test = 1;
			image_address = (void *)(header.startAddr); //0x80700000
		}
		else {
		    prom_printf( "ret=%d\n", ret);
		}
#endif  //CONFIG_NFBI

         if(jump_to_test==1)
           {
            jump_to_test=0;
	    /*we should clear all irq mask.*/
	    //jumpF = (void *)(TESTSTART); //sc_yang
	    jumpF = (void *)(image_address);
	    /*we should clear all irq mask.*/
	    outl(0,GIMR0); // mask all interrupt	    
	   cli();

		dprintf("Jump to 0x%x\n", image_address);
		flush_cache(); 
	    jumpF();	
           }
#ifndef CONFIG_NFBI
	   else if(autoBurn)
	   	checkAutoFlashing(image_address, file_length_to_server);
#endif
        }       
      
      
     }
   }
//else 
//   prom_printf("\n**TFTP port number error");   

}
Example #3
0
/*
 * Open a file.
 */
static int
ext2fs_open(const char *upath, struct open_file *f)
{
	struct file *fp;
	struct ext2fs *fs;
	size_t buf_size;
	ino_t inumber, parent_inumber;
	int i, len, groups, bg_per_blk, blkgrps, mult;
	int nlinks = 0;
	int error = 0;
	char *cp, *ncp, *path = NULL, *buf = NULL;
	char namebuf[MAXPATHLEN+1];
	char c;

	/* allocate file system specific data structure */
	fp = malloc(sizeof(struct file));
	if (fp == NULL)
		return (ENOMEM);
	bzero(fp, sizeof(struct file));
	f->f_fsdata = (void *)fp;

	/* allocate space and read super block */
	fs = (struct ext2fs *)malloc(sizeof(*fs));
	fp->f_fs = fs;
	twiddle();
	error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
	    EXT2_SBLOCK, EXT2_SBSIZE, (char *)fs, &buf_size);
	if (error)
		goto out;

	if (buf_size != EXT2_SBSIZE || fs->fs_magic != EXT2_MAGIC) {
		error = EINVAL;
		goto out;
	}

	/*
	 * compute in-core values for the superblock
	 */
	fs->fs_bshift = EXT2_MINBSHIFT + fs->fs_fd.fd_bsize;
	fs->fs_bsize = 1 << fs->fs_bshift;
	fs->fs_bmask = fs->fs_bsize - 1;

	fs->fs_fshift = EXT2_MINFSHIFT + fs->fs_fd.fd_fsize;
	fs->fs_fsize = 1 << fs->fs_fshift;
	fs->fs_fmask = fs->fs_fsize - 1;

	if (fs->fs_revision == EXT2_REV0) {
		fs->fs_isize = EXT2_R0_ISIZE;
		fs->fs_firstino = EXT2_R0_FIRSTINO;
	} else {
		fs->fs_isize = fs->fs_fd.fd_isize;
		fs->fs_firstino = fs->fs_fd.fd_firstino;
	}
	fs->fs_imask = fs->fs_isize - 1;
	fs->fs_ipb = fs->fs_bsize / fs->fs_isize;
	fs->fs_fsbtodb = (fs->fs_bsize / DEV_BSIZE) - 1;

	/*
	 * we have to load in the "group descriptors" here
	 */
	groups = howmany(fs->fs_blocks - fs->fs_firstblk, fs->fs_bpg);
	bg_per_blk = fs->fs_bsize / sizeof(struct ext2blkgrp);
	blkgrps = howmany(groups, bg_per_blk);
	len = blkgrps * fs->fs_bsize;

	fp->f_bg = malloc(len);
	twiddle();
	error = (f->f_dev->dv_strategy)(f->f_devdata, F_READ,
	    EXT2_SBLOCK + EXT2_SBSIZE / DEV_BSIZE, len,
	    (char *)fp->f_bg, &buf_size);
	if (error)
		goto out;

	/*
	 * XXX
	 * validation of values?  (blocksize, descriptors, etc?)
	 */

	/*
	 * Calculate indirect block levels.
	 */
	mult = 1;
	for (i = 0; i < NIADDR; i++) {
		mult *= nindir(fs);
		fp->f_nindir[i] = mult;
	}

	inumber = EXT2_ROOTINO;
	if ((error = read_inode(inumber, f)) != 0)
		goto out;

	path = strdup(upath);
	if (path == NULL) {
		error = ENOMEM;
		goto out;
	}
	cp = path;
	while (*cp) {
		/*
		 * Remove extra separators
		 */
		while (*cp == '/')
			cp++;
		if (*cp == '\0')
			break;

		/*
		 * Check that current node is a directory.
		 */
		if (! S_ISDIR(fp->f_di.di_mode)) {
			error = ENOTDIR;
			goto out;
		}

		/*
		 * Get next component of path name.
		 */
		len = 0;

		ncp = cp;
		while ((c = *cp) != '\0' && c != '/') {
			if (++len > EXT2_MAXNAMLEN) {
				error = ENOENT;
				goto out;
			}
			cp++;
		}
		*cp = '\0';

		/*
		 * Look up component in current directory.
		 * Save directory inumber in case we find a
		 * symbolic link.
		 */
		parent_inumber = inumber;
		error = search_directory(ncp, f, &inumber);
		*cp = c;
		if (error)
			goto out;

		/*
		 * Open next component.
		 */
		if ((error = read_inode(inumber, f)) != 0)
			goto out;

		/*
		 * Check for symbolic link.
		 */
		if (S_ISLNK(fp->f_di.di_mode)) {
			int link_len = fp->f_di.di_size;
			int len;

			len = strlen(cp);
			if (link_len + len > MAXPATHLEN ||
			    ++nlinks > MAXSYMLINKS) {
				error = ENOENT;
				goto out;
			}

			bcopy(cp, &namebuf[link_len], len + 1);
			if (fp->f_di.di_nblk == 0) {
				bcopy(fp->f_di.di_shortlink,
				    namebuf, link_len);
			} else {
				/*
				 * Read file for symbolic link
				 */
				struct ext2fs *fs = fp->f_fs;
				daddr_t	disk_block;
				size_t buf_size;

				if (! buf)
					buf = malloc(fs->fs_bsize);
				error = block_map(f, (daddr_t)0, &disk_block);
				if (error)
					goto out;
				
				twiddle();
				error = (f->f_dev->dv_strategy)(f->f_devdata,
				    F_READ, fsb_to_db(fs, disk_block),
				    fs->fs_bsize, buf, &buf_size);
				if (error)
					goto out;

				bcopy((char *)buf, namebuf, link_len);
			}

			/*
			 * If relative pathname, restart at parent directory.
			 * If absolute pathname, restart at root.
			 */
			cp = namebuf;
			if (*cp != '/')
				inumber = parent_inumber;
			else
				inumber = (ino_t)EXT2_ROOTINO;

			if ((error = read_inode(inumber, f)) != 0)
				goto out;
		}
	}

	/*
	 * Found terminal component.
	 */
	error = 0;
out:
	if (buf)
		free(buf);
	if (path)
		free(path);
	if (error) {
		if (fp->f_buf)
			free(fp->f_buf);
		free(fp->f_fs);
		free(fp);
	}
	return (error);
}
Example #4
0
//----------------------------------------------------------------------------------------
void tftpd_send_data(char* filename, Int16 block_number)
{
 /*because we only have 1 image supported */
 /*do nothing to char* file is of no use.*/
 /*UDP source port: SERVER_port*/
 /*UDP target port: CLIENT_port*/

 struct iphdr *ip;
 struct udphdr *udp;
 struct tftp_t tftp_tx;
 Int32* data; 
 int length;


 /********************************************/  
   data=(Int32 *)(image_address+ 512*(block_number-1));
   //prom_printf("send data start at %x\n",data);
 if (512* block_number==(file_length_to_client+512))
    {
    /*it is over that means a length=0 data is required*/
    length=0;
    //prom_printf("TFTP RRQ last NULL data to send\n");
    it_is_EOF=1;
    }
 else if( 512* block_number > file_length_to_client)
    { 
     length=file_length_to_client-512*(block_number-1);
     //prom_printf("TFTP RRQ last data to send\n");
     it_is_EOF=1;
    }
 else
    length=512;
 
 /********************************************/
 /*generate the TFTP body*/
 tftp_tx.opcode=htons(TFTP_DATA);
 memcpy(tftp_tx.u.data.download,(Int8*)data,length);
 tftp_tx.u.data.block=htons(block_number);
 
 ip = (struct iphdr *)&tftp_tx;
 udp = (struct udphdr *)((Int8*)&tftp_tx + sizeof(struct iphdr));
 
 /*generate the IP header*/
 ip->verhdrlen = 0x45;
 ip->service = 0;
 ip->len = htons(32+length);
 ip->ident = 0;
 ip->frags = 0;
 ip->ttl = 60;
 ip->protocol = IP_UDP;
 ip->chksum = 0;
 ip->src.s_addr = arptable_tftp[TFTP_SERVER].ipaddr.s_addr;
 ip->dest.s_addr = arptable_tftp[TFTP_CLIENT].ipaddr.s_addr;
 ip->chksum = ipheader_chksum((Int16 *)&tftp_tx, sizeof(struct iphdr));
 /*generate the UDP header*/
 udp->src  = htons(SERVER_port);
 udp->dest = htons(CLIENT_port);
 udp->len  = htons(length+4+8);
 udp->chksum = 0;
 
 /*use twiddle here*/
 twiddle();
 //prom_printf(" -> ");
 
 prepare_txpkt(0,FRAME_IP,arptable_tftp[TFTP_CLIENT].node,(Int8*)&tftp_tx,(Int16)sizeof(struct iphdr)+sizeof(struct udphdr)+length+4);
}
Example #5
0
void bmerge_r(int xlowIn, int xuppIn, int ilowIn, int iuppIn, int col, int lowmax, int uppmax)
// col is >0 and <=ncol-1 if this range of [xlow,xupp] and [ilow,iupp] match up to but not including that column
// lowmax=1 if xlowIn is the lower bound of this group (needed for roll)
// uppmax=1 if xuppIn is the upper bound of this group (needed for roll)
{
    int xlow=xlowIn, xupp=xuppIn, ilow=ilowIn, iupp=iuppIn, j, k, ir, lir, tmp;
    SEXP class;
    ir = lir = ilow + (iupp-ilow)/2;           // lir = logical i row.
    if (o) ir = o[lir]-1;                      // ir = the actual i row if i were ordered

    ic = VECTOR_ELT(i,icols[col]-1);  // ic = i column
    xc = VECTOR_ELT(x,xcols[col]-1);  // xc = x column
    // it was checked in bmerge() that the types are equal
    
    switch (TYPEOF(xc)) {
    case LGLSXP : case INTSXP :   // including factors
        ival.i = INTEGER(ic)[ir];
        while(xlow < xupp-1) {
            mid = xlow + (xupp-xlow)/2;   // Same as (xlow+xupp)/2 but without risk of overflow
            xval.i = INTEGER(xc)[XIND(mid)];
            if (xval.i<ival.i) {          // relies on NA_INTEGER == INT_MIN, tested in init.c
                xlow=mid;
            } else if (xval.i>ival.i) {   // TO DO: is *(&xlow, &xupp)[0|1]=mid more efficient than branch?
                xupp=mid;
            } else { // xval.i == ival.i  including NA_INTEGER==NA_INTEGER
                // branch mid to find start and end of this group in this column
                // TO DO?: not if mult=first|last and col<ncol-1
                tmplow = mid;
                tmpupp = mid;
                while(tmplow<xupp-1) {
                    mid = tmplow + (xupp-tmplow)/2;
                    xval.i = INTEGER(xc)[XIND(mid)];
                    if (xval.i == ival.i) tmplow=mid; else xupp=mid;
                }
                while(xlow<tmpupp-1) {
                    mid = xlow + (tmpupp-xlow)/2;
                    xval.i = INTEGER(xc)[XIND(mid)];
                    if (xval.i == ival.i) tmpupp=mid; else xlow=mid;
                }
                // xlow and xupp now surround the group in xc, we only need this range for the next column
                break;
            }
        }
        tmplow = lir;
        tmpupp = lir;
        while(tmplow<iupp-1) {   // TO DO: could double up from lir rather than halving from iupp
            mid = tmplow + (iupp-tmplow)/2;
            xval.i = INTEGER(ic)[ o ? o[mid]-1 : mid ];   // reuse xval to search in i
            if (xval.i == ival.i) tmplow=mid; else iupp=mid;
        }
        while(ilow<tmpupp-1) {
            mid = ilow + (tmpupp-ilow)/2;
            xval.i = INTEGER(ic)[ o ? o[mid]-1 : mid ];
            if (xval.i == ival.i) tmpupp=mid; else ilow=mid;
        }
        // ilow and iupp now surround the group in ic, too
        break;
    case STRSXP :
        ival.s = STRING_ELT(ic,ir);
        while(xlow < xupp-1) {
            mid = xlow + (xupp-xlow)/2;
            xval.s = STRING_ELT(xc, XIND(mid));
            if (enc_warn && (ENC_KNOWN(ival.s) || ENC_KNOWN(xval.s))) {
                // The || is only done here to avoid the warning message being repeating in this code.
                warning("A known encoding (latin1 or UTF-8) was detected in a join column. data.table compares the bytes currently, so doesn't support *mixed* encodings well; i.e., using both latin1 and UTF-8, or if any unknown encodings are non-ascii and some of those are marked known and others not. But if either latin1 or UTF-8 is used exclusively, and all unknown encodings are ascii, then the result should be ok. In future we will check for you and avoid this warning if everything is ok. The tricky part is doing this without impacting performance for ascii-only cases.");
                // TO DO: check and warn in forder whether any strings are non-ascii (>127) but unknown encoding
                //        check in forder whether both latin1 and UTF-8 have been used
                //        See bugs #5159 and #5266 and related #5295 to revisit
                enc_warn = FALSE;  // just warn once
            }
            tmp = StrCmp(xval.s, ival.s);  // uses pointer equality first, NA_STRING are allowed and joined to, then uses strcmp on CHAR().
            if (tmp == 0) {                // TO DO: deal with mixed encodings and locale optionally
                tmplow = mid;
                tmpupp = mid;
                while(tmplow<xupp-1) {
                    mid = tmplow + (xupp-tmplow)/2;
                    xval.s = STRING_ELT(xc, XIND(mid));
                    if (ival.s == xval.s) tmplow=mid; else xupp=mid;  // the == here assumes (within this column) no mixing of latin1 and UTF-8, and no unknown non-ascii
                }                                                     // TO DO: add checks to forder, see above.
                while(xlow<tmpupp-1) {
                    mid = xlow + (tmpupp-xlow)/2;
                    xval.s = STRING_ELT(xc, XIND(mid));
                    if (ival.s == xval.s) tmpupp=mid; else xlow=mid;  // see above re ==
                }
                break;
            } else if (tmp < 0) {
                xlow=mid;
            } else {
                xupp=mid;
            }
        }
        tmplow = lir;
        tmpupp = lir;
        while(tmplow<iupp-1) {
            mid = tmplow + (iupp-tmplow)/2;
            xval.s = STRING_ELT(ic, o ? o[mid]-1 : mid);
            if (xval.s == ival.s) tmplow=mid; else iupp=mid;   // see above re ==
        }
        while(ilow<tmpupp-1) {
            mid = ilow + (tmpupp-ilow)/2;
            xval.s = STRING_ELT(ic, o ? o[mid]-1 : mid);
            if (xval.s == ival.s) tmpupp=mid; else ilow=mid;   // see above re == 
        }
        break;
    case REALSXP :
        class = getAttrib(xc, R_ClassSymbol);
        twiddle = (isString(class) && STRING_ELT(class, 0)==char_integer64) ? &i64twiddle : &dtwiddle;
        ival.ll = twiddle(DATAPTR(ic), ir, 1);
        while(xlow < xupp-1) {
            mid = xlow + (xupp-xlow)/2;
            xval.ll = twiddle(DATAPTR(xc), XIND(mid), 1);
            if (xval.ll<ival.ll) {
                xlow=mid;
            } else if (xval.ll>ival.ll) {
                xupp=mid;
            } else { // xval.ll == ival.ll) 
                tmplow = mid;
                tmpupp = mid;
                while(tmplow<xupp-1) {
                    mid = tmplow + (xupp-tmplow)/2;
                    xval.ll = twiddle(DATAPTR(xc), XIND(mid), 1);
                    if (xval.ll == ival.ll) tmplow=mid; else xupp=mid;
                }
                while(xlow<tmpupp-1) {
                    mid = xlow + (tmpupp-xlow)/2;
                    xval.ll = twiddle(DATAPTR(xc), XIND(mid), 1);
                    if (xval.ll == ival.ll) tmpupp=mid; else xlow=mid;
                }
                break;
            }
        }
        tmplow = lir;
        tmpupp = lir;
        while(tmplow<iupp-1) {
            mid = tmplow + (iupp-tmplow)/2;
            xval.ll = twiddle(DATAPTR(ic), o ? o[mid]-1 : mid, 1 );
            if (xval.ll == ival.ll) tmplow=mid; else iupp=mid;
        }
        while(ilow<tmpupp-1) {
            mid = ilow + (tmpupp-ilow)/2;
            xval.ll = twiddle(DATAPTR(ic), o ? o[mid]-1 : mid, 1 );
            if (xval.ll == ival.ll) tmpupp=mid; else ilow=mid;
        }
        break;
    default:
        error("Type '%s' not supported as key column", type2char(TYPEOF(xc)));
    }
    
    if (xlow<xupp-1) {      // if value found, low and upp surround it, unlike standard binary search where low falls on it
        if (col<ncol-1) bmerge_r(xlow, xupp, ilow, iupp, col+1, 1, 1);  // final two 1's are lowmax and uppmax
        else {
            int len = xupp-xlow-1;
            if (len>1) allLen1[0] = FALSE;
            for (j=ilow+1; j<iupp; j++) {   // usually iterates once only for j=ir
                k = o ? o[j]-1 : j;
                retFirst[k] = xlow+2;       // extra +1 for 1-based indexing at R level
                retLength[k]= len; 
            }
        }
    }
    else if (roll!=0.0 && col==ncol-1) {
        // runs once per i row (not each search test), so not hugely time critical
        if (xlow != xupp-1 || xlow<xlowIn || xupp>xuppIn) error("Internal error: xlow!=xupp-1 || xlow<xlowIn || xupp>xuppIn");
        if (rollToNearest) {   // value of roll ignored currently when nearest
            if ( (!lowmax || xlow>xlowIn) && (!uppmax || xupp<xuppIn) ) {
                if (  ( TYPEOF(ic)==REALSXP && REAL(ic)[ir]-REAL(xc)[XIND(xlow)] <= REAL(xc)[XIND(xupp)]-REAL(ic)[ir] )
                   || ( TYPEOF(ic)<=INTSXP && INTEGER(ic)[ir]-INTEGER(xc)[XIND(xlow)] <= INTEGER(xc)[XIND(xupp)]-INTEGER(ic)[ir] )) {
                    retFirst[ir] = xlow+1;
                    retLength[ir] = 1;
                } else {
                    retFirst[ir] = xupp+1;
                    retLength[ir] = 1;
                }
            } else if (uppmax && xupp==xuppIn && rollends[1]) {
                retFirst[ir] = xlow+1;
                retLength[ir] = 1;
            } else if (lowmax && xlow==xlowIn && rollends[0]) {
                retFirst[ir] = xupp+1;
                retLength[ir] = 1;
            }
        } else {
            if ( (   (roll>0.0 && (!lowmax || xlow>xlowIn) && (xupp<xuppIn || !uppmax || rollends[1]))
                  || (roll<0.0 && xupp==xuppIn && uppmax && rollends[1]) )
              && (   (TYPEOF(ic)==REALSXP && (REAL(ic)[ir]-REAL(xc)[XIND(xlow)]-rollabs<1e-6 || 
                                              REAL(ic)[ir]-REAL(xc)[XIND(xlow)] == rollabs)) // #1007 fix
                  || (TYPEOF(ic)<=INTSXP && (double)(INTEGER(ic)[ir]-INTEGER(xc)[XIND(xlow)])-rollabs<1e-6 ) 
                  || (TYPEOF(ic)==STRSXP)   )) {
                retFirst[ir] = xlow+1;
                retLength[ir] = 1;
            } else if
               (  (  (roll<0.0 && (!uppmax || xupp<xuppIn) && (xlow>xlowIn || !lowmax || rollends[0]))
                  || (roll>0.0 && xlow==xlowIn && lowmax && rollends[0]) )
              && (   (TYPEOF(ic)==REALSXP && (REAL(xc)[XIND(xupp)]-REAL(ic)[ir]-rollabs<1e-6 || 
                                              REAL(xc)[XIND(xupp)]-REAL(ic)[ir] == rollabs)) // 1007 fix
                  || (TYPEOF(ic)<=INTSXP && (double)(INTEGER(xc)[XIND(xupp)]-INTEGER(ic)[ir])-rollabs<1e-6 )
                  || (TYPEOF(ic)==STRSXP)   )) {
                retFirst[ir] = xupp+1;   // == xlow+2
                retLength[ir] = 1;
            }
        }
        if (iupp-ilow > 2 && retFirst[ir]!=NA_INTEGER) {  // >=2 equal values in the last column being rolling to the same point.  
            for (j=ilow+1; j<iupp; j++) {                 // will rewrite retFirst[ir] to itself, but that's ok
                if (o) k=o[j]-1; else k=j;
                retFirst[k] = retFirst[ir];
                retLength[k]= retLength[ir]; 
            }
        }
    }
    if (ilow>ilowIn && (xlow>xlowIn || (roll!=0.0 && col==ncol-1)))
        bmerge_r(xlowIn, xlow+1, ilowIn, ilow+1, col, lowmax, uppmax && xlow+1==xuppIn);
    if (iupp<iuppIn && (xupp<xuppIn || (roll!=0.0 && col==ncol-1)))
        bmerge_r(xupp-1, xuppIn, iupp-1, iuppIn, col, lowmax && xupp-1==xlowIn, uppmax);
}