/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_file_ref_t tb_file_init(tb_char_t const* path, tb_size_t mode) { // check tb_assert_and_check_return_val(path, tb_null); // the full path tb_char_t full[TB_PATH_MAXN]; path = tb_path_absolute(path, full, TB_PATH_MAXN); tb_assert_and_check_return_val(path, tb_null); // flags tb_size_t flags = 0; if (mode & TB_FILE_MODE_RO) flags |= O_RDONLY; else if (mode & TB_FILE_MODE_WO) flags |= O_WRONLY; else if (mode & TB_FILE_MODE_RW) flags |= O_RDWR; if (mode & TB_FILE_MODE_CREAT) flags |= O_CREAT; if (mode & TB_FILE_MODE_APPEND) flags |= O_APPEND; if (mode & TB_FILE_MODE_TRUNC) flags |= O_TRUNC; // dma mode, no cache #ifdef TB_CONFIG_OS_LINUX if (mode & TB_FILE_MODE_DIRECT) flags |= O_DIRECT; #endif // for native aio aicp #if defined(TB_CONFIG_ASIO_HAVE_NAIO) if (mode & TB_FILE_MODE_ASIO) flags |= O_DIRECT; #endif // noblock flags |= O_NONBLOCK; // modes tb_size_t modes = 0; if (mode & TB_FILE_MODE_CREAT) { // 0644: -rw-r--r-- modes = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH; } // open it, @note need absolute path tb_long_t fd = open(path, flags, modes); if (fd < 0 && (mode & TB_FILE_MODE_CREAT)) { // open it again after creating the file directory tb_char_t dir[TB_PATH_MAXN]; if (tb_directory_create(tb_path_directory(path, dir, sizeof(dir)))) fd = open(path, flags, modes); } // trace tb_trace_d("open: %p", tb_fd2file(fd)); // ok? return tb_fd2file(fd); }
tb_bool_t tb_file_copy(tb_char_t const* path, tb_char_t const* dest) { // check tb_assert_and_check_return_val(path && dest, tb_false); #ifdef TB_CONFIG_POSIX_HAVE_COPYFILE // the full path tb_char_t full0[TB_PATH_MAXN]; path = tb_path_absolute(path, full0, TB_PATH_MAXN); tb_assert_and_check_return_val(path, tb_false); // the dest path tb_char_t full1[TB_PATH_MAXN]; dest = tb_path_absolute(dest, full1, TB_PATH_MAXN); tb_assert_and_check_return_val(dest, tb_false); // attempt to copy it directly if (!copyfile(path, dest, 0, COPYFILE_ALL)) return tb_true; else { // attempt to copy it again after creating directory tb_char_t dir[TB_PATH_MAXN]; if (tb_directory_create(tb_path_directory(dest, dir, sizeof(dir)))) return !copyfile(path, dest, 0, COPYFILE_ALL); } // failed return tb_false; #else tb_int_t ifd = -1; tb_int_t ofd = -1; tb_bool_t ok = tb_false; do { // get the absolute source path tb_char_t data[8192]; path = tb_path_absolute(path, data, sizeof(data)); tb_assert_and_check_break(path); // get stat.st_mode first #ifdef TB_CONFIG_POSIX_HAVE_STAT64 struct stat64 st = {0}; if (stat64(path, &st)) break; #else struct stat st = {0}; if (stat(path, &st)) break; #endif // open source file ifd = open(path, O_RDONLY); tb_check_break(ifd >= 0); // get the absolute source path dest = tb_path_absolute(dest, data, sizeof(data)); tb_assert_and_check_break(dest); // open destinate file and copy file mode ofd = open(dest, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); if (ofd < 0) { // attempt to open it again after creating directory tb_char_t dir[TB_PATH_MAXN]; if (tb_directory_create(tb_path_directory(dest, dir, sizeof(dir)))) ofd = open(dest, O_RDWR | O_CREAT | O_TRUNC, st.st_mode & (S_IRWXU | S_IRWXG | S_IRWXO)); } tb_check_break(ofd >= 0); // get file size tb_hize_t size = tb_file_size(tb_fd2file(ifd)); // init write size tb_hize_t writ = 0; // attempt to copy file using `sendfile` #ifdef TB_CONFIG_POSIX_HAVE_SENDFILE while (writ < size) { off_t seek = writ; tb_hong_t real = sendfile(ofd, ifd, &seek, (size_t)(size - writ)); if (real > 0) writ += real; else break; } /* attempt to copy file directly if sendfile failed * * sendfile() supports regular file only after "since Linux 2.6.33". */ if (writ != size) { lseek(ifd, 0, SEEK_SET); lseek(ofd, 0, SEEK_SET); } else { ok = tb_true; break; } #endif // copy file using `read` and `write` writ = 0; while (writ < size) { // read some data tb_int_t real = read(ifd, data, (size_t)tb_min(size - writ, sizeof(data))); if (real > 0) { real = write(ofd, data, real); if (real > 0) writ += real; else break; } else break; } // ok? ok = (writ == size); } while (0); // close source file if (ifd >= 0) close(ifd); ifd = -1; // close destinate file if (ofd >= 0) close(ofd); ofd = -1; // ok? return ok; #endif }