SMREmulator 1.0
ShingledMagneticRecordingEmulator
|
00001 00014 #include <fcntl.h> 00015 #include <errno.h> 00016 #include <unistd.h> 00017 #include <string.h> 00018 #include <stdarg.h> 00019 00020 #include <emulator.h> 00021 #include <emudebug.h> 00022 #include <emudiskimg.h> 00023 #include <ediversion.h> 00024 #include <emulog.h> 00025 00026 00027 00028 /* -- Macro Definitions -- */ 00029 00030 #define EDIOPS(fd) edi_versions[edis[fd].version] 00031 #define LOG edi_log 00032 #define EDI_LOG 00033 00037 #define EDI_MAGIC_NUMBER 0xE5D10000U // Hex for Emulated 5hingled Disk 1mage 00038 00039 00040 00041 /* -- Type Definitions -- */ 00042 00049 typedef struct { 00050 int fd; 00051 uint32_t version; 00052 } edi_fd_t; 00053 00054 00055 00056 /* -- Static Variables -- */ 00057 static edi_fd_t edis[MAX_EDIS]; 00058 static int edi_count; 00059 static edi_lops_t *edi_log; 00060 00061 00062 00063 /* -- Function Implementations -- */ 00064 00082 int edi_create(const char* filename, uint32_t version, ...) { 00083 int fd, retval = -1; 00084 int oflags = O_RDWR | O_CREAT | O_EXCL; 00085 mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; 00086 edi_ident_t edi_ident; 00087 va_list args; 00088 00089 00090 /* Validate the version */ 00091 if (!ediv_is_valid(version)) { 00092 errno = EVERSION; 00093 return -1; 00094 } 00095 dbg("Version %d is valid.\n", version); 00096 00097 00098 /* Check if the version specific create() function exists */ 00099 if (edi_versions[version]->create == NULL) { 00100 errno = EUNSUPPORTED; 00101 return -1; 00102 } 00103 dbg("Version %d is supported.\n", version); 00104 00105 00106 /* Process the variable arguments list */ 00107 va_start(args, version); 00108 dbg("Variable arguments processed!\n"); 00109 00110 00111 /* Create the EDI file */ 00112 if ((fd = open(filename, oflags, mode)) < 0) 00113 goto cleanup_vargs; 00114 dbg("File %s created. Open at descriptor %d...\n", filename, fd); 00115 00116 00117 /* Write the EDI identifier record */ 00118 edi_ident.magic_no = EDI_MAGIC_NUMBER; 00119 edi_ident.version = version; 00120 if (pwrite(fd, &edi_ident, sizeof(edi_ident_t), 0) != sizeof(edi_ident_t)) 00121 goto cleanup_file; 00122 dbg("EDI Identifier written to file!"); 00123 00124 00125 /* Call the version specific create() function to handle further tasks */ 00126 if (edi_versions[version]->create(fd, args) < 0) 00127 goto cleanup_file; 00128 dbg("Header and Metadata written out to file!\n"); 00129 00130 /* Return the file descriptor to the caller */ 00131 retval = fd; 00132 goto cleanup_vargs; 00133 00134 00135 cleanup_file: 00136 /* Close and delete the open file */ 00137 close(fd); 00138 unlink(filename); 00139 00140 cleanup_vargs: 00141 /* Cleanup the variable arguments */ 00142 va_end(args); 00143 00144 return retval; 00145 } 00146 00147 00148 00164 int edi_dump(int fd) { 00165 /* Verify the file descriptor index */ 00166 if (fd >= edi_count) { 00167 errno = EBADFD; 00168 return -1; 00169 } 00170 00171 /* Select the appropriate call-back function */ 00172 if (EDIOPS(fd)->dump == NULL) { 00173 dbg("version[%d]->dump() not supported!\n", edis[fd].version); 00174 errno = EUNSUPPORTED; 00175 return -1; 00176 } 00177 00178 /* Call the registered call-back function */ 00179 dbg("Calling version[%d]->dump()!\n", edis[fd].version); 00180 return EDIOPS(fd)->dump(edis[fd].fd); 00181 } 00182 00183 00184 00205 int edi_open(const char* filename) { 00206 /* Declare the variables needed */ 00207 int edi_fd; 00208 edi_ident_t edi_ident; 00209 int ident_size = sizeof(edi_ident_t); 00210 00211 00212 /* Attempt to open the file for reading and writing */ 00213 if ((edi_fd = open(filename, O_RDWR)) < 0) 00214 return -1; 00215 dbg("Opened EDI file %s\n", filename); 00216 00217 00218 /* Read the header to check if the file is a valid Emulated Disk Image */ 00219 if (pread(edi_fd, &edi_ident, ident_size, 0) < ident_size) { 00220 /* Report the error */ 00221 dbg("Cannot read identifier data!\n"); 00222 errno = EINVALIDFILE; 00223 return -1; 00224 } 00225 00226 /* Verify the Magic Number */ 00227 if (edi_ident.magic_no != EDI_MAGIC_NUMBER) { 00228 /* Report the error */ 00229 dbg("Magic Number does not match!\n"); 00230 errno = EINVALIDFILE; 00231 return -1; 00232 } 00233 dbg("Magic number is good.\n"); 00234 00235 00236 /* Verify that the version is valid and supported */ 00237 if (!ediv_is_valid(edi_ident.version)) { 00238 LOG->error("Version is not valid!\n"); 00239 errno = EVERSION; 00240 return -1; 00241 } 00242 00243 if (edi_versions[edi_ident.version] == NULL) { 00244 LOG->error("Version %d is not supported by the library!\n", edi_ident.version); 00245 errno = EUNSUPPORTED; 00246 return -1; 00247 } 00248 dbg("Version is valid and supported!\n"); 00249 00250 00251 /* Add the new file descriptor to the list of open EDI files */ 00252 edis[edi_count].fd = edi_fd; 00253 edis[edi_count].version = edi_ident.version; 00254 00255 00256 /* Call the registered callback function, if any */ 00257 if (EDIOPS(edi_count)->open != NULL) { 00258 dbg("Calling version[%d]->open()\n", edi_ident.version); 00259 if ((EDIOPS(edi_count)->open(edis[edi_count].fd)) < 0) 00260 return -1; 00261 } 00262 00263 00264 /* Return the index of the newly opened EDI in the open_edis array */ 00265 dbg("EDI File %s opened with descriptor %d!\n", filename, edi_count); 00266 edi_count++; 00267 return (edi_count - 1); 00268 } 00269 00270 00271 00285 int edi_close(int fd) { 00286 /* Verify the file descriptor index */ 00287 if (fd >= edi_count) { 00288 dbg("%d is an invalid index into the FD lookup table!\n", fd); 00289 errno = EBADFD; 00290 return -1; 00291 } 00292 00293 00294 /* Call the registered callback function, if any */ 00295 if (EDIOPS(fd)->close != NULL) { 00296 dbg("Calling version[%d]->close()!\n", edis[fd].version); 00297 EDIOPS(fd)->close(edis[fd].fd); 00298 } 00299 00300 00301 /* Attempt to close the file */ 00302 if (close(edis[fd].fd) < 0) { 00303 dbg("Cannot close EDI file!\n"); 00304 return -1; 00305 } 00306 dbg("EDI file closed successfully!\n"); 00307 00308 return 0; 00309 } 00310 00311 00312 00334 int edi_modesense(int fd, inq_t inq, void *data) { 00335 #ifdef EDI_LOG 00336 /* Log the function call */ 00337 switch(inq) { 00338 case INQ_BLKSIZE: 00339 LOG->info("edi_modesense(fd=%d, inq=BLK_SIZE, data=%p)\n", fd, data); 00340 break; 00341 00342 case INQ_BNDCOUNT: 00343 LOG->info("edi_modesense(fd=%d, inq=BAND_COUNT, data=%p)\n", fd, data); 00344 break; 00345 00346 } 00347 #endif 00348 00349 00350 /* Verify the file descriptor index */ 00351 if (fd >= edi_count) { 00352 errno = EBADFD; 00353 return -1; 00354 } 00355 00356 /* Select the appropriate call-back function */ 00357 if (EDIOPS(fd)->modesense == NULL) { 00358 dbg("version[%d]->modesense() not supported!\n", edis[fd].version); 00359 errno = EUNSUPPORTED; 00360 return -1; 00361 } 00362 00363 /* Call the registered call-back function */ 00364 dbg("Calling version[%d]->modesense()!\n", edis[fd].version); 00365 return EDIOPS(fd)->modesense(edis[fd].fd, inq, data); 00366 } 00367 00368 00369 00417 int edi_managebands(int fd, svc_act_t action, band_t* band, rba_t* rba, 00418 int len) { 00419 #ifdef EDI_LOG 00420 /* Log the function call */ 00421 switch(action) { 00422 case SVC_GETPTR: 00423 LOG->info("edi_managebands(fd=%d, inq=SVC_GETPTR, band=%d, rba=%p)\n", 00424 fd, *band, rba, len); 00425 break; 00426 00427 case SVC_SETPTR: 00428 LOG->info("edi_managebands(fd=%d, inq=SVC_SETPTR, band=%d, rba=%d)\n", 00429 fd, *band, *rba, len); 00430 break; 00431 00432 case SVC_GETMULTIPLE: 00433 LOG->info("edi_managebands(fd=%d, inq=SVC_GETMULTIPLE, band=%p, rba=%p," 00434 " len=%d)\n", fd, band, rba, len); 00435 break; 00436 00437 case SVC_RESETALL: 00438 LOG->info("edi_managebands(fd=%d, inq=SVC_RESETALL, band=%p, rba=%p, " 00439 "len=%d)\n", fd, band, rba, len); 00440 break; 00441 00442 case SVC_GETBANDCONFIG: 00443 LOG->info("edi_managebands(fd=%d, inq=SVC_GETBANDCONFIG, band=%d, " 00444 "rba=%d, len=%d)\n", fd, *band, *rba, len); 00445 break; 00446 00447 case SVC_SETBANDCONFIG: 00448 LOG->info("edi_managebands(fd=%d, inq=SVC_SETBANDCONFIG, band=%d, " 00449 "rba=%d, len=%d)\n", fd, *band, *rba, len); 00450 break; 00451 } 00452 #endif 00453 00454 00455 /* Verify the file descriptor index */ 00456 if (fd >= edi_count) { 00457 errno = EBADFD; 00458 return -1; 00459 } 00460 00461 /* Select the appropriate call-back function */ 00462 if (EDIOPS(fd)->managebands == NULL) { 00463 dbg("version[%d]->modesense() not supported!\n", edis[fd].version); 00464 errno = EUNSUPPORTED; 00465 return -1; 00466 } 00467 00468 /* Call the registered call-back function */ 00469 dbg("Calling version[%d]->managebands()!\n", edis[fd].version); 00470 return EDIOPS(fd)->managebands(edis[fd].fd, action, band, rba, len); 00471 } 00472 00473 00474 00493 int edi_read(int fd, band_t band, rba_t rba, char *buf, rba_t len) { 00494 #ifdef EDI_LOG 00495 /* Log the function call */ 00496 LOG->info("edi_read(fd=%d, band=%d, rba=%d, buf=%p, len=%d)\n", 00497 fd, band, rba, buf, len); 00498 #endif 00499 00500 00501 /* Verify the file descriptor index */ 00502 if (fd >= edi_count) { 00503 errno = EBADFD; 00504 return -1; 00505 } 00506 00507 /* Select the appropriate call-back function */ 00508 if (EDIOPS(fd)->read == NULL) { 00509 dbg("version[%d]->read() not supported!\n", edis[fd].version); 00510 errno = EUNSUPPORTED; 00511 return -1; 00512 } 00513 00514 /* Call the registered call-back function */ 00515 dbg("Calling version[%d]->read()!\n", edis[fd].version); 00516 return EDIOPS(fd)->read(edis[fd].fd, band, rba, buf, len); 00517 } 00518 00519 00520 00536 int edi_write(int fd, band_t band, rba_t rba, char *buf, rba_t len) { 00537 #ifdef EDI_LOG 00538 /* Log the function call */ 00539 LOG->info("edi_write(fd=%d, band=%d, rba=%d, buf=%p, len=%d)\n", 00540 fd, band, rba, buf, len); 00541 #endif 00542 00543 00544 /* Verify the file descriptor index */ 00545 if (fd >= edi_count) { 00546 errno = EBADFD; 00547 return -1; 00548 } 00549 00550 /* Select the appropriate call-back function */ 00551 if (EDIOPS(fd)->write == NULL) { 00552 dbg("version[%d]->write() not supported!\n", edis[fd].version); 00553 errno = EUNSUPPORTED; 00554 return -1; 00555 } 00556 00557 /* Call the registered callback function */ 00558 dbg("Calling version[%d]->write()!\n", edis[fd].version); 00559 return EDIOPS(fd)->write(edis[fd].fd, band, rba, buf, len); 00560 } 00561 00562 00563 00569 int edi_init() { 00570 #ifdef EDI_LOG 00571 char filename[25]; 00572 int len; 00573 time_t curtime = time(NULL); 00574 00575 /* Initialize the logging module */ 00576 len = strftime(filename, 25, "edi%Y%m%d%H%M%S.log", localtime(&curtime)); 00577 if (!len) { 00578 fprintf(stderr, "Error generating log file name: %s\n", filename); 00579 return -1; 00580 } 00581 dbg("Log filename generated as %s\n", filename); 00582 00583 LOG = emulog_open(filename); 00584 if (LOG == NULL) { 00585 fprintf(stderr, "Cannot open log file %s\n", filename); 00586 return -1; 00587 } 00588 #endif 00589 00590 00591 /* Initialize the data structures */ 00592 memset(&edis, 0, sizeof(edi_fd_t) * MAX_EDIS); 00593 edi_count = 0; 00594 00595 00596 /* Call the initialization operations for the Versioning Interface */ 00597 return ediv_init(); 00598 }