LCOV - code coverage report
Current view: top level - cmdline - handle.c (source / functions) Hit Total Coverage
Test: lcov.info Lines: 126 129 97.7 %
Date: 2017-11-06 22:14:04 Functions: 8 8 100.0 %

          Line data    Source code
       1             : /*
       2             :  * Copyright (C) 2011 Andrea Mazzoleni
       3             :  *
       4             :  * This program is free software: you can redistribute it and/or modify
       5             :  * it under the terms of the GNU General Public License as published by
       6             :  * the Free Software Foundation, either version 3 of the License, or
       7             :  * (at your option) any later version.
       8             :  *
       9             :  * This program is distributed in the hope that it will be useful,
      10             :  * but WITHOUT ANY WARRANTY; without even the implied warranty of
      11             :  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
      12             :  * GNU General Public License for more details.
      13             :  *
      14             :  * You should have received a copy of the GNU General Public License
      15             :  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
      16             :  */
      17             : 
      18             : #include "portable.h"
      19             : 
      20             : #include "elem.h"
      21             : #include "support.h"
      22             : #include "handle.h"
      23             : 
      24             : /****************************************************************************/
      25             : /* handle */
      26             : 
      27      771262 : int handle_create(struct snapraid_handle* handle, struct snapraid_file* file, int mode)
      28             : {
      29             :         int ret;
      30             :         int flags;
      31             : 
      32             :         /* if it's the same file, and already opened, nothing to do */
      33      771262 :         if (handle->file == file && handle->f != -1) {
      34           0 :                 return 0;
      35             :         }
      36             : 
      37      771262 :         advise_init(&handle->advise, mode);
      38      771262 :         pathprint(handle->path, sizeof(handle->path), "%s%s", handle->disk->dir, file->sub);
      39             : 
      40      771262 :         ret = mkancestor(handle->path);
      41      771262 :         if (ret != 0) {
      42             :                 /* LCOV_EXCL_START */
      43             :                 return -1;
      44             :                 /* LCOV_EXCL_STOP */
      45             :         }
      46             : 
      47             :         /* initial values, changed later if required */
      48      771262 :         handle->created = 0;
      49             : 
      50             :         /* flags for opening */
      51             :         /* O_BINARY: open as binary file (Windows only) */
      52             :         /* O_NOFOLLOW: do not follow links to ensure to open the real file */
      53      771262 :         flags = O_BINARY | O_NOFOLLOW | advise_flags(&handle->advise);
      54             : 
      55             :         /* open for read write */
      56      771262 :         handle->f = open(handle->path, flags | O_RDWR);
      57             : 
      58             :         /* if failed for missing write permission */
      59      771262 :         if (handle->f == -1 && (errno == EACCES || errno == EROFS)) {
      60             :                 /* open for real-only */
      61           0 :                 handle->f = open(handle->path, flags | O_RDONLY);
      62             :         }
      63             : 
      64             :         /* if failed for missing file */
      65      771262 :         if (handle->f == -1 && errno == ENOENT) {
      66             :                 char path_from[PATH_MAX];
      67             : 
      68             :                 /* check if exists a .unrecoverable copy, and rename to the real one */
      69      176483 :                 pathprint(path_from, sizeof(path_from), "%s.unrecoverable", handle->path);
      70             : 
      71      176483 :                 if (rename(path_from, handle->path) == 0) {
      72             :                         /* open for read write */
      73       63315 :                         handle->f = open(handle->path, flags | O_RDWR);
      74             :                 } else {
      75             :                         /* create it */
      76      113168 :                         handle->f = open(handle->path, flags | O_RDWR | O_CREAT, 0600);
      77      113168 :                         if (handle->f != -1) {
      78             :                                 /* mark it as created if really done */
      79      113168 :                                 handle->created = 1;
      80             :                         }
      81             :                 }
      82             :         }
      83             : 
      84      771262 :         if (handle->f == -1) {
      85             :                 /* LCOV_EXCL_START */
      86             :                 /* invalidate for error */
      87             :                 handle->file = 0;
      88             :                 handle->f = -1;
      89             :                 handle->valid_size = 0;
      90             : 
      91             :                 log_fatal("Error opening file '%s'. %s.\n", handle->path, strerror(errno));
      92             :                 return -1;
      93             :                 /* LCOV_EXCL_STOP */
      94             :         }
      95             : 
      96             :         /* just opened */
      97      771262 :         handle->file = file;
      98             : 
      99             :         /* get the stat info */
     100      771262 :         ret = fstat(handle->f, &handle->st);
     101      771262 :         if (ret != 0) {
     102             :                 /* LCOV_EXCL_START */
     103             :                 log_fatal("Error accessing file '%s'. %s.\n", handle->path, strerror(errno));
     104             :                 return -1;
     105             :                 /* LCOV_EXCL_STOP */
     106             :         }
     107             : 
     108             :         /* get the size of the existing data */
     109      771262 :         handle->valid_size = handle->st.st_size;
     110             : 
     111      771262 :         ret = advise_open(&handle->advise, handle->f);
     112      771262 :         if (ret != 0) {
     113             :                 /* LCOV_EXCL_START */
     114             :                 log_fatal("Error advising file '%s'. %s.\n", handle->path, strerror(errno));
     115             :                 return -1;
     116             :                 /* LCOV_EXCL_STOP */
     117             :         }
     118             : 
     119      771262 :         return 0;
     120             : }
     121             : 
     122        3186 : int handle_truncate(struct snapraid_handle* handle, struct snapraid_file* file)
     123             : {
     124             :         int ret;
     125             : 
     126        3186 :         ret = ftruncate(handle->f, file->size);
     127        3186 :         if (ret != 0) {
     128             :                 /* LCOV_EXCL_START */
     129             :                 if (errno == EACCES) {
     130             :                         log_fatal("Failed to truncate file '%s' for missing write permission.\n", handle->path);
     131             :                 } else {
     132             :                         log_fatal("Error truncating file '%s'. %s.\n", handle->path, strerror(errno));
     133             :                 }
     134             :                 return -1;
     135             :                 /* LCOV_EXCL_STOP */
     136             :         }
     137             : 
     138             :         /* adjust the size to the truncated size */
     139        3186 :         handle->valid_size = file->size;
     140             : 
     141        3186 :         return 0;
     142             : }
     143             : 
     144     2181235 : int handle_open(struct snapraid_handle* handle, struct snapraid_file* file, int mode, fptr* out, fptr* out_missing)
     145             : {
     146             :         int ret;
     147             :         int flags;
     148             : 
     149     2181235 :         if (!out_missing)
     150     2182560 :                 out_missing = out;
     151             : 
     152             :         /* if already opened, nothing to do */
     153     2181235 :         if (handle->file == file && handle->file != 0 && handle->f != -1) {
     154      468203 :                 return 0;
     155             :         }
     156             : 
     157     1713032 :         advise_init(&handle->advise, mode);
     158     1715621 :         pathprint(handle->path, sizeof(handle->path), "%s%s", handle->disk->dir, file->sub);
     159             : 
     160             :         /* for sure not created */
     161     1716756 :         handle->created = 0;
     162             : 
     163             :         /* flags for opening */
     164             :         /* O_BINARY: open as binary file (Windows only) */
     165             :         /* O_NOFOLLOW: do not follow links to ensure to open the real file */
     166     1716756 :         flags = O_BINARY | O_NOFOLLOW | advise_flags(&handle->advise);
     167             : 
     168             :         /* open for read */
     169     1717051 :         handle->f = open_noatime(handle->path, flags | O_RDONLY);
     170     1712928 :         if (handle->f == -1) {
     171             :                 /* invalidate for error */
     172       78934 :                 handle->file = 0;
     173       78934 :                 handle->f = -1;
     174       78934 :                 handle->valid_size = 0;
     175             : 
     176       78934 :                 if (errno == ENOENT)
     177       78922 :                         out_missing("Missing file '%s'.\n", handle->path);
     178             :                 else
     179          12 :                         out("Error opening file '%s'. %s.\n", handle->path, strerror(errno));
     180       78934 :                 return -1;
     181             :         }
     182             : 
     183             :         /* just opened */
     184     1633994 :         handle->file = file;
     185             : 
     186             :         /* get the stat info */
     187     1633994 :         ret = fstat(handle->f, &handle->st);
     188     1630006 :         if (ret != 0) {
     189             :                 /* LCOV_EXCL_START */
     190             :                 out("Error accessing file '%s'. %s.\n", handle->path, strerror(errno));
     191             :                 return -1;
     192             :                 /* LCOV_EXCL_STOP */
     193             :         }
     194             : 
     195             :         /* get the size of the existing data */
     196     1630006 :         handle->valid_size = handle->st.st_size;
     197             : 
     198     1630006 :         ret = advise_open(&handle->advise, handle->f);
     199     1629129 :         if (ret != 0) {
     200             :                 /* LCOV_EXCL_START */
     201             :                 out("Error advising file '%s'. %s.\n", handle->path, strerror(errno));
     202             :                 return -1;
     203             :                 /* LCOV_EXCL_STOP */
     204             :         }
     205             : 
     206     1629129 :         return 0;
     207             : }
     208             : 
     209     4644944 : int handle_close(struct snapraid_handle* handle)
     210             : {
     211             :         int ret;
     212             : 
     213             :         /* close if open */
     214     4644944 :         if (handle->f != -1) {
     215     2409673 :                 ret = close(handle->f);
     216     2409346 :                 if (ret != 0) {
     217             :                         /* LCOV_EXCL_START */
     218             :                         log_fatal("Error closing file '%s'. %s.\n", handle->file->sub, strerror(errno));
     219             : 
     220             :                         /* invalidate for error */
     221             :                         handle->file = 0;
     222             :                         handle->f = -1;
     223             :                         handle->valid_size = 0;
     224             :                         return -1;
     225             :                         /* LCOV_EXCL_STOP */
     226             :                 }
     227             :         }
     228             : 
     229             :         /* reset the descriptor */
     230     4644617 :         handle->file = 0;
     231     4644617 :         handle->f = -1;
     232     4644617 :         handle->valid_size = 0;
     233             : 
     234     4644617 :         return 0;
     235             : }
     236             : 
     237     5850799 : int handle_read(struct snapraid_handle* handle, block_off_t file_pos, unsigned char* block_buffer, unsigned block_size, fptr* out, fptr* out_missing)
     238             : {
     239             :         ssize_t read_ret;
     240             :         data_off_t offset;
     241             :         unsigned read_size;
     242             :         unsigned count;
     243             :         int ret;
     244             : 
     245     5850799 :         offset = file_pos * (data_off_t)block_size;
     246             : 
     247     5850799 :         if (!out_missing)
     248     5834263 :                 out_missing = out;
     249             : 
     250             :         /* check if we are going to read only not initialized data */
     251     5850799 :         if (offset >= handle->valid_size) {
     252             :                 /* if the file is missing, it's at 0 size, or it's rebuilt while reading */
     253      433534 :                 if (offset == handle->valid_size || handle->valid_size == 0)
     254      432265 :                         out_missing("Reading data from missing file '%s' at offset %" PRIu64 ".\n", handle->path, offset);
     255             :                 else
     256        1269 :                         out("Reading missing data from file '%s' at offset %" PRIu64 ".\n", handle->path, offset);
     257      433534 :                 return -1;
     258             :         }
     259             : 
     260     5417265 :         read_size = file_block_size(handle->file, file_pos, block_size);
     261             : 
     262     5413909 :         count = 0;
     263             :         do {
     264             :                 /* read the full block to support O_DIRECT */
     265     5423657 :                 read_ret = pread(handle->f, block_buffer + count, block_size - count, offset + count);
     266     5427744 :                 if (read_ret < 0) {
     267             :                         /* LCOV_EXCL_START */
     268             :                         out("Error reading file '%s' at offset %" PRIu64 " for size %u. %s.\n", handle->path, offset + count, block_size - count, strerror(errno));
     269             :                         return -1;
     270             :                         /* LCOV_EXCL_STOP */
     271             :                 }
     272     5427744 :                 if (read_ret == 0) {
     273        8602 :                         out("Unexpected end of file '%s' at offset %" PRIu64 ". %s.\n", handle->path, offset, strerror(errno));
     274        8602 :                         return -1;
     275             :                 }
     276             : 
     277     5419142 :                 count += read_ret;
     278     5419142 :         } while (count < read_size);
     279             : 
     280             :         /* pad with 0 */
     281     5409394 :         if (read_size < block_size) {
     282     2187944 :                 memset(block_buffer + read_size, 0, block_size - read_size);
     283             :         }
     284             : 
     285     5409394 :         ret = advise_read(&handle->advise, handle->f, offset, block_size);
     286     5408496 :         if (ret != 0) {
     287             :                 /* LCOV_EXCL_START */
     288             :                 out("Error advising file '%s'. %s.\n", handle->path, strerror(errno));
     289             :                 return -1;
     290             :                 /* LCOV_EXCL_STOP */
     291             :         }
     292             : 
     293     5408496 :         return read_size;
     294             : }
     295             : 
     296      288647 : int handle_write(struct snapraid_handle* handle, block_off_t file_pos, unsigned char* block_buffer, unsigned block_size)
     297             : {
     298             :         ssize_t write_ret;
     299             :         data_off_t offset;
     300             :         unsigned write_size;
     301             :         int ret;
     302             : 
     303      288647 :         offset = file_pos * (data_off_t)block_size;
     304             : 
     305      288647 :         write_size = file_block_size(handle->file, file_pos, block_size);
     306             : 
     307      288647 :         write_ret = pwrite(handle->f, block_buffer, write_size, offset);
     308      288647 :         if (write_ret != (ssize_t)write_size) { /* conversion is safe because block_size is always small */
     309             :                 /* LCOV_EXCL_START */
     310             :                 log_fatal("Error writing file '%s'. %s.\n", handle->path, strerror(errno));
     311             :                 return -1;
     312             :                 /* LCOV_EXCL_STOP */
     313             :         }
     314             : 
     315             :         /* adjust the size of the valid data */
     316      288647 :         if (handle->valid_size < offset + write_size) {
     317      282551 :                 handle->valid_size = offset + write_size;
     318             :         }
     319             : 
     320      288647 :         ret = advise_write(&handle->advise, handle->f, offset, block_size);
     321      288647 :         if (ret != 0) {
     322             :                 /* LCOV_EXCL_START */
     323             :                 log_fatal("Error advising file '%s'. %s.\n", handle->path, strerror(errno));
     324             :                 return -1;
     325             :                 /* LCOV_EXCL_STOP */
     326             :         }
     327             : 
     328      288647 :         return 0;
     329             : }
     330             : 
     331      119462 : int handle_utime(struct snapraid_handle* handle)
     332             : {
     333             :         int ret;
     334             : 
     335             :         /* do nothing if not opened */
     336      119462 :         if (handle->f == -1)
     337           0 :                 return 0;
     338             : 
     339      119462 :         ret = fmtime(handle->f, handle->file->mtime_sec, handle->file->mtime_nsec);
     340             : 
     341      119462 :         if (ret != 0) {
     342             :                 /* LCOV_EXCL_START */
     343             :                 log_fatal("Error timing file '%s'. %s.\n", handle->file->sub, strerror(errno));
     344             :                 return -1;
     345             :                 /* LCOV_EXCL_STOP */
     346             :         }
     347             : 
     348      119462 :         return 0;
     349             : }
     350             : 
     351         221 : struct snapraid_handle* handle_mapping(struct snapraid_state* state, unsigned* handlemax)
     352             : {
     353             :         tommy_node* i;
     354             :         unsigned j;
     355         221 :         unsigned size = 0;
     356             :         struct snapraid_handle* handle;
     357             : 
     358             :         /* get the size of the mapping */
     359         221 :         size = 0;
     360        1542 :         for (i = state->maplist; i != 0; i = i->next) {
     361        1321 :                 struct snapraid_map* map = i->data;
     362        1321 :                 if (map->position > size)
     363         941 :                         size = map->position;
     364             :         }
     365         221 :         ++size; /* size is one more than the max */
     366             : 
     367         221 :         handle = malloc_nofail(size * sizeof(struct snapraid_handle));
     368             : 
     369        1547 :         for (j = 0; j < size; ++j) {
     370             :                 /* default for empty position */
     371        1326 :                 handle[j].disk = 0;
     372        1326 :                 handle[j].file = 0;
     373        1326 :                 handle[j].f = -1;
     374        1326 :                 handle[j].valid_size = 0;
     375             :         }
     376             : 
     377             :         /* set the vector */
     378        1542 :         for (i = state->disklist; i != 0; i = i->next) {
     379             :                 struct snapraid_map* map;
     380        1321 :                 struct snapraid_disk* disk = i->data;
     381             :                 tommy_node* k;
     382             : 
     383             :                 /* search the mapping for this disk */
     384        1321 :                 map = 0;
     385        4611 :                 for (k = state->maplist; k != 0; k = k->next) {
     386        4611 :                         map = k->data;
     387        4611 :                         if (strcmp(disk->name, map->name) == 0)
     388        1321 :                                 break;
     389             :                 }
     390        1321 :                 if (!map) {
     391             :                         /* LCOV_EXCL_START */
     392             :                         log_fatal("Internal error for inconsistent disk mapping.\n");
     393             :                         os_abort();
     394             :                         /* LCOV_EXCL_STOP */
     395             :                 }
     396             : 
     397        1321 :                 handle[map->position].disk = disk;
     398             :         }
     399             : 
     400         221 :         *handlemax = size;
     401         221 :         return handle;
     402             : }
     403             : 

Generated by: LCOV version 1.13