/* this first locks inode (neither reads nor sync are permitted),
   reads tail through page cache, insert direct item. When direct item
   inserted successfully inode is left locked. Return value is always
   what we expect from it (number of cut bytes). But when tail remains
   in the unformatted node, we set mode to SKIP_BALANCING and unlock
   inode */
int indirect2direct (struct reiserfs_transaction_handle *th, 
		     struct inode * p_s_inode,
		     struct page *page, 
		     struct path * p_s_path, /* path to the indirect item. */
		     const struct cpu_key * p_s_item_key, /* Key to look for unformatted node pointer to be cut. */
		     loff_t n_new_file_size, /* New file size. */
		     char * p_c_mode)
{
    struct super_block * p_s_sb = p_s_inode->i_sb;
    struct item_head      s_ih;
    unsigned long n_block_size = p_s_sb->s_blocksize;
    char * tail;
    int tail_len, round_tail_len;
    loff_t pos, pos1; /* position of first byte of the tail */
    struct cpu_key key;

    p_s_sb->u.reiserfs_sb.s_indirect2direct ++;

    *p_c_mode = M_SKIP_BALANCING;

    /* store item head path points to. */
    copy_item_head (&s_ih, PATH_PITEM_HEAD(p_s_path));

    tail_len = (n_new_file_size & (n_block_size - 1));
    if (get_inode_sd_version (p_s_inode) == STAT_DATA_V2)
	round_tail_len = ROUND_UP (tail_len);
    else
	round_tail_len = tail_len;

    pos = le_ih_k_offset (&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * p_s_sb->s_blocksize;
    pos1 = pos;

    // we are protected by i_sem. The tail can not disapper, not
    // append can be done either
    // we are in truncate or packing tail in file_release

    tail = (char *)kmap(page) ; /* this can schedule */

    if (path_changed (&s_ih, p_s_path)) {
	/* re-search indirect item */
	if ( search_for_position_by_key (p_s_sb, p_s_item_key, p_s_path) == POSITION_NOT_FOUND )
	    reiserfs_panic(p_s_sb, "PAP-5520: indirect2direct: "
			   "item to be converted %K does not exist", p_s_item_key);
	copy_item_head(&s_ih, PATH_PITEM_HEAD(p_s_path));
#ifdef CONFIG_REISERFS_CHECK
	pos = le_ih_k_offset (&s_ih) - 1 + 
	    (ih_item_len(&s_ih) / UNFM_P_SIZE - 1) * p_s_sb->s_blocksize;
	if (pos != pos1)
	    reiserfs_panic (p_s_sb, "vs-5530: indirect2direct: "
			    "tail position changed while we were reading it");
#endif
    }


    /* Set direct item header to insert. */
    make_le_item_head (&s_ih, 0, get_inode_item_key_version (p_s_inode), pos1 + 1,
		       TYPE_DIRECT, round_tail_len, 0xffff/*ih_free_space*/);

    /* we want a pointer to the first byte of the tail in the page.
    ** the page was locked and this part of the page was up to date when
    ** indirect2direct was called, so we know the bytes are still valid
    */
    tail = tail + (pos & (PAGE_CACHE_SIZE - 1)) ;

    PATH_LAST_POSITION(p_s_path)++;

    key = *p_s_item_key;
    set_cpu_key_k_type (&key, TYPE_DIRECT);
    key.key_length = 4;
    /* Insert tail as new direct item in the tree */
    if ( reiserfs_insert_item(th, p_s_path, &key, &s_ih,
			      tail ? tail : NULL) < 0 ) {
	/* No disk memory. So we can not convert last unformatted node
	   to the direct item.  In this case we used to adjust
	   indirect items's ih_free_space. Now ih_free_space is not
	   used, it would be ideal to write zeros to corresponding
	   unformatted node. For now i_size is considered as guard for
	   going out of file size */
	kunmap(page) ;
	return n_block_size - round_tail_len;
    }
    kunmap(page) ;

    /* this will invalidate all the buffers in the page after
    ** pos1
    */
    unmap_buffers(page, pos1) ;

    // note: we have now the same as in above direct2indirect
    // conversion: there are two keys which have matching first three
    // key components. They only differ by the fouhth one.

    /* We have inserted new direct item and must remove last
       unformatted node. */
    p_s_inode->i_blocks += (p_s_sb->s_blocksize / 512);
    *p_c_mode = M_CUT;

    /* we store position of first direct item in the in-core inode */
    //mark_file_with_tail (p_s_inode, pos1 + 1);
    p_s_inode->u.reiserfs_i.i_first_direct_byte = pos1 + 1;

    return n_block_size - round_tail_len;
}
Beispiel #2
0
/*
*       File Selector input routine that takes control of the mouse
*       and keyboard, searchs and sort the directory, draws the file 
*       selector, interacts with the user to determine a selection
*       or change of path, and returns to the application with
*       the selected path, filename, and exit button.
*/
WORD fs_input(BYTE *pipath, BYTE *pisel, WORD *pbutton, BYTE *pilabel)
{
        register WORD   touchob, value, fnum;
        WORD            curr, count, sel;
        WORD            mx, my;
        LONG            tree;
        ULONG           bitmask;
        BYTE            *ad_fpath, *ad_fname, *ad_ftitle;
        WORD            drive; 
        WORD            dclkret, cont, newlist, newsel, newdrive;
        register BYTE   *pstr;
        GRECT           pt;
        BYTE            locstr[LEN_ZPATH+1], mask[LEN_ZFNAME+1], selname[LEN_FSNAME];
        OBJECT          *obj;
        TEDINFO         *tedinfo;

        curr = 0;
        count = 0;
                                        /* get out quick if path is     */
                                        /*   nullptr or if pts to null. */
        if (pipath == NULL)
          return(FALSE);
                                        /* if path string is empty, */
                                        /*   set reasonable default */
        if (*pipath == '\0') {
          strcpy(pipath,"A:\\*.*");
          *pipath += dos_gdrv();
        }
                                        /* get memory for the filename buffer */
                                        /*  & the array that points to it     */
        for (nm_files = MAX_NM_FILES; nm_files >= MIN_NM_FILES; nm_files /= 2)
        {
          ad_fsnames = (BYTE *)dos_alloc(nm_files*(LEN_FSNAME+sizeof(BYTE *)));
          if (ad_fsnames)
            break;
        }
        if (!ad_fsnames)
          return(FALSE);
        g_fslist = (LONG *)(ad_fsnames+nm_files*LEN_FSNAME);

        strcpy(locstr, pipath);

        tree = ad_fstree;
                                                /* init strings in form */
        obj = ((OBJECT *)tree) + FTITLE;
        tedinfo = (TEDINFO *)obj->ob_spec;
        ad_ftitle = (BYTE *)tedinfo->te_ptext;
        set_mask(mask, locstr);                 /* save caller's mask */
        strcpy(ad_ftitle, mask);                /*  & copy to title line */

        obj = ((OBJECT *)tree) + FSDIRECT;
        tedinfo = (TEDINFO *)obj->ob_spec;
        ad_fpath = (BYTE *)tedinfo->te_ptext;
        inf_sset(tree, FSDIRECT, locstr);

        obj = ((OBJECT *)tree) + FSSELECT;
        tedinfo = (TEDINFO *)obj->ob_spec;
        ad_fname = (BYTE *)tedinfo->te_ptext;
        fmt_str(pisel, selname);                /* selname[] is without dot */
        inf_sset(tree, FSSELECT, selname);

        obj = ((OBJECT *)tree) + FSTITLE;
        obj->ob_spec = pilabel ? (LONG)pilabel : (LONG)rs_str(ITEMSLCT);

                                                /* set drive buttons */
        obj = ((OBJECT *)tree) + DRIVE_OFFSET;
        for (drive = 0, bitmask = 1; drive < NM_DRIVES; drive++, bitmask <<= 1, obj++)
        {
          if (drvbits & bitmask)
            obj->ob_state &= ~DISABLED;
          else
            obj->ob_state |= DISABLED;
        }
        select_drive(tree,locstr[0]-'A',0);
                                                /* set clip and start   */
                                                /*   form fill-in by    */
                                                /*   drawing the form   */
        gsx_sclip(&gl_rfs);     
        fm_dial(FMD_START, &gl_rfs);
        ob_draw(tree, ROOT, 2);
                                                /* init for while loop  */
                                                /*   by forcing initial */
                                                /*   fs_newdir call     */
        sel = 0;
        newsel = FALSE;
        cont = newlist = TRUE;
        while( cont )
        {
          touchob = (newlist) ? 0x0 : fm_do(tree, FSSELECT);
          gsx_mxmy(&mx, &my);
        
          if ( newlist )
          {
            fs_sel(sel, NORMAL);
            if ( (touchob == FSOK) ||
                 (touchob == FSCANCEL) )
              ob_change(tree, touchob, NORMAL, TRUE);
            inf_sset(tree, FSDIRECT, locstr);
            pstr = fs_pspec(locstr, NULL);        
            strcpy(pstr, mask);
            fs_newdir(locstr, mask, tree, &count);
            curr = 0;
            sel = touchob = 0;
            newlist = FALSE;
          }

          value = 0;
          dclkret = ((touchob & 0x8000) != 0);
          switch( (touchob &= 0x7fff) )
          {
            case FSOK:
            case FSCANCEL:
                cont = FALSE;
                break;
            case FUPAROW:
            case FDNAROW:
                value = 1;
                break;
            case FSVSLID:
                ob_actxywh(tree, FSVELEV, &pt);
                /* anemic slidebars
                  pt.g_x -= 3;
                  pt.g_w += 6;
                */
                if ( !inside(mx, my, &pt) )
                  {
                  touchob = (my <= pt.g_y) ? FUPAROW : FDNAROW;
                  value = NM_NAMES;
                  break;
                  }
                /* drop through */
            case FSVELEV:
                fm_own(TRUE);
                value = gr_slidebox(tree, FSVSLID, FSVELEV, TRUE);
                fm_own(FALSE);
                value = curr - mul_div(value, count-NM_NAMES, 1000);
                if (value >= 0)
                  touchob = FUPAROW;
                else
                {
                  touchob = FDNAROW;
                  value = -value;
                }
                break;
            case F1NAME:
            case F2NAME:
            case F3NAME:
            case F4NAME:
            case F5NAME:
            case F6NAME:
            case F7NAME:
            case F8NAME:
            case F9NAME:
                fnum = touchob - F1NAME + 1;
                if ( fnum > count )
                  break;
                if ( (sel) && (sel != fnum) )
                  fs_sel(sel, NORMAL);
                if ( sel != fnum)
                {
                  sel = fnum;
                  fs_sel(sel, SELECTED);
                }
                                                /* get string and see   */
                                                /*   if file or folder  */
                inf_sget(tree, touchob, selname);
                if (selname[0] == ' ')          /* a file was selected  */
                {                               /* copy to selection    */
                  newsel = TRUE;
                  if (dclkret)
                    cont = FALSE;
                }
                else                            /* a folder was selected:  */
                {                               /* insert name before mask */
                  pstr = fs_pspec(locstr, NULL);
                  unfmt_str(selname+1, pstr);
                  pstr += strlen(pstr);
                  *pstr++ = '\\';
                  strcpy(pstr, mask);
                  newlist = TRUE;
                }
                break;
            case FCLSBOX:
                pstr = fs_back(locstr, NULL);
                if (*pstr-- != '\\')    /* ignore strange path string */
                  break;
                if (*pstr != ':')       /* not at root of drive, so back up */
                {
                  pstr = fs_back(locstr, pstr);
                  if (*pstr == '\\')    /* we must have at least X:\ */
                    strcpy(pstr+1, mask);
                }
                newlist = TRUE;
                break;
            default:
                drive = touchob - DRIVE_OFFSET;
                if ((drive < 0) || (drive >= NM_DRIVES))/* not for us */
                  break;
                if (drive == locstr[0] - 'A')           /* no change */
                  break;
                obj = ((OBJECT *)tree) + touchob;
                if (obj->ob_state & DISABLED)           /* non-existent drive */
                  break;
                strcpy(locstr, "A:\\*.*");
                locstr[0] += drive;
                newdrive = TRUE;
                break;
          }
          if (!newlist && !newdrive
           && path_changed(locstr))                     /* path changed manually */
          {
            if (ad_fpath[0] != locstr[0])               /* drive has changed */
              newdrive = TRUE;
            else
              newlist = TRUE;
            strcpy(locstr, ad_fpath);
          }
          if (newdrive)
          {
            select_drive(tree, touchob-DRIVE_OFFSET,1);
            newdrive = FALSE;
            newlist = TRUE;
          }
          if (newlist)
          {
            inf_sset(tree, FSDIRECT, locstr);
            set_mask(mask, locstr);                 /* set mask         */
            selname[1] = '\0';                      /* selected is empty */
            newsel = TRUE;
          }
          if (newsel)
          {
            strcpy(ad_fname, selname + 1);
            ob_draw(tree, FSSELECT, MAX_DEPTH);
            if (!cont)
              ob_change(tree, FSOK, SELECTED, TRUE);
            newsel = FALSE;
          }
          if (value)
            curr = fs_nscroll(tree, &sel, curr, count, touchob, value);
        }
                                                /* return path and      */
                                                /*   file name to app   */
        strcpy(pipath, locstr);
        unfmt_str(ad_fname, selname);
        strcpy(pisel, selname);
                                                /* start the redraw     */
        fm_dial(FMD_FINISH, &gl_rfs);
                                                /* return exit button   */
        *pbutton = inf_what(tree, FSOK, FSCANCEL);
        dos_free((LONG)ad_fsnames);

        return( TRUE );
}
int indirect2direct(struct reiserfs_transaction_handle *th,
		    struct inode *inode, struct page *page,
		    struct treepath *path,	
		    const struct cpu_key *item_key,	
		    loff_t n_new_file_size,	
		    char *mode)
{
	struct super_block *sb = inode->i_sb;
	struct item_head s_ih;
	unsigned long block_size = sb->s_blocksize;
	char *tail;
	int tail_len, round_tail_len;
	loff_t pos, pos1;	
	struct cpu_key key;

	BUG_ON(!th->t_trans_id);

	REISERFS_SB(sb)->s_indirect2direct++;

	*mode = M_SKIP_BALANCING;

	
	copy_item_head(&s_ih, PATH_PITEM_HEAD(path));

	tail_len = (n_new_file_size & (block_size - 1));
	if (get_inode_sd_version(inode) == STAT_DATA_V2)
		round_tail_len = ROUND_UP(tail_len);
	else
		round_tail_len = tail_len;

	pos =
	    le_ih_k_offset(&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE -
					 1) * sb->s_blocksize;
	pos1 = pos;

	
	
	

	tail = (char *)kmap(page);	

	if (path_changed(&s_ih, path)) {
		
		if (search_for_position_by_key(sb, item_key, path)
		    == POSITION_NOT_FOUND)
			reiserfs_panic(sb, "PAP-5520",
				       "item to be converted %K does not exist",
				       item_key);
		copy_item_head(&s_ih, PATH_PITEM_HEAD(path));
#ifdef CONFIG_REISERFS_CHECK
		pos = le_ih_k_offset(&s_ih) - 1 +
		    (ih_item_len(&s_ih) / UNFM_P_SIZE -
		     1) * sb->s_blocksize;
		if (pos != pos1)
			reiserfs_panic(sb, "vs-5530", "tail position "
				       "changed while we were reading it");
#endif
	}

	
	make_le_item_head(&s_ih, NULL, get_inode_item_key_version(inode),
			  pos1 + 1, TYPE_DIRECT, round_tail_len,
			  0xffff  );

	tail = tail + (pos & (PAGE_CACHE_SIZE - 1));

	PATH_LAST_POSITION(path)++;

	key = *item_key;
	set_cpu_key_k_type(&key, TYPE_DIRECT);
	key.key_length = 4;
	
	if (reiserfs_insert_item(th, path, &key, &s_ih, inode,
				 tail ? tail : NULL) < 0) {
		kunmap(page);
		return block_size - round_tail_len;
	}
	kunmap(page);

	
	reiserfs_update_sd(th, inode);

	
	
	

	*mode = M_CUT;

	
	
	REISERFS_I(inode)->i_first_direct_byte = pos1 + 1;

	return block_size - round_tail_len;
}
Beispiel #4
0
/*
 * this first locks inode (neither reads nor sync are permitted),
 * reads tail through page cache, insert direct item. When direct item
 * inserted successfully inode is left locked. Return value is always
 * what we expect from it (number of cut bytes). But when tail remains
 * in the unformatted node, we set mode to SKIP_BALANCING and unlock
 * inode
 */
int indirect2direct(struct reiserfs_transaction_handle *th,
		    struct inode *inode, struct page *page,
		    struct treepath *path,	/* path to the indirect item. */
		    const struct cpu_key *item_key,	/* Key to look for
							 * unformatted node
							 * pointer to be cut. */
		    loff_t n_new_file_size,	/* New file size. */
		    char *mode)
{
	struct super_block *sb = inode->i_sb;
	struct item_head s_ih;
	unsigned long block_size = sb->s_blocksize;
	char *tail;
	int tail_len, round_tail_len;
	loff_t pos, pos1;	/* position of first byte of the tail */
	struct cpu_key key;

	BUG_ON(!th->t_trans_id);

	REISERFS_SB(sb)->s_indirect2direct++;

	*mode = M_SKIP_BALANCING;

	/* store item head path points to. */
	copy_item_head(&s_ih, tp_item_head(path));

	tail_len = (n_new_file_size & (block_size - 1));
	if (get_inode_sd_version(inode) == STAT_DATA_V2)
		round_tail_len = ROUND_UP(tail_len);
	else
		round_tail_len = tail_len;

	pos =
	    le_ih_k_offset(&s_ih) - 1 + (ih_item_len(&s_ih) / UNFM_P_SIZE -
					 1) * sb->s_blocksize;
	pos1 = pos;

	/*
	 * we are protected by i_mutex. The tail can not disapper, not
	 * append can be done either
	 * we are in truncate or packing tail in file_release
	 */

	tail = (char *)kmap(page);	/* this can schedule */

	if (path_changed(&s_ih, path)) {
		/* re-search indirect item */
		if (search_for_position_by_key(sb, item_key, path)
		    == POSITION_NOT_FOUND)
			reiserfs_panic(sb, "PAP-5520",
				       "item to be converted %K does not exist",
				       item_key);
		copy_item_head(&s_ih, tp_item_head(path));
#ifdef CONFIG_REISERFS_CHECK
		pos = le_ih_k_offset(&s_ih) - 1 +
		    (ih_item_len(&s_ih) / UNFM_P_SIZE -
		     1) * sb->s_blocksize;
		if (pos != pos1)
			reiserfs_panic(sb, "vs-5530", "tail position "
				       "changed while we were reading it");
#endif
	}

	/* Set direct item header to insert. */
	make_le_item_head(&s_ih, NULL, get_inode_item_key_version(inode),
			  pos1 + 1, TYPE_DIRECT, round_tail_len,
			  0xffff /*ih_free_space */ );

	/*
	 * we want a pointer to the first byte of the tail in the page.
	 * the page was locked and this part of the page was up to date when
	 * indirect2direct was called, so we know the bytes are still valid
	 */
	tail = tail + (pos & (PAGE_SIZE - 1));

	PATH_LAST_POSITION(path)++;

	key = *item_key;
	set_cpu_key_k_type(&key, TYPE_DIRECT);
	key.key_length = 4;
	/* Insert tail as new direct item in the tree */
	if (reiserfs_insert_item(th, path, &key, &s_ih, inode,
				 tail ? tail : NULL) < 0) {
		/*
		 * No disk memory. So we can not convert last unformatted node
		 * to the direct item.  In this case we used to adjust
		 * indirect items's ih_free_space. Now ih_free_space is not
		 * used, it would be ideal to write zeros to corresponding
		 * unformatted node. For now i_size is considered as guard for
		 * going out of file size
		 */
		kunmap(page);
		return block_size - round_tail_len;
	}
	kunmap(page);

	/* make sure to get the i_blocks changes from reiserfs_insert_item */
	reiserfs_update_sd(th, inode);

	/*
	 * note: we have now the same as in above direct2indirect
	 * conversion: there are two keys which have matching first three
	 * key components. They only differ by the fourth one.
	 */

	/*
	 * We have inserted new direct item and must remove last
	 * unformatted node.
	 */
	*mode = M_CUT;

	/* we store position of first direct item in the in-core inode */
	/* mark_file_with_tail (inode, pos1 + 1); */
	REISERFS_I(inode)->i_first_direct_byte = pos1 + 1;

	return block_size - round_tail_len;
}