tb_bool_t tb_directory_copy(tb_char_t const* path, tb_char_t const* dest) { // the absolute 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); // walk copy tb_value_t tuple[3]; tuple[0].cstr = dest; tuple[1].ul = tb_strlen(path); tuple[2].b = tb_true; tb_directory_walk(path, -1, tb_true, tb_directory_walk_copy, tuple); // ok? tb_bool_t ok = tuple[2].b; // copy empty directory? if (ok && !tb_file_info(dest, tb_null)) return tb_directory_create(dest); // ok? return ok; }
tb_bool_t tb_file_link(tb_char_t const* path, tb_char_t const* dest) { // check tb_assert_and_check_return_val(path && dest, tb_false); // 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); // symlink return !symlink(path, dest)? tb_true : tb_false; }
/* ////////////////////////////////////////////////////////////////////////////////////// * 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_directory_current_set(tb_char_t const* path) { // the absolute 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_false); // change to the directory return !chdir(path); }
static tb_bool_t xm_machine_main_get_program_directory(xm_machine_impl_t* impl, tb_char_t* path, tb_size_t maxn) { // check tb_assert_and_check_return_val(impl && path && maxn, tb_false); // done tb_bool_t ok = tb_false; do { #ifdef TB_CONFIG_OS_WINDOWS // get the program directory tb_size_t size = GetModuleFileName(tb_null, path, maxn); tb_assert_and_check_break(size < maxn); // end path[size] = '\0'; // get the directory while (size-- > 0) { if (path[size] == '\\') { path[size] = '\0'; break; } } #else // get it from the environment variable tb_char_t data[TB_PATH_MAXN] = {0}; if (!tb_environment_first("XMAKE_PROGRAM_DIR", data, sizeof(data))) { // error tb_printf("error: please set XMAKE_PROGRAM_DIR first!\n"); break; } // get the full path if (!tb_path_absolute(data, path, maxn)) break; #endif // trace tb_trace_d("program: %s", path); // save the directory to the global variable: _PROGRAM_DIR lua_pushstring(impl->lua, path); lua_setglobal(impl->lua, "_PROGRAM_DIR"); // ok ok = tb_true; } while (0); // ok? return ok; }
tb_bool_t tb_file_remove(tb_char_t const* path) { // check tb_assert_and_check_return_val(path, tb_false); // 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_false); // remove it return !remove(path)? tb_true : tb_false; }
tb_bool_t tb_directory_copy(tb_char_t const* path, tb_char_t const* dest) { // the absolute 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); // walk copy tb_value_t tuple[3]; tuple[0].cstr = dest; tuple[1].ul = tb_strlen(path); tuple[2].b = tb_true; tb_directory_walk_impl(path, tb_true, tb_true, tb_directory_walk_copy, tuple); // ok? return tuple[2].b; }
tb_bool_t tb_directory_remove(tb_char_t const* path) { // the absolute 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_false); // walk remove tb_directory_walk_impl(path, tb_true, tb_false, tb_directory_walk_remove, tb_null); // remove it return !remove(path)? tb_true : tb_false; }
tb_bool_t tb_file_info(tb_char_t const* path, tb_file_info_t* info) { // check tb_assert_and_check_return_val(path, tb_false); // the full path (need translate "~/") tb_char_t full[TB_PATH_MAXN]; path = tb_path_absolute(path, full, TB_PATH_MAXN); tb_assert_and_check_return_val(path, tb_false); // exists? tb_check_return_val(!access(path, F_OK), tb_false); // get info if (info) { // init info tb_memset(info, 0, sizeof(tb_file_info_t)); // get stat #ifdef TB_CONFIG_POSIX_HAVE_STAT64 struct stat64 st = {0}; if (!stat64(path, &st)) #else struct stat st = {0}; if (!stat(path, &st)) #endif { // file type if (S_ISDIR(st.st_mode)) info->type = TB_FILE_TYPE_DIRECTORY; else info->type = TB_FILE_TYPE_FILE; // file size info->size = st.st_size >= 0? (tb_hize_t)st.st_size : 0; // the last access time info->atime = (tb_time_t)st.st_atime; // the last modify time info->mtime = (tb_time_t)st.st_mtime; } } // ok return tb_true; }
tb_void_t tb_directory_walk(tb_char_t const* path, tb_bool_t recursion, tb_bool_t prefix, tb_directory_walk_func_t func, tb_cpointer_t priv) { // check tb_assert_and_check_return(path && func); // exists? tb_file_info_t info = {0}; if (tb_file_info(path, &info) && info.type == TB_FILE_TYPE_DIRECTORY) tb_directory_walk_impl(path, recursion, prefix, func, priv); else { // the absolute path tb_char_t full[TB_PATH_MAXN]; path = tb_path_absolute(path, full, TB_PATH_MAXN); tb_assert_and_check_return(path); // walk tb_directory_walk_impl(path, recursion, prefix, func, priv); } }
/* ////////////////////////////////////////////////////////////////////////////////////// * implementation */ tb_bool_t tb_directory_create(tb_char_t const* path) { // check tb_assert_and_check_return_val(path, tb_false); // the absolute 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_false); // make it tb_bool_t ok = !mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO)? tb_true : tb_false; if (!ok) { // make directory tb_char_t temp[TB_PATH_MAXN] = {0}; tb_char_t const* p = full; tb_char_t* t = temp; tb_char_t const* e = temp + TB_PATH_MAXN - 1; for (; t < e && *p; t++) { *t = *p; if (*p == '/') { // make directory if not exists if (!tb_file_info(temp, tb_null)) mkdir(temp, S_IRWXU | S_IRWXG | S_IRWXO); // skip repeat '/' while (*p && *p == '/') p++; } else p++; } // make it again ok = !mkdir(path, S_IRWXU | S_IRWXG | S_IRWXO)? tb_true : tb_false; } // ok? return ok; }
static tb_bool_t xm_machine_main_get_project_directory(xm_machine_impl_t* impl, tb_char_t* path, tb_size_t maxn) { // check tb_assert_and_check_return_val(impl && path && maxn, tb_false); // done tb_bool_t ok = tb_false; do { // attempt to get it from the environment variable first tb_char_t data[TB_PATH_MAXN] = {0}; if ( !tb_environment_first("XMAKE_PROJECT_DIR", data, sizeof(data)) || !tb_path_absolute(data, path, maxn)) { // get it from the current directory if (!tb_directory_current(path, maxn)) break; } // trace tb_trace_d("project: %s", path); // save the directory to the global variable: _PROJECT_DIR lua_pushstring(impl->lua, path); lua_setglobal(impl->lua, "_PROJECT_DIR"); // ok ok = tb_true; } while (0); // failed? if (!ok) tb_printf("error: not found the project directory!\n"); // ok? return ok; }
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 }
tb_char_t const* tb_path_relative_to(tb_char_t const* root, tb_char_t const* path, tb_char_t* data, tb_size_t maxn) { // check tb_assert_and_check_return_val(path && data && maxn, tb_null); // trace tb_trace_d("path: %s", path); // the root is the current and the path is absolute? return path directly if (!root && !tb_path_is_absolute(path)) { // copy it tb_strlcpy(data, path, maxn); // translate it return tb_path_translate(data, 0, maxn)? data : tb_null; } // get the absolute path tb_size_t path_size = 0; tb_char_t path_absolute[TB_PATH_MAXN]; tb_size_t path_maxn = sizeof(path_absolute); path = tb_path_absolute(path, path_absolute, path_maxn); path_size = tb_strlen(path); tb_assert_and_check_return_val(path && path_size && path_size < path_maxn, tb_null); // trace tb_trace_d("path_absolute: %s", path); // get the absolute root tb_size_t root_size = 0; tb_char_t root_absolute[TB_PATH_MAXN]; tb_size_t root_maxn = sizeof(root_absolute); if (root) { // get the absolute root root = tb_path_absolute(root, root_absolute, root_maxn); root_size = tb_strlen(root); } else { // get the current directory if (!(root_size = tb_directory_current(root_absolute, root_maxn))) return tb_null; // translate it if (!(root_size = tb_path_translate(root_absolute, root_size, root_maxn))) return tb_null; root = root_absolute; } tb_assert_and_check_return_val(root && root_size && root_size < root_maxn, tb_null); // trace tb_trace_d("root_absolute: %s", root); // same directory? return "." if (path_size == root_size && !tb_strncmp(path, root, root_size)) { // check tb_assert_and_check_return_val(maxn >= 2, "."); // return "." data[0] = '.'; data[1] = '\0'; return data; } // append separator if (path_size + 1 < path_maxn) { path_absolute[path_size++] = TB_PATH_SEPARATOR; path_absolute[path_size] = '\0'; } if (root_size + 1 < root_maxn) { root_absolute[root_size++] = TB_PATH_SEPARATOR; root_absolute[root_size] = '\0'; } // find the common leading directory tb_char_t const* p = path; tb_char_t const* q = root; tb_long_t last = -1; for (; *p && *q && *p == *q; q++, p++) { // save the last separator if (*p == TB_PATH_SEPARATOR) last = q - root; } // is different directory or outside the windows drive root? using the absolute path if (last <= 0 || (last == 2 && root[1] == ':')) { // the path size tb_size_t size = tb_min(path_size - 1, maxn); // copy it tb_strncpy(data, path, size); data[size] = '\0'; } // exists same root? else { // count the remaining levels in root tb_size_t count = 0; tb_char_t const* l = root + last + 1; for (; *l; l++) { if (*l == TB_PATH_SEPARATOR) count++; } // append "../" or "..\\" tb_char_t* d = data; tb_char_t* e = data + maxn; while (count--) { if (d + 3 < e) { d[0] = '.'; d[1] = '.'; d[2] = TB_PATH_SEPARATOR; d += 3; } } // append the left path l = path + last + 1; while (*l && d < e) *d++ = *l++; // remove the last separator if (d > data) d--; // end *d = '\0'; } // trace tb_trace_d("relative: %s", data); // ok? return data; }