summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--file.c14
-rw-r--r--win32/file.h2
-rw-r--r--win32/win32.c41
3 files changed, 53 insertions, 4 deletions
diff --git a/file.c b/file.c
index e6edbba..f4ba59a 100644
--- a/file.c
+++ b/file.c
@@ -2357,7 +2357,7 @@ rb_file_chmod(VALUE obj, VALUE vmode)
{
rb_io_t *fptr;
int mode;
-#ifndef HAVE_FCHMOD
+#if !defined HAVE_FCHMOD || !HAVE_FCHMOD
VALUE path;
#endif
@@ -2365,9 +2365,15 @@ rb_file_chmod(VALUE obj, VALUE vmode)
GetOpenFile(obj, fptr);
#ifdef HAVE_FCHMOD
- if (fchmod(fptr->fd, mode) == -1)
- rb_sys_fail_path(fptr->pathv);
-#else
+ if (fchmod(fptr->fd, mode) == -1) {
+ if (HAVE_FCHMOD || errno != ENOSYS)
+ rb_sys_fail_path(fptr->pathv);
+ }
+ else {
+ if (!HAVE_FCHMOD) return INT2FIX(0);
+ }
+#endif
+#if !defined HAVE_FCHMOD || !HAVE_FCHMOD
if (NIL_P(fptr->pathv)) return Qnil;
path = rb_str_encode_ospath(fptr->pathv);
if (chmod(RSTRING_PTR(path), mode) == -1)
diff --git a/win32/file.h b/win32/file.h
index deebbfa..624707f 100644
--- a/win32/file.h
+++ b/win32/file.h
@@ -39,5 +39,7 @@ int rb_w32_read_reparse_point(const WCHAR *path, rb_w32_reparse_buffer_t *rp,
int lchown(const char *path, int owner, int group);
int rb_w32_ulchown(const char *path, int owner, int group);
+int fchmod(int fd, int mode);
+#define HAVE_FCHMOD 0
#endif /* RUBY_WIN32_FILE_H */
diff --git a/win32/win32.c b/win32/win32.c
index a3a76c1..70e95d1 100644
--- a/win32/win32.c
+++ b/win32/win32.c
@@ -7315,6 +7315,47 @@ rb_w32_uchmod(const char *path, int mode)
/* License: Ruby's */
int
+fchmod(int fd, int mode)
+{
+ typedef BOOL (WINAPI *set_file_information_by_handle_func)
+ (HANDLE, int, void*, DWORD);
+ static set_file_information_by_handle_func set_file_info =
+ (set_file_information_by_handle_func)-1;
+
+ /* from winbase.h of the mingw-w64 runtime package. */
+ struct {
+ LARGE_INTEGER CreationTime;
+ LARGE_INTEGER LastAccessTime;
+ LARGE_INTEGER LastWriteTime;
+ LARGE_INTEGER ChangeTime;
+ DWORD FileAttributes;
+ } info = {0, 0, 0}; /* fields with 0 are unchanged */
+ HANDLE h = (HANDLE)_get_osfhandle(fd);
+
+ if (h == INVALID_HANDLE_VALUE) {
+ errno = EBADF;
+ return -1;
+ }
+ if (set_file_info == (set_file_information_by_handle_func)-1) {
+ set_file_info = (set_file_information_by_handle_func)
+ get_proc_address("kernel32", "SetFileInformationByHandle", NULL);
+ }
+ if (!set_file_info) {
+ errno = ENOSYS;
+ return -1;
+ }
+
+ info.FileAttributes = FILE_ATTRIBUTE_NORMAL;
+ if (!(mode & 0200)) info.FileAttributes |= FILE_ATTRIBUTE_READONLY;
+ if (!set_file_info(h, 0, &info, sizeof(info))) {
+ errno = map_errno(GetLastError());
+ return -1;
+ }
+ return 0;
+}
+
+/* License: Ruby's */
+int
rb_w32_isatty(int fd)
{
DWORD mode;