📄 rdcf2.c
字号:
memcpy (f->file.spec, d->name_extension, NAME_SIZE + EXTENSION_SIZE); f->file.spec[NAME_SIZE + EXTENSION_SIZE] = 0; } else name_extension_to_spec (f->file.spec, d->name_extension); f->file.attribute = d->attribute; { ushort date = d->date;#ifdef _BIG_ENDIAN convert_short (date);#endif f->file.date_and_time.year = (date >> 9) + 1980; f->file.date_and_time.month = date >> 5 & 0xF; f->file.date_and_time.day = date & 0x1F; } { ushort aTime = d->time;#ifdef _BIG_ENDIAN convert_short (time);#endif f->file.date_and_time.hour = aTime >> 11; f->file.date_and_time.minute = aTime >> 5 & 0x3F; f->file.date_and_time.second = aTime << 1 & 0x1F << 1; } f->file.first_cluster = d->first_cluster; f->file.size = d->size;#ifdef _BIG_ENDIAN convert_short (f->file.first_cluster); convert_long (f->file.size);#endif}/*-----------------------------------------------------------------------------If the parameter "name_extension" is not NULL, this function looks up the nameand extension in the directory specified by f->directory_cluster (the entireroot directory if f->directory_cluster == 0). If found, it puts the appropriateinformation into the file structure and returns a true (nonzero) result. If notfound, it returns a false (zero) value and also puts the cluster and index ofthe first empty entry, if any, into f->directory_cluster andf->directory_index. In any case, the name and extension are left inf->file.spec, and the first directory cluster is left inf->directory_first_cluster.If the parameter name_extension is NULL, this function looks up the volumelabel in the same way (although in this case the calling function looks only inthe root directory, of course).If the file or volume label is not found and there is no empty entry, thespecial value NO_DIRECTORY_INDEX is left in f->directory_index.-----------------------------------------------------------------------------*/static int find_file_in_directory_or_find_volume (struct rdcf *f, const uint8_t * name_extension){ unsigned empty_cluster = 2; unsigned empty_index = NO_DIRECTORY_INDEX; unsigned number_of_directory_entries = f->directory_cluster == 0 ? (f->first_data_sector - f->first_directory_sector) * ENTRIES_PER_SECTOR : ENTRIES_PER_SECTOR * f->sectors_per_cluster; f->directory_first_cluster = f->directory_cluster; while (1) { for (f->directory_index = 0; f->directory_index < number_of_directory_entries; f->directory_index++) { struct directory *d = find_directory (f); if ((d->name_extension[0] == DELETED_FILE || d->name_extension[0] == END_DIRECTORY) && empty_index == NO_DIRECTORY_INDEX) { empty_cluster = f->directory_cluster; empty_index = f->directory_index; } if (d->name_extension[0] == END_DIRECTORY) break; if ((name_extension == NULL && (d->name_extension[0] != DELETED_FILE && d->attribute & RDCF_VOLUME)) || (name_extension != NULL && (memcmp (d->name_extension, name_extension, NAME_SIZE + EXTENSION_SIZE) == 0 && (d-> attribute & RDCF_VOLUME) == 0))) { read_directory_entry (f); return 1; } } if (f->directory_index < number_of_directory_entries || f->directory_cluster == 0) { break; } { unsigned x = FAT_entry (f, f->directory_cluster); if (x >= f->last_cluster_mark) break; f->directory_cluster = x; } } f->directory_index = empty_index; if (f->directory_index != NO_DIRECTORY_INDEX) f->directory_cluster = empty_cluster; if (name_extension != NULL) name_extension_to_spec (f->file.spec, name_extension); return 0;}/*-----------------------------------------------------------------------------This function follows the directory path and finds the directory entry for thefile (or directory) with the spec provided. If found, it reads the directoryinformation into the FCB and returns a true (nonzero) value. Otherwise, itreturns a false (zero) value and also puts the cluster and index of the firstavailable directory entry, if any, into f->directory_cluster andf->directory_index. If there is no available directory entry, it puts thespecial value NO_DIRECTORY_INDEX into f->directory_index. In any case, thenumber of the first cluster of the directory is left inf->directory_first_cluster and the name and extension are left in f->file.spec.-----------------------------------------------------------------------------*/static int find_file (struct rdcf *f, const char *spec){ /* start with root directory */ f->directory_cluster = 0; while (1) { int found; uint8_t name_extension[NAME_SIZE + EXTENSION_SIZE]; /* scan name and extension */ spec = spec_to_name_extension (f, name_extension, spec); /* look it up in directory */ found = find_file_in_directory_or_find_volume (f, name_extension); /* if this is the end of the file specification, return */ if (*spec == 0) return found; /* otherwise, the name and extension were a subdirectory in the path */ if (!found || (f->file.attribute & RDCF_DIRECTORY) == 0) error_exit (f, ~EISDIR); f->directory_cluster = f->file.first_cluster; /* skip over the \ after the subdirectory */ spec++; }}/*-----------------------------------------------------------------------------This function refers to data alread read from the file system partition info.-----------------------------------------------------------------------------*/static void read_file_system_information (struct rdcf *f){ f->first_FAT_sector = DriveDesc.FirstFatSector; f->sectors_per_FAT = DriveDesc.SectorsPerFAT; f->sectors_per_cluster = DriveDesc.SectorsPerCluster; f->first_directory_sector = DriveDesc.RootDirSector; f->first_data_sector = DriveDesc.DataStartSector; f->maximum_cluster_number = ((DriveDesc.MaxDataSector - DriveDesc.DataStartSector) / DriveDesc.SectorsPerCluster) + 1; f->last_cluster_mark = f->maximum_cluster_number < RESERVED_CLUSTER_12_BIT ? LAST_CLUSTER_12_BIT : LAST_CLUSTER_16_BIT;}/*-----------------------------------------------------------------------------This function gets the drive specifications and returns a pointer to thecharacter following the drive specifications.-----------------------------------------------------------------------------*/#ifdef RDCF_MULTIPLE_DRIVE#error "multiple drives has not been implemented!"static char *get_drive (struct rdcf *f, char *spec){ if (spec[0] != 0 && spec[1] == ':') { if (isalpha (spec[0])) f->drive = toupper (spec[0]) - 'A'; else error_exit (f, ~EINVAL); return spec + 2; } error_exit (f, ~EINVAL);}#endif/*-----------------------------------------------------------------------------This function scans the file spec and sets up the file control block forfurther file operations. It returns a pointer to the character following thedrive specifications.-----------------------------------------------------------------------------*/static const char *initialize_fcb (struct rdcf *f, const char *spec){ f->buffer_status = EMPTY; read_file_system_information (f); return spec;}/*-----------------------------------------------------------------------------This function checks write access and generates an error if write access isdenied.-----------------------------------------------------------------------------*/static void check_write_access (struct rdcf *f){ if (f->file.attribute & (RDCF_READ_ONLY + RDCF_HIDDEN + RDCF_SYSTEM)) error_exit (f, ~EACCES);}/*-----------------------------------------------------------------------------This function releases all the FAT entries of a file.-----------------------------------------------------------------------------*/static void release_FAT_entries (struct rdcf *f){ unsigned j; j = f->file.first_cluster; if (j != EMPTY_CLUSTER) { while (j < f->last_cluster_mark && j) { unsigned k = FAT_entry (f, j); if (j < DriveDesc.FirstPossiblyEmptyCluster) { DriveDesc.FirstPossiblyEmptyCluster = j; } set_FAT_entry (f, j, EMPTY_CLUSTER); j = k; } } f->mode |= WRITTEN;}/*-----------------------------------------------------------------------------This function finds a new cluster, if possible, and adds it to a chain endingwith the specified cluster. It returns the new cluster number, orEMPTY_CLUSTER if there are no free clusters.-----------------------------------------------------------------------------*/static unsigned add_new_cluster (struct rdcf *f, unsigned cluster){ unsigned new_cluster; for (new_cluster = DriveDesc.FirstPossiblyEmptyCluster; new_cluster <= f->maximum_cluster_number; new_cluster++) { if (FAT_entry (f, new_cluster) == EMPTY_CLUSTER) break; } if (new_cluster > f->maximum_cluster_number) return EMPTY_CLUSTER; if (cluster != EMPTY_CLUSTER) set_FAT_entry (f, cluster, new_cluster); set_FAT_entry (f, new_cluster, f->last_cluster_mark); return new_cluster;}/*-----------------------------------------------------------------------------This function writes zeros into a cluster.-----------------------------------------------------------------------------*/static void clear_cluster (struct rdcf *f, unsigned cluster){ unsigned count = f->sectors_per_cluster; unsigned sector = first_sector_in_cluster (f, cluster); flush_buffer (f); f->buffer_status = EMPTY; memset (f->buffer.buf, 0, SECTOR_SIZE); do write_sector (f, sector++, f->buffer.buf); while (--count != 0);}/*-----------------------------------------------------------------------------This function adds another cluster to the directory if necessary to accommodatea new file or subdirectory.-----------------------------------------------------------------------------*/static void lengthen_directory_if_necessary (struct rdcf *f){ if (f->directory_index == NO_DIRECTORY_INDEX) { if (f->directory_cluster == 0) error_exit (f, ~ENOSPC); f->directory_cluster = add_new_cluster (f, f->directory_cluster); if (f->directory_cluster == 0) error_exit (f, ~ENOSPC); f->directory_index = 0; clear_cluster (f, f->directory_cluster); }}/*-----------------------------------------------------------------------------The following functions are publicly defined. They do not call each other andany of them may be removed without making changes to those that remain. Thefunctions are defined in alphabetical order.-----------------------------------------------------------------------------*/#define CHANGEABLE_ATTRIBUTES \ (RDCF_ARCHIVE+RDCF_HIDDEN+RDCF_READ_ONLY+RDCF_SYSTEM)int rdcf_close (struct rdcf *f){ if ((f->result = setjmp (f->error)) != 0) return f->result; if (f->mode & WRITTEN) { f->buffer_status = EMPTY; f->file.attribute |= RDCF_ARCHIVE; rdcf_get_date_and_time (&f->file.date_and_time); // do not allow empty files. update_directory_entry (f, (f->file.size) ? 0 : 1); flush_buffer (f); } return 0;}int rdcf_delete (struct rdcf *f, const char *spec){ if ((f->result = setjmp (f->error)) != 0) return f->result; spec = initialize_fcb (f, spec); if (*spec == 0) { /* delete volume label */ if (!find_file_in_directory_or_find_volume (f, NULL)) error_exit (f, ~ENOENT); } else if (!find_file (f, spec)) error_exit (f, ~ENOENT); /* check to see that a directory is empty before deleting it */ else if (f->file.attribute & RDCF_DIRECTORY) { unsigned cluster = f->file.first_cluster; while (cluster != EMPTY_CLUSTER && cluster < f->last_cluster_mark) { unsigned sector = first_sector_in_cluster (f, cluster); unsigned sector_count = f->sectors_per_cluster; unsigned next_cluster = FAT_entry (f, cluster); do { unsigned entry_count = ENTRIES_PER_SECTOR; uint8_t *p = f->buffer.buf; read_buffer (f, sector); do { unsigned c = *p; if (c == END_DIRECTORY) break; if (c != DELETED_FILE && c != '.') error_exit (f, ~EACCES); p += sizeof (struct directory); } while (--entry_count != 0); if (entry_count != 0) break; } while (--sector_count != 0); cluster = next_cluster; } } else check_write_access (f); release_FAT_entries (f); update_directory_entry (f, 1); flush_buffer (f); return 0;}int rdcf_rename (struct rdcf *f, const char *old_spec, const char *new_spec){ uint8_t name_extension[NAME_SIZE + EXTENSION_SIZE]; if ((f->result = setjmp (f->error)) != 0) return f->result; old_spec = initialize_fcb (f, old_spec); if (!find_file (f, old_spec)) error_exit (f, ~ENOENT); if (f->file.attribute & (RDCF_HIDDEN + RDCF_SYSTEM)) error_exit (f, ~EACCES); spec_to_name_extension (f, name_extension, new_spec); f->directory_cluster = f->directory_first_cluster; if (find_file_in_directory_or_find_volume (f, name_extension)) error_exit (f, ~ENOENT); find_file (f, old_spec); name_extension_to_spec (f->file.spec, name_extension); update_directory_entry (f, 0); flush_buffer (f); return 0;}int rdcf_open (struct rdcf *f, const char *spec, unsigned mode){ int found; if ((f->result = setjmp (f->error)) != 0) return f->result; // printf("mode: 0x%xd\n", mode); // does it exist already ? found = find_file (f, initialize_fcb (f, spec)); // is it a directory ? if (found && f->file.attribute & RDCF_DIRECTORY) error_exit (f, ~EISDIR); // see how to open the file if (mode & O_CREAT) { // printf("O_CREAT\n"); bool new_file = false; if (mode & O_TRUNC && found) { // printf(" O_TRUNC and found\n"); // TRUNC and CREATE and found -> empty the file of clusters check_write_access (f); release_FAT_entries (f); new_file = true; } else if (!found) { // printf(" not O_TRUNC, not found\n"); // CREATE and not found -> create a new file lengthen_directory_if_necessary (f); new_file = true; } // if found and APPEND, don't do anything to it (new_file = false) // write back any changes we made here if (new_file) { // printf(" new_file = true\n"); f->file.attribute = RDCF_ARCHIVE; rdcf_get_date_and_time (&f->file.date_and_time);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -