/* msdos_find_node_by_cluster_num_in_fat_file --
 *     Find node with specified number of cluster in fat-file.
 *
 * PARAMETERS:
 *     mt_entry  - mount table entry
 *     fat_fd    - fat-file descriptor
 *     cl4find   - number of cluster to find
 *     paux      - identify a node location on the disk -
 *                 cluster num and offset inside the cluster
 *     dir_entry - placeholder for found node
 *
 * RETURNS:
 *     RC_OK on success, or error code if error occured
 *
 */
int msdos_find_node_by_cluster_num_in_fat_file(
    rtems_filesystem_mount_table_entry_t *mt_entry,
    fat_file_fd_t                        *fat_fd,
    uint32_t                              cl4find,
    fat_auxiliary_t                      *paux,
    char                                 *dir_entry
    )
{
    int              rc = RC_OK;
    ssize_t          ret = 0;
    msdos_fs_info_t *fs_info = mt_entry->fs_info;
    uint32_t         bts2rd = 0;
    uint32_t         i = 0, j = 0;

    if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
       (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
        bts2rd = fat_fd->fat_file_size;
    else
        bts2rd = fs_info->fat.vol.bpc;

    while ((ret = fat_file_read(mt_entry, fat_fd, j * bts2rd, bts2rd,
                                  fs_info->cl_buf)) != FAT_EOF)
    {
        if ( ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE )
            set_errno_and_return_minus_one( EIO );

        assert(ret == bts2rd);

        for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
        {
            /* if this and all rest entries are empty - return not-found */
            if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
                MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
                return MSDOS_NAME_NOT_FOUND_ERR;

            /* have to look at the DIR_NAME as "raw" 8-bit data */
            /* if this entry is empty - skip it */
            if ((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
                MSDOS_THIS_DIR_ENTRY_EMPTY)
                continue;

            /* if get a non-empty entry - compare clusters num */
            if (MSDOS_EXTRACT_CLUSTER_NUM((fs_info->cl_buf + i)) == cl4find)
            {
                /* on success fill aux structure and copy all 32 bytes */
                rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM, j * bts2rd,
                                    &paux->cln);
                if (rc != RC_OK)
                    return rc;

                paux->ofs = i;
                memcpy(dir_entry, fs_info->cl_buf + i,
                       MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
                return RC_OK;
            }
        }
        j++;
    }
    return MSDOS_NAME_NOT_FOUND_ERR;
}
/* msdos_dir_is_empty --
 *     Check whether directory which correspondes to the fat-file descriptor is
 *     empty.
 *
 * PARAMETERS:
 *     mt_entry - mount table entry
 *     fat_fd   - fat-file descriptor
 *     ret_val  - placeholder for result
 *
 * RETURNS:
 *     RC_OK on success, or -1 if error occured
 *
 */
int
msdos_dir_is_empty(
    rtems_filesystem_mount_table_entry_t *mt_entry,
    fat_file_fd_t                        *fat_fd,
    rtems_boolean                        *ret_val
    )
{
    ssize_t          ret = 0;
    msdos_fs_info_t *fs_info = mt_entry->fs_info;
    uint32_t         j = 0, i = 0;

    /* dir is not empty */
    *ret_val = FALSE;

    while ((ret = fat_file_read(mt_entry, fat_fd, j * fs_info->fat.vol.bps,
                                  fs_info->fat.vol.bps,
                                  fs_info->cl_buf)) != FAT_EOF)
    {
        if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
            return -1;

        assert(ret == fs_info->fat.vol.bps);

        /* have to look at the DIR_NAME as "raw" 8-bit data */
        for (i = 0;
             i < fs_info->fat.vol.bps;
             i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
        {
            if (((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
                 MSDOS_THIS_DIR_ENTRY_EMPTY) ||
                (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), MSDOS_DOT_NAME,
                         MSDOS_SHORT_NAME_LEN) == 0) ||
                (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)),
                         MSDOS_DOTDOT_NAME,
                         MSDOS_SHORT_NAME_LEN) == 0))
                continue;

            if ((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
                MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY)
            {
                *ret_val = TRUE;
                return RC_OK;
            }
            return RC_OK;
        }
        j++;
    }
    *ret_val = TRUE;
    return RC_OK;
}
Exemple #3
0
/*=========================================================================*\
| Function:                                                                 |
\*-------------------------------------------------------------------------*/
int msdos_format
(
/*-------------------------------------------------------------------------*\
| Purpose:                                                                  |
|     format device with msdos filesystem                                   |
+---------------------------------------------------------------------------+
| Input Parameters:                                                         |
\*-------------------------------------------------------------------------*/
 const char *devname,                  /* device name                      */
 const msdos_format_request_param_t *rqdata  /* requested fmt parameters   */
                                             /* set to NULL for automatic  */
                                             /* determination              */
 )
/*-------------------------------------------------------------------------*\
| Return Value:                                                             |
|    0, if success, -1 and errno if failed                                  |
\*=========================================================================*/
{
  char                 tmp_sec[FAT_TOTAL_MBR_SIZE];
  struct stat          stat_buf;
  int                  ret_val   = 0;
  int                  fd        = -1;
  int                  i;
  msdos_format_param_t fmt_params;

  /*
   * open device for writing
   */
  msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL, "open device\n");
  fd = open(devname, O_RDWR);
  if (fd == -1) {
    ret_val= -1;
  }

  /*
   * sanity check on device
   */
  msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL,
                       "stat check: %s\n", devname);
  if (ret_val == 0) {
    ret_val = fstat(fd, &stat_buf);
  }

  msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_INFO,
                       "formating: %s\n", devname);
  /* rtems feature: no block devices, all are character devices */
  if ((ret_val == 0) && (!S_ISBLK(stat_buf.st_mode))) {
    errno = ENOTTY;
    ret_val = -1;
  }

  /*
   * compute formatting parameters
   */
  if (ret_val == 0) {
    ret_val = msdos_format_determine_fmt_params(fd,rqdata,&fmt_params);
  }
  /*
   * if requested, write whole disk/partition with 0xe5
   */
  if ((ret_val == 0) &&
      (rqdata != NULL) &&
      !(rqdata->quick_format)) {
    ret_val = msdos_format_fill_sectors
      (rqdata,
       fd,
       0,                            /* start sector */
       fmt_params.totl_sector_cnt,   /* sector count */
       fmt_params.bytes_per_sector,
       0xe5);
  }

  /*
   * create master boot record
   */
  if (ret_val == 0) {
    /*
     * Read the current MBR to obtain the partition table.
     */
    msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL,
                         "read MRB sector\n");
    ret_val = msdos_format_read_sec(fd,
                                    0,
                                    fmt_params.bytes_per_sector,
                                    tmp_sec);
    if (ret_val == 0) {
      msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL,
                           "generate MRB sector\n");
      ret_val = msdos_format_gen_mbr(tmp_sec,&fmt_params);
    }

    /*
     * write master boot record to disk
     * also write copy of MBR to disk
     */
    if (ret_val == 0) {
      msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL,
                           "write MRB sector\n");
      ret_val = msdos_format_write_sec(fd,
                                       0,
                                       fmt_params.bytes_per_sector,
                                       tmp_sec);
    }
    if ((ret_val == 0) &&
        (fmt_params.mbr_copy_sec != 0)) {
      /*
       * write copy of MBR
       */
      msdos_format_printf (rqdata, MSDOS_FMT_INFO_LEVEL_DETAIL,
                           "write back up MRB sector\n");
      ret_val = msdos_format_write_sec(fd,
                                       fmt_params.mbr_copy_sec ,
                                       fmt_params.bytes_per_sector,
                                       tmp_sec);
    }
  }
  /*
   * for FAT32: initialize info sector on disk
   */
  if ((ret_val == 0) &&
      (fmt_params.fsinfo_sec != 0)) {
      ret_val = msdos_format_gen_fsinfo(tmp_sec);
  }
  /*
   * write fsinfo sector
   */
  if ((ret_val == 0) &&
      (fmt_params.fsinfo_sec != 0)) {
    ret_val = msdos_format_write_sec(fd,
                                     fmt_params.fsinfo_sec,
                                     fmt_params.bytes_per_sector,
                                     tmp_sec);
  }
  /*
   * write FAT as all empty
   * -> write all FAT sectors as zero
   */
  if (ret_val == 0) {
    ret_val = msdos_format_fill_sectors
      (rqdata,
       fd,
       fmt_params.rsvd_sector_cnt,                   /* start sector */
       fmt_params.fat_num*fmt_params.sectors_per_fat,/* sector count */
       fmt_params.bytes_per_sector,
       0x00);
  }
  /*
   * clear/init root directory
   * -> write all directory sectors as 0x00
   */
  if (ret_val == 0) {
    ret_val = msdos_format_fill_sectors
      (rqdata,
       fd,
       fmt_params.root_dir_start_sec,        /* start sector */
       fmt_params.root_dir_fmt_sec_cnt,      /* sector count */
       fmt_params.bytes_per_sector,
       0x00);
  }
  /*
   * write volume label to first entry of directory
   */
  if ((ret_val == 0) && fmt_params.VolLabel_present) {
    memset(tmp_sec,0,sizeof(tmp_sec));
    memcpy(MSDOS_DIR_NAME(tmp_sec),fmt_params.VolLabel,MSDOS_SHORT_NAME_LEN);
    *MSDOS_DIR_ATTR(tmp_sec) = MSDOS_ATTR_VOLUME_ID;
    ret_val = msdos_format_write_sec
      (fd,
       fmt_params.root_dir_start_sec,
       fmt_params.bytes_per_sector,
       tmp_sec);
  }
  /*
   * write FAT entry 0 as (0xffffff00|Media_type)EOC,
   * write FAT entry 1 as EOC
   * allocate directory in a FAT32 FS
   */
  if (ret_val == 0) {
    uint32_t start_sector;

    /*
     * empty sector: all clusters are free/do not link further on
     */
    memset(tmp_sec,0,sizeof(tmp_sec));

    switch(fmt_params.fattype) {
    case FAT_FAT12:
      /* LSBits of FAT entry 0: media_type */
      FAT_SET_VAL8(tmp_sec,0,(fmt_params.media_code));
      /* MSBits of FAT entry 0:0xf, LSBits of FAT entry 1: LSB of EOC */
      FAT_SET_VAL8(tmp_sec,1,(0x0f | (FAT_FAT12_EOC << 4)));
      /* MSBits of FAT entry 1: MSBits of EOC */
      FAT_SET_VAL8(tmp_sec,2,(FAT_FAT12_EOC >> 4));
      break;

    case FAT_FAT16:
      /* FAT entry 0: 0xff00|media_type */
      FAT_SET_VAL8(tmp_sec,0,fmt_params.media_code);
      FAT_SET_VAL8(tmp_sec,1,0xff);
      /* FAT entry 1: EOC */
      FAT_SET_VAL16(tmp_sec,2,FAT_FAT16_EOC);
      break;

    case FAT_FAT32:
      /* FAT entry 0: 0xffffff00|media_type */
      FAT_SET_VAL32(tmp_sec,0,0xffffff00|fmt_params.media_code);
      /* FAT entry 1: Not dirty, no IO error, EOC */
      FAT_SET_VAL32(tmp_sec,4,0xc0000000|FAT_FAT32_EOC);
      break;

    default:
      ret_val = -1;
      errno = EINVAL;
    }
    if (fmt_params.fattype == FAT_FAT32) {
      /*
       * only first valid cluster (cluster number 2) belongs
       * to root directory, and is end of chain
       * mark this in every copy of the FAT
       */
      FAT_SET_VAL32(tmp_sec,8,FAT_FAT32_EOC);
    }

    start_sector = loc_align_object (fmt_params.rsvd_sector_cnt,
                                     fmt_params.sectors_per_cluster,
                                     fmt_params.skip_alignment);
    for (i = 0;
         (i < fmt_params.fat_num) && (ret_val == 0);
         i++) {
      ret_val = msdos_format_write_sec
        (fd,
         start_sector
         + (i * fmt_params.sectors_per_fat),
         fmt_params.bytes_per_sector,
         tmp_sec);
    }
  }
Exemple #4
0
/* msdos_creat_node --
 *     Create a new node. Determine if the name is a long name. If long we to
 *     scan the directory to create a short entry.
 *
 *



 *     If a new node is file, FAT 32 Bytes Directory
 *     Entry Structure is initialized, free space is found in parent
 *     directory and structure is written to the disk. In case of directory,
 *     all above steps present and also new cluster is allocated for a
 *     new directory and dot and dotdot nodes are created in alloceted cluster.
 *
 * PARAMETERS:
 *     parent_loc - parent (directory we are going to create node in)
 *     type       - new node type (file or directory)
 *     name       - new node name
 *     mode       - mode
 *     link_info  - fs_info of existing node for a pseudo "hard-link"
 *                  (see msdos_file.c, msdos_link for documentation)
 *
 * RETURNS:
 *     RC_OK on success, or -1 if error occured (errno set appropriately).
 *
 */
int
msdos_creat_node(const rtems_filesystem_location_info_t  *parent_loc,
                 fat_file_type_t                          type,
                 const char                              *name,
                 int                                      name_len,
                 mode_t                                   mode,
                 const fat_file_fd_t                     *link_fd)
{
    int               rc = RC_OK;
    ssize_t           ret = 0;
    msdos_fs_info_t  *fs_info = parent_loc->mt_entry->fs_info;
    fat_file_fd_t    *parent_fat_fd = parent_loc->node_access;
    fat_file_fd_t    *fat_fd = NULL;
    time_t            now;
    uint16_t          time_val = 0;
    uint16_t          date = 0;
    fat_dir_pos_t     dir_pos;
    msdos_name_type_t name_type;
    char              short_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
    char              dot_dotdot[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2];
    char              link_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];
    uint32_t          sec = 0;
    uint32_t          byte = 0;

    fat_dir_pos_init(&dir_pos);

    memset(short_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
    memset(dot_dotdot, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2);

    if (name_len > MSDOS_NAME_MAX_LFN_WITH_DOT) {
        rtems_set_errno_and_return_minus_one(ENAMETOOLONG);
    }

    name_type = msdos_long_to_short (fs_info->converter,
                                     name, name_len,
                                     MSDOS_DIR_NAME(short_node),
                                     MSDOS_NAME_MAX);
    if (name_type == MSDOS_NAME_INVALID) {
        rtems_set_errno_and_return_minus_one(EINVAL);
    }

    /* fill reserved field */
    *MSDOS_DIR_NT_RES(short_node) = MSDOS_RES_NT_VALUE;

    /* set up last write date and time */
    now = time(NULL);
    fat_file_set_ctime_mtime(parent_fat_fd, now);

    msdos_date_unix2dos(now, &date, &time_val);
    *MSDOS_DIR_CRT_TIME(short_node) = CT_LE_W(time_val);
    *MSDOS_DIR_CRT_DATE(short_node) = CT_LE_W(date);
    *MSDOS_DIR_WRITE_TIME(short_node) = CT_LE_W(time_val);
    *MSDOS_DIR_WRITE_DATE(short_node) = CT_LE_W(date);
    *MSDOS_DIR_LAST_ACCESS_DATE(short_node) = CT_LE_W(date);

    /* initialize directory/file size */
    *MSDOS_DIR_FILE_SIZE(short_node) = MSDOS_INIT_DIR_SIZE;

    if (type == FAT_DIRECTORY) {
      *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_DIRECTORY;
    }
    else if (type == FAT_HARD_LINK) {
      /*
       * when we establish a (temporary) hard link,
       * we must copy some information from the original
       * node to the newly created
       */
      /*
       * read the original directory entry
       */
      sec = fat_cluster_num_to_sector_num(&fs_info->fat,
                                          link_fd->dir_pos.sname.cln);
      sec += (link_fd->dir_pos.sname.ofs >> fs_info->fat.vol.sec_log2);
      byte = (link_fd->dir_pos.sname.ofs & (fs_info->fat.vol.bps - 1));

      ret = _fat_block_read(&fs_info->fat,
                            sec, byte, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
                            link_node);
      if (ret < 0) {
          return -1;
      }
      /*
       * copy various attributes
       */
      *MSDOS_DIR_ATTR(short_node)          =*MSDOS_DIR_ATTR(link_node);
      *MSDOS_DIR_CRT_TIME_TENTH(short_node)=*MSDOS_DIR_CRT_TIME_TENTH(link_node);
      *MSDOS_DIR_CRT_TIME(short_node)      =*MSDOS_DIR_CRT_TIME(link_node);
      *MSDOS_DIR_CRT_DATE(short_node)      =*MSDOS_DIR_CRT_DATE(link_node);

      /*
       * copy/set "file size", "first cluster"
       */
      *MSDOS_DIR_FILE_SIZE(short_node)     =*MSDOS_DIR_FILE_SIZE(link_node);

      *MSDOS_DIR_FIRST_CLUSTER_LOW(short_node) =
           *MSDOS_DIR_FIRST_CLUSTER_LOW(link_node);
      *MSDOS_DIR_FIRST_CLUSTER_HI(short_node) =
           *MSDOS_DIR_FIRST_CLUSTER_HI(link_node);
      /*
       * set "archive bit" due to changes
       */
      *MSDOS_DIR_ATTR(short_node) |= MSDOS_ATTR_ARCHIVE;
    }
/* msdos_find_name_in_fat_file --
 *     This routine is used in two ways: for a new mode creation (a) or for
 *     search the node which correspondes to the 'name' parameter (b).
 *     In case (a) name should be set up to NULL and 'name_dir_entry' should
 *     point to initialized 32 bytes structure described a new node.
 *     In case (b) 'name' should contain a valid string.
 *
 *     (a): reading fat-file corresponded to directory we are going to create
 *          node in. If found free slot write contents of name_dir_entry into
 *          it.
 *
 *     (b): reading fat-file corresponded to directory and trying to find slot
 *          with the name field == name parameter
 *
 * PARAMETERS:
 *     mt_entry       - mount table entry
 *     fat_fd         - fat-file descriptor
 *     name           - NULL or name to find
 *     paux           - identify a node location on the disk -
 *                      number of cluster and offset inside the cluster
 *     name_dir_entry - node to create/placeholder for found node
 *
 * RETURNS:
 *     RC_OK on success, or error code if error occured (errno set
 *     appropriately)
 *
 */
int msdos_find_name_in_fat_file(
    rtems_filesystem_mount_table_entry_t *mt_entry,
    fat_file_fd_t                        *fat_fd,
    char                                 *name,
    fat_auxiliary_t                      *paux,
    char                                 *name_dir_entry
    )
{
    int              rc = RC_OK;
    ssize_t          ret = 0;
    msdos_fs_info_t *fs_info = mt_entry->fs_info;
    uint32_t         i = 0, j = 0;
    uint32_t         bts2rd = 0;

    if (FAT_FD_OF_ROOT_DIR(fat_fd) &&
       (fs_info->fat.vol.type & (FAT_FAT12 | FAT_FAT16)))
        bts2rd = fat_fd->fat_file_size;
    else
        bts2rd = fs_info->fat.vol.bpc;

    while ((ret = fat_file_read(mt_entry, fat_fd, (j * bts2rd), bts2rd,
                                fs_info->cl_buf)) != FAT_EOF)
    {
        if (ret < MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
            set_errno_and_return_minus_one(EIO);

        assert(ret == bts2rd);

        /* have to look at the DIR_NAME as "raw" 8-bit data */
        for (i = 0; i < bts2rd; i += MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
        {
            /* is the entry empty ? */
            if (((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
                 MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY) ||
                 ((*(uint8_t *)MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
                 MSDOS_THIS_DIR_ENTRY_EMPTY))
            {
                /* whether we are looking for an empty entry */
                if (name == NULL)
                {
                    /* get current cluster number */
                    rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
                                        j * bts2rd, &paux->cln);
                    if (rc != RC_OK)
                        return rc;

                    /* offset is computed in bytes */
                    paux->ofs = i;

                    /* write new node entry */
                    ret = fat_file_write(mt_entry, fat_fd, j * bts2rd + i,
                                         MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE,
                                         (uint8_t *)name_dir_entry);
                    if (ret != MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE)
                        return -1;

                    /*
                     * we don't update fat_file_size here - it should not
                     * increase
                     */
                    return RC_OK;
                }

                /*
                 * if name != NULL and there is no more entries in the
                 * directory - return name-not-found
                 */
                if (((*MSDOS_DIR_NAME(fs_info->cl_buf + i)) ==
                     MSDOS_THIS_DIR_ENTRY_AND_REST_EMPTY))
                    return MSDOS_NAME_NOT_FOUND_ERR;
            }
            else
            {
                /* entry not empty and name != NULL -> compare names */
                if (name != NULL)
                {
                    if (strncmp(MSDOS_DIR_NAME((fs_info->cl_buf + i)), name,
                                MSDOS_SHORT_NAME_LEN) == 0)
                    {
                        /*
                         * we get the entry we looked for - fill auxiliary
                         * structure and copy all 32 bytes of the entry
                         */
                        rc = fat_file_ioctl(mt_entry, fat_fd, F_CLU_NUM,
                                            j * bts2rd, &paux->cln);
                        if (rc != RC_OK)
                            return rc;

                        /* offset is computed in bytes */
                        paux->ofs = i;
                        memcpy(name_dir_entry,(fs_info->cl_buf + i),
                               MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);
                        return RC_OK;
                    }
                }
            }
        }
        j++;
    }
    return MSDOS_NAME_NOT_FOUND_ERR;
}
/* msdos_find_name --
 *     Find the node which correspondes to the name, open fat-file which
 *     correspondes to the found node and close fat-file which correspondes
 *     to the node we searched in.
 *
 * PARAMETERS:
 *     parent_loc - parent node description
 *     name       - name to find
 *
 * RETURNS:
 *     RC_OK and updated 'parent_loc' on success, or -1 if error
 *     occured (errno set apropriately)
 *
 */
int
msdos_find_name(
    rtems_filesystem_location_info_t *parent_loc,
    char                             *name
    )
{
    int              rc = RC_OK;
    msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info;
    fat_file_fd_t   *fat_fd = NULL;
    fat_auxiliary_t  aux;
    unsigned short   time_val = 0;
    unsigned short   date = 0;
    char             node_entry[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE];

    memset(node_entry, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE);

    /*
     * find the node which correspondes to the name in the directory pointed by
     * 'parent_loc'
     */
    rc = msdos_get_name_node(parent_loc, name, &aux, node_entry);
    if (rc != RC_OK)
        return rc;

    /* open fat-file corresponded to the found node */
    rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd);
    if (rc != RC_OK)
        return rc;

    /*
     * I don't like this if, but: we should do it , or should write new file
     * size and first cluster num to the disk after each write operation
     * (even if one byte is written  - that is TOO non-optimize) because
     * otherwise real values of these fields stored in fat-file descriptor
     * may be accidentely rewritten with wrong values stored on the disk
     */
    if (fat_fd->links_num == 1)
    {
        fat_fd->info_cln = aux.cln;
        fat_fd->info_ofs = aux.ofs;
        fat_fd->cln = MSDOS_EXTRACT_CLUSTER_NUM(node_entry);
        fat_fd->first_char = *MSDOS_DIR_NAME(node_entry);

        time_val = *MSDOS_DIR_WRITE_TIME(node_entry);
        date = *MSDOS_DIR_WRITE_DATE(node_entry);

        fat_fd->mtime = msdos_date_dos2unix(CF_LE_W(time_val), CF_LE_W(date));

        if ((*MSDOS_DIR_ATTR(node_entry)) & MSDOS_ATTR_DIRECTORY)
        {
            fat_fd->fat_file_type = FAT_DIRECTORY;
            fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT;

            rc = fat_file_size(parent_loc->mt_entry, fat_fd);
            if (rc != RC_OK)
            {
                fat_file_close(parent_loc->mt_entry, fat_fd);
                return rc;
            }
        }
        else
        {
            fat_fd->fat_file_size = CF_LE_L(*MSDOS_DIR_FILE_SIZE(node_entry));
            fat_fd->fat_file_type = FAT_FILE;
            fat_fd->size_limit = MSDOS_MAX_FILE_SIZE;
        }

        /* these data is not actual for zero-length fat-file */
        fat_fd->map.file_cln = 0;
        fat_fd->map.disk_cln = fat_fd->cln;

        if ((fat_fd->fat_file_size != 0) &&
            (fat_fd->fat_file_size <= fs_info->fat.vol.bpc))
        {
            fat_fd->map.last_cln = fat_fd->cln;
        }
        else
        {
            fat_fd->map.last_cln = FAT_UNDEFINED_VALUE;
        }
    }

    /* close fat-file corresponded to the node we searched in */
    rc = fat_file_close(parent_loc->mt_entry, parent_loc->node_access);
    if (rc != RC_OK)
    {
        fat_file_close(parent_loc->mt_entry, fat_fd);
        return rc;
    }

    /* update node_info_ptr field */
    parent_loc->node_access = fat_fd;

    return rc;
}