[f36a7bfc] | 1 | /* |
---|
| 2 | * Routine to create a new MSDOS filesystem node |
---|
| 3 | * |
---|
| 4 | * Copyright (C) 2001 OKTET Ltd., St.-Petersburg, Russia |
---|
| 5 | * Author: Eugeny S. Mints <Eugeny.Mints@oktet.ru> |
---|
| 6 | * |
---|
| 7 | * The license and distribution terms for this file may be |
---|
| 8 | * found in the file LICENSE in this distribution or at |
---|
| 9 | * http://www.OARcorp.com/rtems/license.html. |
---|
| 10 | * |
---|
| 11 | * @(#) $Id$ |
---|
| 12 | * |
---|
| 13 | */ |
---|
| 14 | #if HAVE_CONFIG_H |
---|
| 15 | #include "config.h" |
---|
| 16 | #endif |
---|
| 17 | |
---|
| 18 | #include <errno.h> |
---|
| 19 | #include <assert.h> |
---|
| 20 | #include <stdlib.h> |
---|
| 21 | #include <string.h> |
---|
| 22 | #include <rtems/libio_.h> |
---|
| 23 | #include <time.h> |
---|
| 24 | |
---|
| 25 | #include "fat.h" |
---|
| 26 | #include "fat_fat_operations.h" |
---|
| 27 | #include "fat_file.h" |
---|
| 28 | |
---|
| 29 | #include "msdos.h" |
---|
| 30 | |
---|
| 31 | /* msdos_creat_node -- |
---|
| 32 | * Create a new node. If a new node is file, FAT 32 Bytes Directory |
---|
| 33 | * Entry Structure (see M$ White Paper) is initialized, free space is |
---|
| 34 | * found in parent directory and structure is written to the disk. |
---|
| 35 | * In case of directory, all above steps present and also new cluster |
---|
| 36 | * is allocated for a new directory and dot and dotdot nodes are created |
---|
| 37 | * in alloceted cluster. |
---|
| 38 | * |
---|
| 39 | * PARAMETERS: |
---|
| 40 | * parent_loc - parent (directory we are going to create node in) |
---|
| 41 | * type - new node type (file or directory) |
---|
| 42 | * name - new node name |
---|
| 43 | * mode - mode |
---|
| 44 | * |
---|
| 45 | * RETURNS: |
---|
| 46 | * RC_OK on success, or -1 if error occured (errno set appropriately). |
---|
| 47 | * |
---|
| 48 | */ |
---|
| 49 | int |
---|
| 50 | msdos_creat_node( |
---|
| 51 | rtems_filesystem_location_info_t *parent_loc, |
---|
| 52 | msdos_node_type_t type, |
---|
| 53 | char *name, |
---|
| 54 | mode_t mode |
---|
| 55 | ) |
---|
| 56 | { |
---|
| 57 | int rc = RC_OK; |
---|
| 58 | ssize_t ret = 0; |
---|
| 59 | msdos_fs_info_t *fs_info = parent_loc->mt_entry->fs_info; |
---|
| 60 | fat_file_fd_t *parent_fat_fd = parent_loc->node_access; |
---|
| 61 | fat_file_fd_t *fat_fd = NULL; |
---|
| 62 | time_t time_ret = 0; |
---|
| 63 | unsigned16 time_val = 0; |
---|
| 64 | unsigned16 date = 0; |
---|
| 65 | fat_auxiliary_t aux; |
---|
| 66 | unsigned char new_node[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE]; |
---|
| 67 | unsigned char dot_dotdot[MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2]; |
---|
| 68 | |
---|
| 69 | memset(new_node, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); |
---|
| 70 | memset(dot_dotdot, 0, MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2); |
---|
| 71 | |
---|
| 72 | /* set up name */ |
---|
| 73 | strncpy(MSDOS_DIR_NAME(new_node), name, MSDOS_NAME_MAX); |
---|
| 74 | |
---|
| 75 | /* fill reserved field */ |
---|
| 76 | *MSDOS_DIR_NT_RES(new_node) = MSDOS_RES_NT_VALUE; |
---|
| 77 | |
---|
| 78 | /* set up last write date and time */ |
---|
| 79 | time_ret = time(NULL); |
---|
| 80 | if ( time_ret == -1 ) |
---|
| 81 | return -1; |
---|
| 82 | |
---|
| 83 | msdos_date_unix2dos(time_ret, &time_val, &date); |
---|
| 84 | *MSDOS_DIR_WRITE_TIME(new_node) = CT_LE_W(time_val); |
---|
| 85 | *MSDOS_DIR_WRITE_DATE(new_node) = CT_LE_W(date); |
---|
| 86 | |
---|
| 87 | /* initialize directory/file size */ |
---|
| 88 | *MSDOS_DIR_FILE_SIZE(new_node) = MSDOS_INIT_DIR_SIZE; |
---|
| 89 | |
---|
| 90 | if (type == MSDOS_DIRECTORY) |
---|
| 91 | *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_DIRECTORY; |
---|
| 92 | else |
---|
| 93 | *MSDOS_DIR_ATTR(new_node) |= MSDOS_ATTR_ARCHIVE; |
---|
| 94 | |
---|
| 95 | /* |
---|
| 96 | * find free space in the parent directory and write new initialized |
---|
| 97 | * FAT 32 Bytes Directory Entry Structure (see M$ White Paper) |
---|
| 98 | * to the disk |
---|
| 99 | */ |
---|
| 100 | rc = msdos_get_name_node(parent_loc, NULL, &aux, new_node); |
---|
| 101 | if ( rc != RC_OK ) |
---|
| 102 | return rc; |
---|
| 103 | |
---|
| 104 | /* |
---|
| 105 | * if we create a new file we are done, if directory there are more steps |
---|
| 106 | * to do |
---|
| 107 | */ |
---|
| 108 | if (type == MSDOS_DIRECTORY) |
---|
| 109 | { |
---|
| 110 | /* open new directory as fat-file */ |
---|
| 111 | rc = fat_file_open(parent_loc->mt_entry, aux.cln, aux.ofs, &fat_fd); |
---|
| 112 | if (rc != RC_OK) |
---|
| 113 | goto err; |
---|
| 114 | |
---|
| 115 | /* |
---|
| 116 | * we opened fat-file for node we just created, so initialize fat-file |
---|
| 117 | * descritor |
---|
| 118 | */ |
---|
| 119 | fat_fd->info_cln = aux.cln; |
---|
| 120 | fat_fd->info_ofs = aux.ofs; |
---|
| 121 | fat_fd->fat_file_size = 0; |
---|
| 122 | fat_fd->fat_file_type = FAT_DIRECTORY; |
---|
| 123 | fat_fd->size_limit = MSDOS_MAX_DIR_LENGHT; |
---|
| 124 | |
---|
| 125 | /* |
---|
| 126 | * dot and dotdot entries are identical to new node except the |
---|
| 127 | * names |
---|
| 128 | */ |
---|
| 129 | memcpy(DOT_NODE_P(dot_dotdot), new_node, |
---|
| 130 | MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); |
---|
| 131 | memcpy(DOTDOT_NODE_P(dot_dotdot), new_node, |
---|
| 132 | MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE); |
---|
| 133 | memcpy(MSDOS_DIR_NAME(DOT_NODE_P(dot_dotdot)), MSDOS_DOT_NAME, |
---|
| 134 | MSDOS_NAME_MAX); |
---|
| 135 | memcpy(MSDOS_DIR_NAME(DOTDOT_NODE_P(dot_dotdot)), MSDOS_DOTDOT_NAME, |
---|
| 136 | MSDOS_NAME_MAX); |
---|
| 137 | |
---|
| 138 | /* set up cluster num for dotdot entry */ |
---|
| 139 | /* |
---|
| 140 | * here we can ommit FAT32 condition because for all FAT types dirs |
---|
| 141 | * right under root dir should contain 0 in dotdot entry but for |
---|
| 142 | * FAT12/16 parent_fat_fd->cluster_num always contains such value |
---|
| 143 | */ |
---|
| 144 | if ((FAT_FD_OF_ROOT_DIR(parent_fat_fd)) && |
---|
| 145 | (fs_info->fat.vol.type & FAT_FAT32)) |
---|
| 146 | { |
---|
| 147 | *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) = 0x0000; |
---|
| 148 | *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) = 0x0000; |
---|
| 149 | } |
---|
| 150 | else |
---|
| 151 | { |
---|
| 152 | *MSDOS_DIR_FIRST_CLUSTER_LOW(DOTDOT_NODE_P(dot_dotdot)) = |
---|
| 153 | CT_LE_W((unsigned16)((parent_fat_fd->cln) & 0x0000FFFF)); |
---|
| 154 | *MSDOS_DIR_FIRST_CLUSTER_HI(DOTDOT_NODE_P(dot_dotdot)) = |
---|
| 155 | CT_LE_W((unsigned16)(((parent_fat_fd->cln) & 0xFFFF0000)>>16)); |
---|
| 156 | } |
---|
| 157 | |
---|
| 158 | /* |
---|
| 159 | * write dot and dotdot entries to new fat-file: currently fat-file |
---|
| 160 | * correspondes to a new node is zero length, so it will be extended |
---|
| 161 | * by one cluster and entries will be written |
---|
| 162 | */ |
---|
| 163 | ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0, |
---|
| 164 | MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE * 2, |
---|
| 165 | dot_dotdot); |
---|
| 166 | if (ret < 0) |
---|
| 167 | { |
---|
| 168 | rc = -1; |
---|
| 169 | goto error; |
---|
| 170 | } |
---|
| 171 | |
---|
| 172 | /* increment fat-file size by cluster size */ |
---|
| 173 | fat_fd->fat_file_size += fs_info->fat.vol.bpc; |
---|
| 174 | |
---|
| 175 | /* set up cluster num for dot entry */ |
---|
| 176 | *MSDOS_DIR_FIRST_CLUSTER_LOW(DOT_NODE_P(dot_dotdot)) = |
---|
| 177 | CT_LE_W((unsigned16)((fat_fd->cln) & 0x0000FFFF)); |
---|
| 178 | *MSDOS_DIR_FIRST_CLUSTER_HI(DOT_NODE_P(dot_dotdot)) = |
---|
| 179 | CT_LE_W((unsigned16)(((fat_fd->cln) & 0xFFFF0000) >> 16)); |
---|
| 180 | |
---|
| 181 | /* rewrite dot entry */ |
---|
| 182 | ret = fat_file_write(parent_loc->mt_entry, fat_fd, 0, |
---|
| 183 | MSDOS_DIRECTORY_ENTRY_STRUCT_SIZE, |
---|
| 184 | DOT_NODE_P(dot_dotdot)); |
---|
| 185 | if (ret < 0) |
---|
| 186 | { |
---|
| 187 | rc = -1; |
---|
| 188 | goto error; |
---|
| 189 | } |
---|
| 190 | |
---|
| 191 | /* write first cluster num of a new directory to disk */ |
---|
| 192 | rc = msdos_set_first_cluster_num(parent_loc->mt_entry, fat_fd); |
---|
| 193 | if (rc != RC_OK) |
---|
| 194 | goto error; |
---|
| 195 | |
---|
| 196 | fat_file_close(parent_loc->mt_entry, fat_fd); |
---|
| 197 | } |
---|
| 198 | return RC_OK; |
---|
| 199 | |
---|
| 200 | error: |
---|
| 201 | fat_file_close(parent_loc->mt_entry, fat_fd); |
---|
| 202 | |
---|
| 203 | err: |
---|
| 204 | /* mark 32bytes structure on the disk as free */ |
---|
| 205 | msdos_set_first_char4file_name(parent_loc->mt_entry, aux.cln, aux.ofs, |
---|
| 206 | 0xE5); |
---|
| 207 | return rc; |
---|
| 208 | } |
---|