/* 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; }
/*=========================================================================*\ | 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); } }
/* 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; }