Home | History | Annotate | Line # | Download | only in test
      1 /* Copyright libuv project contributors. All rights reserved.
      2  *
      3  * Permission is hereby granted, free of charge, to any person obtaining a copy
      4  * of this software and associated documentation files (the "Software"), to
      5  * deal in the Software without restriction, including without limitation the
      6  * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
      7  * sell copies of the Software, and to permit persons to whom the Software is
      8  * furnished to do so, subject to the following conditions:
      9  *
     10  * The above copyright notice and this permission notice shall be included in
     11  * all copies or substantial portions of the Software.
     12  *
     13  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
     14  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
     15  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
     16  * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
     17  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
     18  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
     19  * IN THE SOFTWARE.
     20  */
     21 
     22 #include "uv.h"
     23 #include "task.h"
     24 
     25 #if defined(__unix__) || defined(__POSIX__) || \
     26     defined(__APPLE__) || defined(__sun) || \
     27     defined(_AIX) || defined(__MVS__) || \
     28     defined(__HAIKU__) || defined(__QNX__)
     29 #include <unistd.h> /* unlink, etc. */
     30 #else
     31 # include <direct.h>
     32 # include <io.h>
     33 # define unlink _unlink
     34 #endif
     35 
     36 static const char fixture[] = "test/fixtures/load_error.node";
     37 static const char dst[] = "test_file_dst";
     38 static int result_check_count;
     39 
     40 
     41 static void fail_cb(uv_fs_t* req) {
     42   FATAL("fail_cb should not have been called");
     43 }
     44 
     45 static void handle_result(uv_fs_t* req) {
     46   uv_fs_t stat_req;
     47   uint64_t size;
     48   uint64_t mode;
     49   uint64_t uid;
     50   uint64_t gid;
     51   int r;
     52 
     53   ASSERT_EQ(req->fs_type, UV_FS_COPYFILE);
     54   ASSERT_OK(req->result);
     55 
     56   /* Verify that the file size and mode are the same. */
     57   r = uv_fs_stat(NULL, &stat_req, req->path, NULL);
     58   ASSERT_OK(r);
     59   size = stat_req.statbuf.st_size;
     60   mode = stat_req.statbuf.st_mode;
     61   uid = stat_req.statbuf.st_uid;
     62   gid = stat_req.statbuf.st_gid;
     63   uv_fs_req_cleanup(&stat_req);
     64   r = uv_fs_stat(NULL, &stat_req, dst, NULL);
     65   ASSERT_OK(r);
     66   ASSERT_EQ(stat_req.statbuf.st_size, size);
     67   ASSERT_EQ(stat_req.statbuf.st_mode, mode);
     68   ASSERT_EQ(stat_req.statbuf.st_uid, uid);
     69   ASSERT_EQ(stat_req.statbuf.st_gid, gid);
     70   uv_fs_req_cleanup(&stat_req);
     71   uv_fs_req_cleanup(req);
     72   result_check_count++;
     73 }
     74 
     75 
     76 static void touch_file(const char* name, unsigned int size) {
     77   uv_file file;
     78   uv_fs_t req;
     79   uv_buf_t buf;
     80   int r;
     81   unsigned int i;
     82 
     83   r = uv_fs_open(NULL, &req, name,
     84                  UV_FS_O_WRONLY | UV_FS_O_CREAT | UV_FS_O_TRUNC,
     85                  S_IWUSR | S_IRUSR, NULL);
     86   uv_fs_req_cleanup(&req);
     87   ASSERT_GE(r, 0);
     88   file = r;
     89 
     90   buf = uv_buf_init("a", 1);
     91 
     92   /* Inefficient but simple. */
     93   for (i = 0; i < size; i++) {
     94     r = uv_fs_write(NULL, &req, file, &buf, 1, i, NULL);
     95     uv_fs_req_cleanup(&req);
     96     ASSERT_GE(r, 0);
     97   }
     98 
     99   r = uv_fs_close(NULL, &req, file, NULL);
    100   uv_fs_req_cleanup(&req);
    101   ASSERT_OK(r);
    102 }
    103 
    104 
    105 TEST_IMPL(fs_copyfile) {
    106   const char src[] = "test_file_src";
    107   uv_loop_t* loop;
    108   uv_fs_t req;
    109   int r;
    110 
    111   loop = uv_default_loop();
    112 
    113   /* Fails with EINVAL if bad flags are passed. */
    114   r = uv_fs_copyfile(NULL, &req, src, dst, -1, NULL);
    115   ASSERT_EQ(r, UV_EINVAL);
    116   uv_fs_req_cleanup(&req);
    117 
    118   /* Fails with ENOENT if source does not exist. */
    119   unlink(src);
    120   unlink(dst);
    121   r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL);
    122   ASSERT_EQ(req.result, UV_ENOENT);
    123   ASSERT_EQ(r, UV_ENOENT);
    124   uv_fs_req_cleanup(&req);
    125   /* The destination should not exist. */
    126   r = uv_fs_stat(NULL, &req, dst, NULL);
    127   ASSERT(r);
    128   uv_fs_req_cleanup(&req);
    129 
    130   /* Succeeds if src and dst files are identical. */
    131   touch_file(src, 12);
    132   r = uv_fs_copyfile(NULL, &req, src, src, 0, NULL);
    133   ASSERT_OK(r);
    134   uv_fs_req_cleanup(&req);
    135   /* Verify that the src file did not get truncated. */
    136   r = uv_fs_stat(NULL, &req, src, NULL);
    137   ASSERT_OK(r);
    138   ASSERT_EQ(12, req.statbuf.st_size);
    139   uv_fs_req_cleanup(&req);
    140   unlink(src);
    141 
    142   /* Copies file synchronously. Creates new file. */
    143   unlink(dst);
    144   r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL);
    145   ASSERT_OK(r);
    146   handle_result(&req);
    147 
    148   /* Copies a file of size zero. */
    149   unlink(dst);
    150   touch_file(src, 0);
    151   r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL);
    152   ASSERT_OK(r);
    153   handle_result(&req);
    154 
    155   /* Copies file synchronously. Overwrites existing file. */
    156   r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL);
    157   ASSERT_OK(r);
    158   handle_result(&req);
    159 
    160   /* Fails to overwrites existing file. */
    161   ASSERT_OK(uv_fs_chmod(NULL, &req, dst, 0644, NULL));
    162   uv_fs_req_cleanup(&req);
    163   r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_EXCL, NULL);
    164   ASSERT_EQ(r, UV_EEXIST);
    165   uv_fs_req_cleanup(&req);
    166 
    167   /* Truncates when an existing destination is larger than the source file. */
    168   ASSERT_OK(uv_fs_chmod(NULL, &req, dst, 0644, NULL));
    169   uv_fs_req_cleanup(&req);
    170   touch_file(src, 1);
    171   r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL);
    172   ASSERT_OK(r);
    173   handle_result(&req);
    174 
    175   /* Copies a larger file. */
    176   unlink(dst);
    177   touch_file(src, 4096 * 2);
    178   r = uv_fs_copyfile(NULL, &req, src, dst, 0, NULL);
    179   ASSERT_OK(r);
    180   handle_result(&req);
    181   unlink(src);
    182 
    183   /* Copies file asynchronously */
    184   unlink(dst);
    185   r = uv_fs_copyfile(loop, &req, fixture, dst, 0, handle_result);
    186   ASSERT_OK(r);
    187   ASSERT_EQ(5, result_check_count);
    188   uv_run(loop, UV_RUN_DEFAULT);
    189   ASSERT_EQ(6, result_check_count);
    190   /* Ensure file is user-writable (not copied from src). */
    191   ASSERT_OK(uv_fs_chmod(NULL, &req, dst, 0644, NULL));
    192   uv_fs_req_cleanup(&req);
    193 
    194   /* If the flags are invalid, the loop should not be kept open */
    195   unlink(dst);
    196   r = uv_fs_copyfile(loop, &req, fixture, dst, -1, fail_cb);
    197   ASSERT_EQ(r, UV_EINVAL);
    198   uv_run(loop, UV_RUN_DEFAULT);
    199 
    200   /* Copies file using UV_FS_COPYFILE_FICLONE. */
    201   unlink(dst);
    202   r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_FICLONE, NULL);
    203   ASSERT_OK(r);
    204   handle_result(&req);
    205 
    206   /* Copies file using UV_FS_COPYFILE_FICLONE_FORCE. */
    207   unlink(dst);
    208   r = uv_fs_copyfile(NULL, &req, fixture, dst, UV_FS_COPYFILE_FICLONE_FORCE,
    209                      NULL);
    210   ASSERT_LE(r, 0);
    211 
    212   if (r == 0)
    213     handle_result(&req);
    214 
    215 #ifndef _WIN32
    216   /* Copying respects permissions/mode. */
    217   unlink(dst);
    218   touch_file(dst, 0);
    219   chmod(dst, S_IRUSR|S_IRGRP|S_IROTH); /* Sets file mode to 444 (read-only). */
    220   r = uv_fs_copyfile(NULL, &req, fixture, dst, 0, NULL);
    221   /* On IBMi PASE, qsecofr users can overwrite read-only files */
    222 # ifndef __PASE__
    223   ASSERT_EQ(req.result, UV_EACCES);
    224   ASSERT_EQ(r, UV_EACCES);
    225 # endif
    226   uv_fs_req_cleanup(&req);
    227 #endif
    228 
    229   unlink(dst); /* Cleanup */
    230   MAKE_VALGRIND_HAPPY(loop);
    231   return 0;
    232 }
    233