/** * KFile read/write test. * This function write and read \a test_buf long \a size * on \a fd handler. * \a save_buf can be NULL or a buffer where to save previous file content. */ int kfile_testRunGeneric(KFile *fd, uint8_t *test_buf, uint8_t *save_buf, size_t size) { /* * Part of test buf size that you would write. * This var is used in test 3 to check kfile_write * when writing beyond filesize limit. */ kfile_off_t len = size / 2; /* Fill test buffer */ for (size_t i = 0; i < size; i++) test_buf[i] = (i & 0xff); /* * If necessary, user can save content, * for later restore. */ if (save_buf) { LOG_INFO("Saved content..form [%ld] to [%ld]\n", fd->seek_pos, fd->seek_pos + size); kfile_read(fd, save_buf, size); } /* TEST 1 BEGIN. */ LOG_INFO("Test 1: write from pos 0 to [%ld]\n", (long)size); /* * Seek to addr 0. */ if (kfile_seek(fd, 0, KSM_SEEK_SET) != 0) goto kfile_test_end; /* * Test read/write to address 0..size */ if (!kfile_rwTest(fd, test_buf, size)) goto kfile_test_end; LOG_INFO("Test 1: ok!\n"); /* * Restore previous read content. */ if (save_buf) { kfile_seek(fd, 0, KSM_SEEK_SET); if (kfile_write(fd, save_buf, size) != size) goto kfile_test_end; LOG_INFO("Restore content..form [%ld] to [%ld]\n", fd->seek_pos, fd->seek_pos + size); } /* TEST 1 END. */ /* TEST 2 BEGIN. */ LOG_INFO("Test 2: write from pos [%ld] to [%ld]\n", fd->size/2 , fd->size/2 + size); /* * Go to half test size. */ kfile_seek(fd, (fd->size / 2), KSM_SEEK_SET); /* * If necessary, user can save content * for later restore. */ if (save_buf) { kfile_read(fd, save_buf, size); kfile_seek(fd, -(kfile_off_t)size, KSM_SEEK_CUR); LOG_INFO("Saved content..form [%ld] to [%ld]\n", fd->seek_pos, fd->seek_pos + size); } /* * Test read/write to address filesize/2 ... filesize/2 + size */ if (!kfile_rwTest(fd, test_buf, size)) goto kfile_test_end; LOG_INFO("Test 2: ok!\n"); /* * Restore previous content. */ if (save_buf) { kfile_seek(fd, -(kfile_off_t)size, KSM_SEEK_CUR); if (kfile_write(fd, save_buf, size) != size) goto kfile_test_end; LOG_INFO("Restore content..form [%ld] to [%ld]\n", fd->seek_pos, fd->seek_pos + size); } /* TEST 2 END. */ /* TEST 3 BEGIN. */ LOG_INFO("Test 3: write outside of fd->size limit [%ld]\n", fd->size); /* * Go to the Flash end */ kfile_seek(fd, -len, KSM_SEEK_END); /* * If necessary, user can save content, * for later restore. */ if (save_buf) { kfile_read(fd, save_buf, len); kfile_seek(fd, -len, KSM_SEEK_CUR); LOG_INFO("Saved content..form [%ld] to [%ld]\n", fd->seek_pos, fd->seek_pos + len); } /* * Test read/write to address (filesize - size) ... filesize */ if (kfile_rwTest(fd, test_buf, size)) goto kfile_test_end; kprintf("Test 3: ok!\n"); /* * Restore previous read content */ if (save_buf) { kfile_seek(fd, -len, KSM_SEEK_END); if ((kfile_off_t)kfile_write(fd, save_buf, len) != len) goto kfile_test_end; LOG_INFO("Restore content..form [%ld] to [%ld]\n", fd->seek_pos, fd->seek_pos + len); } /* TEST 3 END. */ kfile_close(fd); return 0; kfile_test_end: kfile_close(fd); LOG_ERR("One kfile_test failed!\n"); return EOF; }
/* * ext3301: modified to encrypt/decrypt files moving to/from * an encrypted folder. * Rename still succeeds if an encrypt/decrypt operation fails. */ static int ext2_rename (struct inode * old_dir, struct dentry * old_dentry, struct inode * new_dir, struct dentry * new_dentry ) { struct inode * old_inode = old_dentry->d_inode; struct inode * new_inode = new_dentry->d_inode; struct page * dir_page = NULL; struct ext2_dir_entry_2 * dir_de = NULL; struct page * old_page; struct ext2_dir_entry_2 * old_de; int err = -ENOENT; bool is_encryptable, src_encrypt, dest_encrypt; int i; struct file * fcrypt; ssize_t nchunk, nread, nwritten; loff_t fpos, fseekpos; unsigned int fsize, fremaining; char * buf, * strbuf1, * strbuf2, * path_src, * path_dest; size_t blocksize = INODE_BLKSIZE(old_inode); // dquot_initialize(old_dir); dquot_initialize(new_dir); old_de = ext2_find_entry (old_dir, &old_dentry->d_name, &old_page); if (!old_de) goto out; if (S_ISDIR(old_inode->i_mode)) { err = -EIO; dir_de = ext2_dotdot(old_inode, &dir_page); if (!dir_de) goto out_old; } if (new_inode) { struct page *new_page; struct ext2_dir_entry_2 *new_de; err = -ENOTEMPTY; if (dir_de && !ext2_empty_dir (new_inode)) goto out_dir; err = -ENOENT; new_de = ext2_find_entry (new_dir, &new_dentry->d_name, &new_page); if (!new_de) goto out_dir; ext2_set_link(new_dir, new_de, new_page, old_inode, 1); new_inode->i_ctime = CURRENT_TIME_SEC; if (dir_de) drop_nlink(new_inode); inode_dec_link_count(new_inode); } else { err = ext2_add_link(new_dentry, old_inode); if (err) goto out_dir; if (dir_de) inode_inc_link_count(new_dir); } // allocate buffers strbuf1 = kmalloc((size_t)512, GFP_KERNEL); strbuf2 = kmalloc((size_t)512, GFP_KERNEL); buf = kmalloc(blocksize, GFP_KERNEL); if (!buf || !strbuf1 || !strbuf2) return -ENOMEM; // check if the source XOR destination lie under /encrypt, // and both entries are regular or immediate files is_encryptable = (I_ISIM(old_inode) || I_ISREG(old_inode)); src_encrypt = ext3301_isencrypted(old_dentry); dest_encrypt = ext3301_isencrypted(new_dentry); path_src = ext3301_getpath(old_dentry, strbuf1, blocksize); path_dest = ext3301_getpath(new_dentry, strbuf2, blocksize); // decide whether to encrypt dbg(KERN_DEBUG "rename (%s --> %s)\n", path_src, path_dest); if (is_encryptable) { dbg_cr(KERN_DEBUG "- File encryptable type (regular/immediate)\n"); if (src_encrypt && dest_encrypt) { dbg_cr(KERN_DEBUG "- File moving inside /encrypt (no change))\n"); } else if (src_encrypt) { dbg_cr(KERN_DEBUG "- File moving out of /encrypt. Decrypting..\n"); goto cryptstart; } else if (dest_encrypt) { dbg_cr(KERN_DEBUG "- File moving into /encrypt. Encrypting..\n"); goto cryptstart; } else { dbg_cr(KERN_DEBUG "- Src/dest directories not encryptable\n"); } } else { dbg_cr(KERN_DEBUG "- File not an encryptable type\n"); } goto cryptdone; /* encrypt/decrypt file */ cryptstart: // open file if (!path_src) goto cryptfail; fcrypt = kfile_open(path_src, O_RDWR); if (!fcrypt) goto cryptfail; fsize = FILP_FSIZE(fcrypt); fremaining = fsize; fpos = 0; fseekpos = 0; dbg_cr(KERN_DEBUG " - Opened %s (Fsize: %d)\n", FILP_NAME(fcrypt), fsize); // special case: nothing to encrypt if (fsize==0) goto cryptclose; // loop: read, encrypt, write while (fremaining > 0) { // choose a chunk size nchunk = (fremaining > blocksize ? blocksize : (ssize_t)fremaining); dbg_cr(KERN_DEBUG " - Starting a %d-byte chunk at pos %u.\n", (int)nchunk, (unsigned int)fpos); // read a chunk; make sure we read all bytes requested. fpos = fseekpos; nread = kfile_read(fcrypt, buf, (size_t)nchunk, &fpos); // this inequality covers error conditions (nread<0) and // partial reads (0<=nread<=nchunk && nread != nchunk) if (nread != nchunk) { kfile_close(fcrypt); goto cryptfail; } // encrypt the buffer for (i=0; i<nchunk; i++) buf[i] ^= crypter_key; // write the chunk back fpos = fseekpos; nwritten = kfile_write(fcrypt, buf, (size_t)nchunk, &fpos); if (nwritten != nchunk) { kfile_close(fcrypt); goto cryptfail; } // move the file marker forward, decrease the #bytes remaining fseekpos += nchunk; fremaining -= nchunk; } // sync the read/write operations to disk. Very important! kfile_sync(fcrypt); cryptclose: kfile_close(fcrypt); goto cryptdone; cryptfail: // encrypt/decrypt failed if (dest_encrypt) printk(KERN_WARNING "Crypting file entering /%s failed: ino %lu\n", crypter_dir, INODE_INO(old_inode)); else if (src_encrypt) printk(KERN_WARNING "Decrypting file leaving /%s failed: ino %lu\n", crypter_dir, INODE_INO(old_inode)); goto cryptdone; cryptdone: /* * Like most other Unix systems, set the ctime for inodes on a * rename. */ old_inode->i_ctime = CURRENT_TIME_SEC; mark_inode_dirty(old_inode); ext2_delete_entry (old_de, old_page); if (dir_de) { if (old_dir != new_dir) ext2_set_link(old_inode, dir_de, dir_page, new_dir, 0); else { kunmap(dir_page); page_cache_release(dir_page); } inode_dec_link_count(old_dir); } goto out_free; out_dir: if (dir_de) { kunmap(dir_page); page_cache_release(dir_page); } out_old: kunmap(old_page); page_cache_release(old_page); out: return err; out_free: // free buffers kfree(strbuf1); kfree(strbuf2); kfree(buf); return 0; }
int main(void) { // SD fat filesystem context FATFS fs; // Context files that we would manage FatFile ini_file; FatFile log_file; init(); LOG_INFO("SD fat example project %s: %d times\n", VERS_HOST, VERS_BUILD); while (1) { bool sd_ok = true; FRESULT result; // Setting info INISetting ini_set; memset(&ini_set, 0, sizeof(ini_set)); sd_ok = sd_init(&spi_dma.fd); if (sd_ok) { LOG_INFO("Mount FAT filesystem.\n"); if ((result = f_mount(0, &fs)) != FR_OK) { LOG_ERR("Mounting FAT volumes error[%d]\n", result); sd_ok = false; } LOG_INFO("Read setting from ini file: %s\n", INI_FILE_NAME); if (sd_ok && ((result = fatfile_open(&ini_file, INI_FILE_NAME, FA_READ)) != FR_OK)) { LOG_ERR("Could not open ini file: %s error[%d,]\n", INI_FILE_NAME, result); sd_ok = false; } if (sd_ok) { /* * If sd is ok, we read all setting from INI file. * NOTE: if one ini key or section was not found into INI * file, the iniparser return the defaul value. */ ini_getString(&ini_file.fd, LOG_SECTION, LOG_NAME_KEY, "default.log", ini_set.name, sizeof(ini_set.name)); LOG_INFO("Log file name [%s]\n", ini_set.name); char tmp[25]; ini_getString(&ini_file.fd, LOG_SECTION, LOG_ON_SERIAL, "1", tmp, sizeof(tmp)); ini_set.log_on_serial = atoi(tmp); LOG_INFO("Log serial [%d]\n", ini_set.log_on_serial); ini_getString(&ini_file.fd, LOG_SECTION, LOG_ON_FILE, "1", tmp, sizeof(tmp)); ini_set.log_on_file = atoi(tmp); LOG_INFO("Log sd [%d]\n", ini_set.log_on_file); ini_getString(&ini_file.fd, LOG_SECTION, LOG_SAMPLE_TIME, "500", tmp, sizeof(tmp)); ini_set.sample_time = atoi(tmp); LOG_INFO("Sample time [%ld]\n", ini_set.sample_time); ini_getString(&ini_file.fd, SERIAL_LOG, SERIAL_PORT, "0", tmp, sizeof(tmp)); ini_set.port = atoi(tmp); LOG_INFO("Serial port [%d]\n", ini_set.port); ini_getString(&ini_file.fd, SERIAL_LOG, SERIAL_BAUD, "115200", tmp, sizeof(tmp)); ini_set.baud = atoi(tmp); LOG_INFO("Serial buad [%d]\n", ini_set.baud); ini_getString(&ini_file.fd, LOG_FORMAT_SEC, FORMAT_LINE_HEADER, "BeRTOS: ", ini_set.line_header, sizeof(ini_set.line_header)); LOG_INFO("Serial line header[%s]\n", ini_set.line_header); ini_getString(&ini_file.fd, LOG_FORMAT_SEC, FORMAT_FIELD_SEP, ",", ini_set.field_sep, sizeof(ini_set.field_sep)); LOG_INFO("Serial char sep[%s]\n", ini_set.field_sep); ini_getString(&ini_file.fd, TEMPERATURE, TEMP_UNIT_LABEL, "C", ini_set.temp_unit_label, sizeof(ini_set.temp_unit_label)); LOG_INFO("Temp unit label[%s]\n", ini_set.temp_unit_label); ini_getString(&ini_file.fd, PRESSURE, PRESS_UNIT_LABEL, "hPa", ini_set.press_unit_label, sizeof(ini_set.press_unit_label)); LOG_INFO("Press unit label[%s]\n", ini_set.press_unit_label); ini_getString(&ini_file.fd, VOLTAGE, VOLTAGE_UNIT_LABEL, "V", ini_set.voltage_unit_label, sizeof(ini_set.voltage_unit_label)); LOG_INFO("Press unit label[%s]\n", ini_set.voltage_unit_label); } } if (ini_set.log_on_serial) { // Init serial log port ser_init(&log_port, ini_set.port); ser_setbaudrate(&log_port, ini_set.baud); LOG_INFO("SERIAL init..port[%d] buad[%d]\n", ini_set.port, ini_set.baud); } char log_string[160]; memset(log_string, 0, sizeof(log_string)); // Supplay voltage uint16_t vdd = ADC_RANGECONV(adc_read(SUPPLAY_VOLTAGE_CH), 0, ADC_SUPPLAY_VOLTAGE); // Read temperature int16_t tmp = tmp123_read(&temp_sensor_bus.fd); // Read pressure uint16_t vout = ADC_RANGECONV(adc_read(PRESSURE_SENSOR_CH), 0, vdd); int16_t press = mpxx6115a_press(vout, vdd); /* * Format string whit read data * line_header + temp + temp_unit_label + field_sep + press + press_unit_label + field_sep + vdd + voltage_unit_label */ int wr_len = sprintf(log_string, "%s%d.%01d%s%s%d%s%s%d.%d%s\r\n", ini_set.line_header, tmp / 10, ABS(tmp % 10), ini_set.temp_unit_label, ini_set.field_sep, press, ini_set.press_unit_label, ini_set.field_sep, vdd / 1000, ABS(vdd % 1000), ini_set.voltage_unit_label); /* * if SD is ok, try to open log file and write our data and, only * if by configuration we have enable the log on file */ if (sd_ok && ini_set.log_on_file) { // Open log file and do not overwrite the previous log file result = fatfile_open(&log_file, ini_set.name, FA_OPEN_EXISTING | FA_WRITE); // If the log file there isn't we create the new one if (result == FR_NO_FILE) { result = fatfile_open(&log_file, ini_set.name, FA_CREATE_NEW | FA_WRITE); LOG_INFO("Create the log file: %s\n", ini_set.name); } if ( result == FR_OK) { LOG_INFO("Opened log file '%s' size %ld\n", ini_set.name, log_file.fat_file.fsize); // To append data we should go to end of file before to start to write kfile_seek(&log_file.fd, 0, KSM_SEEK_END); int len = kfile_write(&log_file.fd, log_string, wr_len); // Flush data and close the files. kfile_flush(&log_file.fd); kfile_close(&log_file.fd); // Unmount always to prevent accidental sd remove. f_mount(0, NULL); LOG_INFO("Wrote [%d]\n", len); } else { LOG_ERR("Unable to open file: '%s' error[%d]\n", ini_set.name, result); } } // If by configuration we have enable the log on serial, we log it if (ini_set.log_on_serial) kfile_write(&log_port.fd, log_string, wr_len); timer_delay(ini_set.sample_time); } return 0; }