diff --git a/qse/configure b/qse/configure index 4d742bba..27f809b6 100755 --- a/qse/configure +++ b/qse/configure @@ -18650,7 +18650,7 @@ _ACEOF fi done -for ac_func in lseek64 stat64 fstat64 lstat64 ftruncate64 readdir64 dirfd +for ac_func in lseek64 ftruncate64 readdir64 dirfd do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -18662,7 +18662,31 @@ _ACEOF fi done -for ac_func in lstat fchmod fsync ftruncate +for ac_func in stat64 fstat64 lstat64 fstatat64 +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +for ac_func in fstat fstatat +do : + as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` +ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" +if eval test \"x\$"$as_ac_var"\" = x"yes"; then : + cat >>confdefs.h <<_ACEOF +#define `$as_echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +for ac_func in fchmod fchmodat fchown fchownat fsync ftruncate do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" @@ -18686,7 +18710,7 @@ _ACEOF fi done -for ac_func in utime utimes futimes lutimes futimens +for ac_func in utime utimes futimes lutimes futimens utimensat do : as_ac_var=`$as_echo "ac_cv_func_$ac_func" | $as_tr_sh` ac_fn_c_check_func "$LINENO" "$ac_func" "$as_ac_var" diff --git a/qse/configure.ac b/qse/configure.ac index fa1ee3c6..8d11d699 100644 --- a/qse/configure.ac +++ b/qse/configure.ac @@ -145,10 +145,12 @@ AC_CHECK_FUNCS([mbrlen mbrtowc wcrtomb]) AC_CHECK_FUNCS([mbsnrtowcs mbsrtowcs wcsnrtombs wcsrtombs]) AC_CHECK_FUNCS([wctype iswctype wctrans towctrans]) AC_CHECK_FUNCS([isblank iswblank]) -AC_CHECK_FUNCS([lseek64 stat64 fstat64 lstat64 ftruncate64 readdir64 dirfd]) -AC_CHECK_FUNCS([lstat fchmod fsync ftruncate]) +AC_CHECK_FUNCS([lseek64 ftruncate64 readdir64 dirfd]) +AC_CHECK_FUNCS([stat64 fstat64 lstat64 fstatat64]) +AC_CHECK_FUNCS([fstat fstatat]) +AC_CHECK_FUNCS([fchmod fchmodat fchown fchownat fsync ftruncate]) AC_CHECK_FUNCS([timegm timelocal localtime_r gettimeofday settimeofday]) -AC_CHECK_FUNCS([utime utimes futimes lutimes futimens]) +AC_CHECK_FUNCS([utime utimes futimes lutimes futimens utimensat]) AC_CHECK_FUNCS([sysconf prctl fdopendir setrlimit getrlimit getpgid getpgrp]) AC_CHECK_FUNCS([backtrace backtrace_symbols]) AC_CHECK_FUNCS([fork vfork posix_spawn gettid nanosleep select]) diff --git a/qse/include/qse/config.h.in b/qse/include/qse/config.h.in index 7f366bcf..9e0f15dc 100644 --- a/qse/include/qse/config.h.in +++ b/qse/include/qse/config.h.in @@ -203,6 +203,15 @@ /* Define to 1 if you have the `fchmod' function. */ #undef HAVE_FCHMOD +/* Define to 1 if you have the `fchmodat' function. */ +#undef HAVE_FCHMODAT + +/* Define to 1 if you have the `fchown' function. */ +#undef HAVE_FCHOWN + +/* Define to 1 if you have the `fchownat' function. */ +#undef HAVE_FCHOWNAT + /* Define to 1 if you have the header file. */ #undef HAVE_FCNTL_H @@ -236,9 +245,18 @@ /* Define to 1 if you have the `fork' function. */ #undef HAVE_FORK +/* Define to 1 if you have the `fstat' function. */ +#undef HAVE_FSTAT + /* Define to 1 if you have the `fstat64' function. */ #undef HAVE_FSTAT64 +/* Define to 1 if you have the `fstatat' function. */ +#undef HAVE_FSTATAT + +/* Define to 1 if you have the `fstatat64' function. */ +#undef HAVE_FSTATAT64 + /* Define to 1 if you have the `fsync' function. */ #undef HAVE_FSYNC @@ -356,9 +374,6 @@ /* Define to 1 if you have the `lseek64' function. */ #undef HAVE_LSEEK64 -/* Define to 1 if you have the `lstat' function. */ -#undef HAVE_LSTAT - /* Define to 1 if you have the `lstat64' function. */ #undef HAVE_LSTAT64 @@ -745,6 +760,9 @@ /* Define to 1 if you have the `utime' function. */ #undef HAVE_UTIME +/* Define to 1 if you have the `utimensat' function. */ +#undef HAVE_UTIMENSAT + /* Define to 1 if you have the `utimes' function. */ #undef HAVE_UTIMES diff --git a/qse/include/qse/si/fs.h b/qse/include/qse/si/fs.h index abf7683e..822b1d09 100644 --- a/qse/include/qse/si/fs.h +++ b/qse/include/qse/si/fs.h @@ -140,6 +140,28 @@ struct qse_fs_attr_t typedef struct qse_fs_attr_t qse_fs_attr_t; +enum qse_fs_getattr_flag_t +{ + QSE_FS_GETATTR_SYMLINK = (1 << 15) +}; +typedef enum qse_fs_getattr_flag_t qse_fs_getattr_flag_t; + +enum qse_fs_setattr_flag_t +{ + QSE_FS_SETATTR_TIME = (1 << 0), + QSE_FS_SETATTR_OWNER = (1 << 1), + QSE_FS_SETATTR_MODE = (1 << 2), + + QSE_FS_SETATTR_SYMLINK = (1 << 15) /* work on the symbolic link itself. don't follow */ +}; +typedef enum qse_fs_setattr_flag_t qse_fs_setattr_flag_t; + +#if defined(_WIN32) +typedef void* qse_fs_handle_t; +#else +typedef int qse_fs_handle_t; +#endif + typedef struct qse_fs_t qse_fs_t; enum qse_fs_trait_t @@ -206,13 +228,14 @@ enum qse_fs_cpfile_flag_t QSE_FS_CPFILE_FORCE = (1 << 2), QSE_FS_CPFILE_PRESERVE = (1 << 3), QSE_FS_CPFILE_REPLACE = (1 << 4), - QSE_FS_CPFILE_SYMLINK = (1 << 5), - QSE_FS_CPFILE_NOTGTDIR = (1 << 6), /* no target directory */ + QSE_FS_CPFILE_NOTGTDIR = (1 << 5), /* no target directory */ + + QSE_FS_CPFILE_SYMLINK = (1 << 15), QSE_FS_CPFILE_ALL = (QSE_FS_CPFILE_GLOB | QSE_FS_CPFILE_RECURSIVE | QSE_FS_CPFILE_FORCE | QSE_FS_CPFILE_PRESERVE | - QSE_FS_CPFILE_REPLACE | QSE_FS_CPFILE_SYMLINK | - QSE_FS_CPFILE_NOTGTDIR) + QSE_FS_CPFILE_REPLACE | QSE_FS_CPFILE_NOTGTDIR | + QSE_FS_CPFILE_SYMLINK) }; typedef enum qse_fs_cpfile_flag_t qse_fs_cpfile_flag_t; @@ -317,24 +340,64 @@ QSE_EXPORT int qse_fs_pop ( const qse_char_t* name ); + + + +QSE_EXPORT int qse_fs_getattronfd ( + qse_fs_t* fs, + qse_fs_handle_t fd, + qse_fs_attr_t* attr, + int flags +); + +QSE_EXPORT int qse_fs_setattronfd ( + qse_fs_t* fs, + qse_fs_handle_t fd, + const qse_fs_attr_t* attr, + int flags /** bitwise-ORed #qse_fs_setattr_flag_t enumerators */ +); + QSE_EXPORT int qse_fs_getattrmbs ( qse_fs_t* fs, const qse_mchar_t* path, - qse_fs_attr_t* attr + qse_fs_attr_t* attr, + int flags ); QSE_EXPORT int qse_fs_getattrwcs ( qse_fs_t* fs, const qse_wchar_t* path, - qse_fs_attr_t* attr + qse_fs_attr_t* attr, + int flags ); +QSE_EXPORT int qse_fs_setattrmbs ( + qse_fs_t* fs, + qse_mchar_t* path, + const qse_fs_attr_t* attr, + int flags /** bitwise-ORed #qse_fs_setattr_flag_t enumerators */ +); + +QSE_EXPORT int qse_fs_setattrwcs ( + qse_fs_t* fs, + qse_wchar_t* path, + const qse_fs_attr_t* attr, + int flags /** bitwise-ORed #qse_fs_setattr_flag_t enumerators */ +); + + #if defined(QSE_CHAR_IS_MCHAR) -# define qse_fs_getattr(fs,path,attr) qse_fs_getattrmbs(fs,path,attr) +# define qse_fs_getattr(fs,path,attr,flags) qse_fs_getattrmbs(fs,path,attr,flags) +# define qse_fs_setattr(fs,path,attr,flags) qse_fssetattrmbs(fs,path,attr,flags) #else -# define qse_fs_getattr(fs,path,attr) qse_fs_getattrwcs(fs,path,attr) +# define qse_fs_getattr(fs,path,attr,flags) qse_fs_getattrwcs(fs,path,attr,flags) +# define qse_fs_setattr(fs,path,attr,flags) qse_fssetattrwcs(fs,path,attr,flags) #endif + + + + QSE_EXPORT int qse_fs_move ( qse_fs_t* fs, const qse_char_t* oldpath, @@ -408,6 +471,10 @@ QSE_EXPORT int qse_fs_deldirwcs ( # define qse_fs_deldir(fs,path,flags) qse_fs_deldirwcs(fs,path,flags) #endif + + + + #if defined(__cplusplus) } #endif diff --git a/qse/lib/cmn/syscall.h b/qse/lib/cmn/syscall.h index a37f50f1..09107556 100644 --- a/qse/lib/cmn/syscall.h +++ b/qse/lib/cmn/syscall.h @@ -114,20 +114,6 @@ # define QSE_LSEEK(handle,offset,whence) lseek(handle,offset,whence) #endif -#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_fstat64) && defined(QSE_USE_SYSCALL) -# define QSE_FSTAT(handle,stbuf) syscall(SYS_fstat64,handle,stbuf) - typedef struct stat64 qse_fstat_t; -#elif defined(SYS_fstat) && defined(QSE_USE_SYSCALL) -# define QSE_FSTAT(handle,stbuf) syscall(SYS_fstat,handle,stbuf) - typedef struct stat qse_fstat_t; -#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_FSTAT64) -# define QSE_FSTAT(handle,stbuf) fstat64(handle,stbuf) - typedef struct stat64 qse_fstat_t; -#else -# define QSE_FSTAT(handle,stbuf) fstat(handle,stbuf) - typedef struct stat qse_fstat_t; -#endif - #if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_ftruncate64) && defined(QSE_USE_SYSCALL) # define QSE_FTRUNCATE(handle,size) syscall(SYS_ftruncate64,handle,size) #elif defined(SYS_ftruncate) && defined(QSE_USE_SYSCALL) @@ -138,18 +124,6 @@ # define QSE_FTRUNCATE(handle,size) ftruncate(handle,size) #endif -#if defined(SYS_fchmod) && defined(QSE_USE_SYSCALL) -# define QSE_FCHMOD(handle,mode) syscall(SYS_fchmod,handle,mode) -#else -# define QSE_FCHMOD(handle,mode) fchmod(handle,mode) -#endif - -#if defined(SYS_fchown) && defined(QSE_USE_SYSCALL) -# define QSE_FCHOWN(handle,owner,group) syscall(SYS_fchown,handle,owner,group) -#else -# define QSE_FCHOWN(handle,owner,group) fchown(handle,owner,group) -#endif - #if defined(SYS_fsync) && defined(QSE_USE_SYSCALL) # define QSE_FSYNC(handle) syscall(SYS_fsync,handle) #else @@ -285,12 +259,36 @@ # define QSE_CHMOD(path,mode) chmod(path,mode) #endif +#if defined(SYS_fchmod) && defined(QSE_USE_SYSCALL) +# define QSE_FCHMOD(handle,mode) syscall(SYS_fchmod,handle,mode) +#else +# define QSE_FCHMOD(handle,mode) fchmod(handle,mode) +#endif + +#if defined(SYS_fchmodat) && defined(QSE_USE_SYSCALL) +# define QSE_FCHMODAT(dirfd,path,mode,flags) syscall(SYS_fchmodat,dirfd,path,mode,flags) +#else +# define QSE_FCHMODAT(dirfd,path,mode,flags) fchmodat(dirfd,path,mode,flags) +#endif + #if defined(SYS_chown) && defined(QSE_USE_SYSCALL) # define QSE_CHOWN(path,owner,group) syscall(SYS_chown,path,owner,group) #else # define QSE_CHOWN(path,owner,group) chown(path,owner,group) #endif +#if defined(SYS_fchown) && defined(QSE_USE_SYSCALL) +# define QSE_FCHOWN(handle,owner,group) syscall(SYS_fchown,handle,owner,group) +#else +# define QSE_FCHOWN(handle,owner,group) fchown(handle,owner,group) +#endif + +#if defined(SYS_fchownat) && defined(QSE_USE_SYSCALL) +# define QSE_FCHOWNAT(dirfd,path,uid,gid,flags) syscall(SYS_fchownat,dirfd,path,uid,gid,flags) +#else +# define QSE_FCHOWNAT(dirfd,path,uid,gid,flags) fchownat(dirfd,path,uid,gid,flags) +#endif + #if defined(SYS_chroot) && defined(QSE_USE_SYSCALL) # define QSE_CHROOT(path) syscall(SYS_chroot,path) #else @@ -309,6 +307,35 @@ # define QSE_LINK(oldpath,newpath) link(oldpath,newpath) #endif + +#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_fstat64) && defined(QSE_USE_SYSCALL) +# define QSE_FSTAT(handle,stbuf) syscall(SYS_fstat64,handle,stbuf) + typedef struct stat64 qse_fstat_t; +#elif defined(SYS_fstat) && defined(QSE_USE_SYSCALL) +# define QSE_FSTAT(handle,stbuf) syscall(SYS_fstat,handle,stbuf) + typedef struct stat qse_fstat_t; +#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_FSTAT64) +# define QSE_FSTAT(handle,stbuf) fstat64(handle,stbuf) + typedef struct stat64 qse_fstat_t; +#else +# define QSE_FSTAT(handle,stbuf) fstat(handle,stbuf) + typedef struct stat qse_fstat_t; +#endif + +#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_stat64) && defined(QSE_USE_SYSCALL) +# define QSE_STAT(path,stbuf) syscall(SYS_stat64,path,stbuf) + typedef struct stat64 qse_stat_t; +#elif defined(SYS_stat) && defined(QSE_USE_SYSCALL) +# define QSE_STAT(path,stbuf) syscall(SYS_stat,path,stbuf) + typedef struct stat qse_stat_t; +#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_STAT64) +# define QSE_STAT(path,stbuf) stat64(path,stbuf) + typedef struct stat64 qse_stat_t; +#else +# define QSE_STAT(path,stbuf) stat(path,stbuf) + typedef struct stat qse_stat_t; +#endif + #if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_lstat64) && defined(QSE_USE_SYSCALL) # define QSE_LSTAT(path,stbuf) syscall(SYS_lstat,path,stbuf) typedef struct stat64 qse_lstat_t; @@ -323,6 +350,21 @@ typedef struct stat qse_lstat_t; #endif + +#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_fstatat64) && defined(QSE_USE_SYSCALL) +# define QSE_FSTATAT(dirfd,path,stbuf,flags) syscall(SYS_fstatat,dirfd,path,stbuf,flags) + typedef struct stat64 qse_fstatat_t; +#elif defined(SYS_fstatat) && defined(QSE_USE_SYSCALL) +# define QSE_FSTATAT(dirfd,path,stbuf,flags) syscall(SYS_fstatat,dirfd,path,stbuf,flags) + typedef struct stat qse_fstatat_t; +#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_FSTATAT64) +# define QSE_FSTATAT(dirfd,path,stbuf,flags) fstatat64(dirfd,path,stbuf,flags) + typedef struct stat64 qse_fstatat_t; +#else +# define QSE_FSTATAT(dirfd,path,stbuf,flags) fstatat(dirfd,path,stbuf,flags) + typedef struct stat qse_fstatat_t; +#endif + #if defined(SYS_access) && defined(QSE_USE_SYSCALL) # define QSE_ACCESS(path,mode) syscall(SYS_access,path,mode) #else @@ -348,20 +390,6 @@ # define QSE_RMDIR(path) rmdir(path) #endif -#if !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(SYS_stat64) && defined(QSE_USE_SYSCALL) -# define QSE_STAT(path,stbuf) syscall(SYS_stat64,path,stbuf) - typedef struct stat64 qse_stat_t; -#elif defined(SYS_stat) && defined(QSE_USE_SYSCALL) -# define QSE_STAT(path,stbuf) syscall(SYS_stat,path,stbuf) - typedef struct stat qse_stat_t; -#elif !defined(_LP64) && (QSE_SIZEOF_VOID_P<8) && defined(HAVE_STAT64) -# define QSE_STAT(path,stbuf) stat64(path,stbuf) - typedef struct stat64 qse_stat_t; -#else -# define QSE_STAT(path,stbuf) stat(path,stbuf) - typedef struct stat qse_stat_t; -#endif - #if defined(SYS_symlink) && defined(QSE_USE_SYSCALL) # define QSE_SYMLINK(oldpath,newpath) syscall(SYS_symlink,oldpath,newpath) #else @@ -410,6 +438,12 @@ # define QSE_FUTIMENS(fd,t) futimens(fd,t) #endif +#if defined(SYS_utimensat) && defined(QSE_USE_SYSCALL) +# define QSE_FUTIMENS(dirfd,path,times,flags) syscall(SYS_futimens,dirfd,path,times,flags) +#else +# define QSE_UTIMENSAT(dirfd,path,times,flags) utimensat(dirfd,path,times,flags) +#endif + /* ===== DIRECTORY - not really system calls ===== */ #define QSE_OPENDIR(name) opendir(name) #define QSE_CLOSEDIR(dir) closedir(dir) diff --git a/qse/lib/http/httpd-proxy.c b/qse/lib/http/httpd-proxy.c index 87002e35..410dfbf0 100644 --- a/qse/lib/http/httpd-proxy.c +++ b/qse/lib/http/httpd-proxy.c @@ -1122,7 +1122,7 @@ static int task_init_proxy (qse_httpd_t* httpd, qse_httpd_client_t* client, qse_ /* length must include the parameters also */ proxy->qpath_len_in_reqfwdbuf = QSE_STR_LEN(proxy->reqfwdbuf) - proxy->qpath_pos_in_reqfwdbuf; -#if 0 +#if 1 { /* EXPERIMENTAL */ /* KT FILTERING WORKAROUND POC. KT seems to check the Host: the first packet diff --git a/qse/lib/si/fs-attr.c b/qse/lib/si/fs-attr.c index 00dd0df2..92c1fe5a 100644 --- a/qse/lib/si/fs-attr.c +++ b/qse/lib/si/fs-attr.c @@ -27,7 +27,164 @@ #include "fs-prv.h" #include "../cmn/mem-prv.h" -int qse_fs_sysgetattr (qse_fs_t* fs, const qse_fs_char_t* fspath, qse_fs_attr_t* attr) + +static void stat_to_attr (const qse_stat_t* st, qse_fs_attr_t* attr) +{ + QSE_MEMSET (attr, 0, QSE_SIZEOF(*attr)); + + if (S_ISDIR(st->st_mode)) attr->isdir = 1; + if (S_ISLNK(st->st_mode)) attr->islnk = 1; + if (S_ISREG(st->st_mode)) attr->isreg = 1; + if (S_ISBLK(st->st_mode)) attr->isblk = 1; + if (S_ISCHR(st->st_mode)) attr->ischr = 1; + + attr->mode = st->st_mode; + attr->size = st->st_size; + attr->ino = st->st_ino; + attr->dev = st->st_dev; + attr->uid = st->st_uid; + attr->gid = st->st_gid; + +#if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) + attr->atime.sec = st->st_atim.tv_sec; + attr->atime.nsec = st->st_atim.tv_nsec; + attr->mtime.sec = st->st_mtim.tv_sec; + attr->mtime.nsec = st->st_mtim.tv_nsec; + attr->ctime.sec = st->st_ctim.tv_sec; + attr->ctime.nsec = st->st_ctim.tv_nsec; +#elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) + attr->atime.sec = st->st_atimespec.tv_sec; + attr->atime.nsec = st->st_atimespec.tv_nsec; + attr->mtime.sec = st->st_mtimespec.tv_sec; + attr->mtime.nsec = st->st_mtimespec.tv_nsec; + attr->ctime.sec = st->st_ctimespec.tv_sec; + attr->ctime.nsec = st->st_ctimespec.tv_nsec; +#else + attr->atime.sec = st->st_atime; + attr->mtime.sec = st->st_mtime; + attr->ctime.sec = st->st_ctime; +#endif +} + +int qse_fs_getattronfd (qse_fs_t* fs, qse_fs_handle_t fd, qse_fs_attr_t* attr, int flags) +{ +#if defined(_WIN32) + + fs->errnum = QSE_FS_ENOIMPL; + return -1; + +#elif defined(__OS2__) + + /* TODO */ + fs->errnum = QSE_FS_ENOIMPL; + return -1; + +#elif defined(__DOS__) + + fs->errnum = QSE_FS_ENOIMPL; + return -1; + +#elif defined(HAVE_FSTAT) + qse_fstat_t st; + + if (QSE_FSTAT (fd, &st) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + + stat_to_attr (&st, attr); + return 0; +#else + fs->errnum = QSE_FS_ENOIMPL; + return -1; +#endif +} + +int qse_fs_getattrsys (qse_fs_t* fs, const qse_fs_char_t* fspath, qse_fs_attr_t* attr, int flags) +{ +#if defined(_WIN32) + + fs->errnum = QSE_FS_ENOIMPL; + return -1; + +#elif defined(__OS2__) + + /* TODO */ + fs->errnum = QSE_FS_ENOIMPL; + return -1; + +#elif defined(__DOS__) + + fs->errnum = QSE_FS_ENOIMPL; + return -1; + +#elif defined(HAVE_FSTATAT) + + qse_fstatat_t st; + int sysflags = 0; + + if (flags & QSE_FS_GETATTR_SYMLINK) sysflags |= AT_SYMLINK_NOFOLLOW; + if (QSE_FSTATAT(AT_FDCWD, fspath, &st, sysflags) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + + stat_to_attr (&st, attr); + return 0; + +#else + qse_stat_t st; + int x; + + if (flags & QSE_FS_GETATTR_SYMLINK) + x = QSE_LSTAT (fspath, &st); + else + x = QSE_STAT (fspath, &st); + + if (x <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + + stat_to_attr (&st, attr); + return 0; +#endif +} + +int qse_fs_getattrmbs (qse_fs_t* fs, const qse_mchar_t* path, qse_fs_attr_t* attr, int flags) +{ + qse_fs_char_t* fspath; + int ret; + + fspath = qse_fs_makefspathformbs (fs, path); + if (!fspath) return -1; + + ret = qse_fs_getattrsys (fs, fspath, attr, flags); + + qse_fs_freefspathformbs (fs, path, fspath); + return ret; +} + +int qse_fs_getattrwcs (qse_fs_t* fs, const qse_wchar_t* path, qse_fs_attr_t* attr, int flags) +{ + qse_fs_char_t* fspath; + int ret; + + fspath = qse_fs_makefspathforwcs (fs, path); + if (!fspath) return -1; + + ret = qse_fs_getattrsys (fs, fspath, attr, flags); + + qse_fs_freefspathforwcs (fs, path, fspath); + return ret; +} + +/* -------------------------------------------------------------------------- */ + +int qse_fs_setattronfd (qse_fs_t* fs, qse_fs_handle_t fd, const qse_fs_attr_t* attr, int flags) { #if defined(_WIN32) @@ -46,66 +203,235 @@ int qse_fs_sysgetattr (qse_fs_t* fs, const qse_fs_char_t* fspath, qse_fs_attr_t* return -1; #else - #if defined(HAVE_LSTAT) - qse_lstat_t st; - #else - qse_stat_t st; - #endif - - #if defined(HAVE_LSTAT) - if (QSE_LSTAT (fspath, &st) == -1) + if (flags & QSE_FS_SETATTR_TIME) { - fs->errnum = qse_fs_syserrtoerrnum (fs, errno); - return -1; - } + #if defined(HAVE_FUTIMENS) && defined(HAVE_STRUCT_TIMESPEC) + struct timespec ts[2]; + + QSE_MEMSET (&ts, 0, QSE_SIZEOF(ts)); + ts[0].tv_sec = attr->atime.sec; + ts[0].tv_nsec = attr->atime.nsec; + ts[1].tv_sec = attr->mtime.sec; + ts[1].tv_nsec = attr->mtime.nsec; + if (QSE_FUTIMENS (fd, ts) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + + #elif defined(HAVE_FUTIMES) + struct timeval tv[2]; + + QSE_MEMSET (&tv, 0, QSE_SIZEOF(tv)); + tv[0].tv_sec = attr->atime.sec; + tv[0].tv_usec = QSE_NSEC_TO_USEC(attr->atime.nsec); + tv[1].tv_sec = attr->mtime.sec; + tv[1].tv_usec = QSE_NSEC_TO_USEC(attr->mtime.nsec); + if (QSE_FUTIMES (fspath, tv) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } #else - /* is this ok to use stat? */ - if (QSE_STAT (fspath, &st) == -1) + fs->errnum = QSE_FS_ENOIMPL; + return -1; + #endif + } + + if (flags & QSE_FS_SETATTR_OWNER) { - fs->errnum = qse_fs_syserrtoerrnum (fs, errno); - return -1; - } - #endif - - QSE_MEMSET (attr, 0, QSE_SIZEOF(*attr)); - - if (S_ISDIR(st.st_mode)) attr->isdir = 1; - if (S_ISLNK(st.st_mode)) attr->islnk = 1; - if (S_ISREG(st.st_mode)) attr->isreg = 1; - if (S_ISBLK(st.st_mode)) attr->isblk = 1; - if (S_ISCHR(st.st_mode)) attr->ischr = 1; - - attr->mode = st.st_mode; - attr->size = st.st_size; - attr->ino = st.st_ino; - attr->dev = st.st_dev; - attr->uid = st.st_uid; - attr->gid = st.st_gid; - - #if defined(HAVE_STRUCT_STAT_ST_MTIM_TV_NSEC) - attr->atime.sec = st.st_atim.tv_sec; - attr->atime.nsec = st.st_atim.tv_nsec; - attr->mtime.sec = st.st_mtim.tv_sec; - attr->mtime.nsec = st.st_mtim.tv_nsec; - attr->ctime.sec = st.st_ctim.tv_sec; - attr->ctime.nsec = st.st_ctim.tv_nsec; - #elif defined(HAVE_STRUCT_STAT_ST_MTIMESPEC_TV_NSEC) - attr->atime.sec = st.st_atimespec.tv_sec; - attr->atime.nsec = st.st_atimespec.tv_nsec; - attr->mtime.sec = st.st_mtimespec.tv_sec; - attr->mtime.nsec = st.st_mtimespec.tv_nsec; - attr->ctime.sec = st.st_ctimespec.tv_sec; - attr->ctime.nsec = st.st_ctimespec.tv_nsec; + #if defined(HAVE_FCHOWN) + if (QSE_FCHOWN (fd, attr->uid, attr->gid) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } #else - attr->atime.sec = st.st_atime; - attr->mtime.sec = st.st_mtime; - attr->ctime.sec = st.st_ctime; + fs->errnum = QSE_FS_ENOIMPL; + return -1; #endif + } + + if (flags & QSE_FS_SETATTR_MODE) + { + #if defined(HAVE_FCHMOD) + if (QSE_FCHMOD(fd, attr->mode) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + #else + fs->errnum = QSE_FS_ENOIMPL; + return -1; + #endif + } + return 0; #endif } -int qse_fs_getattrmbs (qse_fs_t* fs, const qse_mchar_t* path, qse_fs_attr_t* attr) +int qse_fs_setattrsys (qse_fs_t* fs, qse_fs_char_t* path, const qse_fs_attr_t* attr, int flags) +{ + +#if defined(_WIN32) + + fs->errnum = QSE_FS_ENOIMPL; + return -1; + +#elif defined(__OS2__) + + /* TODO */ + fs->errnum = QSE_FS_ENOIMPL; + return -1; + +#elif defined(__DOS__) + + fs->errnum = QSE_FS_ENOIMPL; + return -1; + +#else + if (flags & QSE_FS_SETATTR_TIME) + { + #if defined(HAVE_UTIMENSAT) + struct timespec ts[2]; + int sysflags = 0; + + if (flags & QSE_FS_SETATTR_SYMLINK) sysflags |= AT_SYMLINK_NOFOLLOW; + + QSE_MEMSET (&ts, 0, QSE_SIZEOF(ts)); + ts[0].tv_sec = attr->atime.sec; + ts[0].tv_nsec = attr->atime.nsec; + ts[1].tv_sec = attr->mtime.sec; + ts[1].tv_nsec = attr->mtime.nsec; + + if (QSE_UTIMENSAT(AT_FDCWD, path, NULL, sysflags) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + + #else + if (flags & QSE_FS_SETATTR_SYMLINK) + { + #if defined(HAVE_LUTIMES) + struct timeval tv[2]; + + QSE_MEMSET (&tv, 0, QSE_SIZEOF(tv)); + tv[0].tv_sec = attr->atime.sec; + tv[0].tv_usec = QSE_NSEC_TO_USEC(attr->atime.nsec); + tv[1].tv_sec = attr->mtime.sec; + tv[1].tv_usec = QSE_NSEC_TO_USEC(attr->mtime.nsec); + + if (QSE_LUTIMES (path, tv) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + #else + fs->errnum = QSE_FS_ENOIMPL; + return -1; + #endif + } + else + { + #if defined(HAVE_UTIMES) + struct timeval tv[2]; + + QSE_MEMSET (&tv, 0, QSE_SIZEOF(tv)); + tv[0].tv_sec = attr->atime.sec; + tv[0].tv_usec = QSE_NSEC_TO_USEC(attr->atime.nsec); + tv[1].tv_sec = attr->mtime.sec; + tv[1].tv_usec = QSE_NSEC_TO_USEC(attr->mtime.nsec); + + if (QSE_UTIMES (path, tv) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + + #elif defined(HAVE_UTIME) + struct utimbuf ub; + + QSE_MEMSET (&ub, 0, QSE_SIZEOF(ub)); + ub.actime = attr->atime.sec; + ub.modtime = attr->mtime.sec; + if (QSE_UTIME (path, &ub) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + + #else + fs->errnum = QSE_FS_ENOIMPL; + return -1; + #endif + } + #endif + } + + if (flags & QSE_FS_SETATTR_OWNER) + { + #if defined(QSE_FCHOWNAT) + int sysflags = 0; + + if (flags & QSE_FS_SETATTR_SYMLINK) sysflags |= AT_SYMLINK_NOFOLLOW; + + if (QSE_FCHOWNAT(AT_FDCWD, path, attr->uid, attr->gid, sysflags) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + #else + int x; + + if (flags & QSE_FS_SETATTR_SYMLINK) + x = QSE_LCHOWN (path, attr->uid, attr->gid); + else + x = QSE_CHOWN (path, attr->uid, attr->gid); + + if (x <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + #endif + } + + if (flags & QSE_FS_SETATTR_MODE) + { + #if defined(QSE_FCHMODAT) + int sysflags = 0; + + if (flags & QSE_FS_SETATTR_SYMLINK) sysflags |= AT_SYMLINK_NOFOLLOW; + + if (QSE_FCHMODAT(AT_FDCWD, path, attr->mode, sysflags) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + #else + if (flags & QSE_FS_SETATTR_SYMLINK) + { + /* not supported. symlink permission is kind of fixed. + * do nothing */ + } + else + { + if (QSE_CHMOD(path, attr->mode) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + return -1; + } + } + #endif + } + + return 0; +#endif +} + + +int qse_fs_setattrmbs (qse_fs_t* fs, qse_mchar_t* path, const qse_fs_attr_t* attr, int flags) { qse_fs_char_t* fspath; int ret; @@ -113,13 +439,14 @@ int qse_fs_getattrmbs (qse_fs_t* fs, const qse_mchar_t* path, qse_fs_attr_t* att fspath = qse_fs_makefspathformbs (fs, path); if (!fspath) return -1; - ret = qse_fs_sysgetattr (fs, fspath, attr); + ret = qse_fs_setattrsys (fs, fspath, attr, flags); qse_fs_freefspathformbs (fs, path, fspath); return ret; } -int qse_fs_getattrwcs (qse_fs_t* fs, const qse_wchar_t* path, qse_fs_attr_t* attr) + +int qse_fs_setattrwcs (qse_fs_t* fs, qse_wchar_t* path, const qse_fs_attr_t* attr, int flags) { qse_fs_char_t* fspath; int ret; @@ -127,7 +454,7 @@ int qse_fs_getattrwcs (qse_fs_t* fs, const qse_wchar_t* path, qse_fs_attr_t* att fspath = qse_fs_makefspathforwcs (fs, path); if (!fspath) return -1; - ret = qse_fs_sysgetattr (fs, fspath, attr); + ret = qse_fs_setattrsys (fs, fspath, attr, flags); qse_fs_freefspathforwcs (fs, path, fspath); return ret; diff --git a/qse/lib/si/fs-copy.c b/qse/lib/si/fs-copy.c index 92e89d95..70606f7d 100644 --- a/qse/lib/si/fs-copy.c +++ b/qse/lib/si/fs-copy.c @@ -38,10 +38,8 @@ struct cpfile_t { int flags; - qse_fs_char_t* src_fspath; qse_fs_char_t* dst_fspath; - qse_fs_attr_t src_attr; qse_fs_attr_t dst_attr; }; @@ -67,7 +65,8 @@ static int merge_dstdir_and_file (qse_fs_t* fs, cpfile_t* cpfile) qse_fs_freefspath (fs, QSE_NULL, cpfile->dst_fspath); cpfile->dst_fspath = fstmp; - if (qse_fs_sysgetattr (fs, cpfile->dst_fspath, &cpfile->dst_attr) <= -1) +/* TODO: check on the flags to getattrsys()... */ + if (qse_fs_getattrsys (fs, cpfile->dst_fspath, &cpfile->dst_attr, 0) <= -1) { /* attribute on the new destination is not available */ cpfile->flags &= ~CPFILE_DST_ATTR; @@ -280,17 +279,6 @@ static int copy_file_in_fs (qse_fs_t* fs, cpfile_t* cpfile) goto oops; } - #elif defined(HAVE_UTIME) - - QSE_MEMSET (&ub, 0, QSE_SIZEOF(ub)); - ub.actime = cpfile->src_attr.atime.sec; - ub.modtime = cpfile->src_attr.mtime.sec; - if (QSE_UTIME (cpfile->dst_fspath, &ub) <= -1) - { - fs->errnum = qse_fs_syserrtoerrnum (fs, errno); - goto oops; - } - #elif defined(HAVE_UTIMES) QSE_MEMSET (&tv, 0, QSE_SIZEOF(tv)); @@ -305,6 +293,17 @@ static int copy_file_in_fs (qse_fs_t* fs, cpfile_t* cpfile) goto oops; } + #elif defined(HAVE_UTIME) + + QSE_MEMSET (&ub, 0, QSE_SIZEOF(ub)); + ub.actime = cpfile->src_attr.atime.sec; + ub.modtime = cpfile->src_attr.mtime.sec; + if (QSE_UTIME (cpfile->dst_fspath, &ub) <= -1) + { + fs->errnum = qse_fs_syserrtoerrnum (fs, errno); + goto oops; + } + #else # error none of futimens, futimes, utime, utimes exist #endif @@ -327,8 +326,9 @@ static int prepare_cpfile (qse_fs_t* fs, cpfile_t* cpfile) { /* error if the source file can't be stat'ed. * ok if the destination file can't be stat'ed */ - if (qse_fs_sysgetattr (fs, cpfile->src_fspath, &cpfile->src_attr) <= -1) return -1; - if (qse_fs_sysgetattr (fs, cpfile->dst_fspath, &cpfile->dst_attr) >= 0) cpfile->flags |= CPFILE_DST_ATTR; +/* TODO: check on flags to getattrsys() */ + if (qse_fs_getattrsys (fs, cpfile->src_fspath, &cpfile->src_attr, 0) <= -1) return -1; + if (qse_fs_getattrsys (fs, cpfile->dst_fspath, &cpfile->dst_attr, 0) >= 0) cpfile->flags |= CPFILE_DST_ATTR; return 0; } @@ -634,3 +634,198 @@ oops: clear_cpfile (fs, &cpfile); return -1; } + + +#if 0 +/* --------------------------------------------------------------------- */ +/* + * Copyright (c) 1983 Regents of the University of California. + * All rights reserved. The Berkeley software License Agreement + * specifies the terms and conditions for redistribution. + */ + +static int copy (const char* from, const char* to) +{ + int fold, fnew, n, exists; + char *last, destname[MAXPATHLEN + 1], buf[MAXBSIZE]; + struct stat stfrom, stto; + + fold = open (from, O_RDONLY); + if (fold < 0) + { + return -1; + } + + if (fstat(fold, &stfrom) < 0) + { + close(fold); + return -1; + } + + if (stat(to, &stto) >= 0 && (stto.st_mode&S_IFMT) == S_IFDIR) + { + last = rindex(from, '/'); + if (last) last++; else last = from; + + if (strlen(to) + strlen(last) >= sizeof(destname) - 1) + { + /* name too long */ + close(fold); + return(1); + } + + (void) sprintf(destname, "%s/%s", to, last); + to = destname; + } + + if (rflag && (stfrom.st_mode&S_IFMT) == S_IFDIR) + { + int fixmode = 0; /* cleanup mode after rcopy */ + + close(fold); + if (stat(to, &stto) < 0) + { + if (mkdir(to, (stfrom.st_mode & 07777) | 0700) < 0) + { + Perror(to); + return (1); + } + fixmode = 1; + } + else if ((stto.st_mode&S_IFMT) != S_IFDIR) + { + fprintf(stderr, "cp: %s: Not a directory.\n", to); + return (1); + } + else if (pflag) + { + fixmode = 1; + } + + n = rcopy(from, to); + if (fixmode) chmod(to, stfrom.st_mode & 07777); + return (n); + } + + if ((stfrom.st_mode&S_IFMT) == S_IFDIR) + fprintf(stderr, + "cp: %s: Is a directory (copying as plain file).\n", + from); + + exists = stat(to, &stto) == 0; + if (exists) + { + if (stfrom.st_dev == stto.st_dev && stfrom.st_ino == stto.st_ino) + { + fprintf(stderr, + "cp: %s and %s are identical (not copied).\n", from, to); + close(fold); + return (1); + } + if (iflag && isatty(fileno(stdin))) + { + int i, c; + + fprintf (stderr, "overwrite %s? ", to); + i = c = getchar(); + + while (c != '\n' && c != EOF) + c = getchar(); + if (i != 'y') + { + close(fold); + return(1); + } + } + } + + fnew = creat(to, stfrom.st_mode & 07777); + if (fnew < 0) + { + Perror(to); + (void) close(fold); + return(1); + } + + if (exists && pflag) + fchmod(fnew, stfrom.st_mode & 07777); + + for (;;) + { + /* use vmsplice() to copy??? */ + n = read(fold, buf, sizeof buf); + if (n == 0) break; + + if (n < 0) + { + Perror(from); + close(fold); + close(fnew); + return (1); + } + if (write(fnew, buf, n) != n) + { + Perror(to); + close(fold); + close(fnew); + return (1); + } + } + + close(fold); + close(fnew); + if (pflag) return (setimes(to, &stfrom)); + return (0); +} + +int rcopy(const char* from, const char* to) +{ + DIR *fold = opendir(from); + struct direct *dp; + struct stat statb; + int errs = 0; + char fromname[MAXPATHLEN + 1]; + + if (fold == 0 || (pflag && fstat(fold->dd_fd, &statb) < 0)) { + Perror(from); + return (1); + } + for (;;) + { + dp = readdir(fold); + if (dp == 0) + { + closedir(fold); + if (pflag) return (setimes(to, &statb) + errs); + return (errs); + } + if (dp->d_ino == 0) continue; + if (!strcmp(dp->d_name, ".") || !strcmp(dp->d_name, "..")) continue; + if (strlen(from)+1+strlen(dp->d_name) >= sizeof fromname - 1) + { + fprintf(stderr, "cp: %s/%s: Name too long.\n", from, dp->d_name); + errs++; + continue; + } + + sprintf(fromname, "%s/%s", from, dp->d_name); + errs += copy(fromname, to); + } +} + +static int setimes(const char* path, const struct stat* statp) +{ + struct timeval tv[2]; + + tv[0].tv_sec = statp->st_atime; + tv[1].tv_sec = statp->st_mtime; + tv[0].tv_usec = tv[1].tv_usec = 0; + if (utimes(path, tv) < 0) + { + Perror(path); + return (1); + } + return (0); +} + +#endif diff --git a/qse/lib/si/fs-prv.h b/qse/lib/si/fs-prv.h index 06dd5286..8362aa1a 100644 --- a/qse/lib/si/fs-prv.h +++ b/qse/lib/si/fs-prv.h @@ -143,10 +143,18 @@ void qse_fs_freefspathforwcs ( # define qse_fs_freefspath(fs,path,fspath) qse_fs_freefspathforwcs(fs,path,fspath); #endif -int qse_fs_sysgetattr ( +int qse_fs_getattrsys ( qse_fs_t* fs, const qse_fs_char_t* fspath, - qse_fs_attr_t* attr + qse_fs_attr_t* attr, + int flags +); + +int qse_fs_setattrsys ( + qse_fs_t* fs, + qse_fs_char_t* path, + const qse_fs_attr_t* attr, + int flags /** bitwise-ORed #qse_fs_setattr_flag_t enumerators */ ); int qse_fs_syscpfile (