diff options
author | Corinna Vinschen <corinna@vinschen.de> | 2005-02-19 21:53:36 +0000 |
---|---|---|
committer | Corinna Vinschen <corinna@vinschen.de> | 2005-02-19 21:53:36 +0000 |
commit | 0d75ce965cf46a16585477469bb4edb597a35f00 (patch) | |
tree | 7fbe3e9926fae6373ca21014ebd1e24bf5c8bdb6 /winsup/cygwin/fhandler_disk_file.cc | |
parent | c2d0b9d89a3406e8905efa8fe58f9d948242e028 (diff) | |
download | cygnal-0d75ce965cf46a16585477469bb4edb597a35f00.tar.gz cygnal-0d75ce965cf46a16585477469bb4edb597a35f00.tar.bz2 cygnal-0d75ce965cf46a16585477469bb4edb597a35f00.zip |
* fhandler.h (class fhandler_base): Declare new method link.
(class fhandler_socket): Ditto.
(class fhandler_disk_file): Ditto.
* fhandler.cc (fhandler_base::open): Add FILE_WRITE_ATTRIBUTES
to query_write_control access flags.
(fhandler_base::link): New method.
* fhandler_disk_file.cc (fhandler_disk_file::fchmod): Don't try to
open with O_WRONLY since query_write_control includes
FILE_WRITE_ATTRIBUTES.
(fhandler_disk_file::fchown): Ditto.
(fhandler_disk_file::facl): Ditto.
(fhandler_disk_file::link): New method. Touch st_ctime on successful
link.
* fhandler_socket.cc (fhandler_socket::link): New method.
* syscalls.cc (link): Move functionality into fhandler method link.
Just call this method from here.
Diffstat (limited to 'winsup/cygwin/fhandler_disk_file.cc')
-rw-r--r-- | winsup/cygwin/fhandler_disk_file.cc | 206 |
1 files changed, 179 insertions, 27 deletions
diff --git a/winsup/cygwin/fhandler_disk_file.cc b/winsup/cygwin/fhandler_disk_file.cc index 8644e8964..b77ae82fd 100644 --- a/winsup/cygwin/fhandler_disk_file.cc +++ b/winsup/cygwin/fhandler_disk_file.cc @@ -408,13 +408,9 @@ fhandler_disk_file::fchmod (mode_t mode) enable_restore_privilege (); if (!get_io_handle () && pc.has_acls ()) { - /* Open for writing required to be able to set ctime. */ - if (!(oret = open (O_WRONLY | O_BINARY, 0))) - { - query_open (query_write_control); - if (!(oret = open (O_BINARY, 0))) - return -1; - } + query_open (query_write_control); + if (!(oret = open (O_BINARY, 0))) + return -1; } if (!allow_ntsec && allow_ntea) /* Not necessary when manipulating SD. */ @@ -440,7 +436,7 @@ fhandler_disk_file::fchmod (mode_t mode) res = 0; /* Set ctime on success. */ - if (!res && !query_open ()) + if (!res) has_changed (true); if (oret) @@ -464,13 +460,9 @@ fhandler_disk_file::fchown (__uid32_t uid, __gid32_t gid) enable_restore_privilege (); if (!get_io_handle ()) { - /* Open for writing required to be able to set ctime. */ - if (!(oret = open (O_WRONLY | O_BINARY, 0))) - { - query_open (query_write_control); - if (!(oret = open (O_BINARY, 0))) - return -1; - } + query_open (query_write_control); + if (!(oret = open (O_BINARY, 0))) + return -1; } mode_t attrib = 0; @@ -482,7 +474,7 @@ fhandler_disk_file::fchown (__uid32_t uid, __gid32_t gid) res = set_file_attribute (pc.has_acls (), get_io_handle (), pc, uid, gid, attrib); /* Set ctime on success. */ - if (!res && !query_open ()) + if (!res) has_changed (true); } @@ -556,16 +548,9 @@ fhandler_disk_file::facl (int cmd, int nentries, __aclent32_t *aclbufp) enable_restore_privilege (); if (!get_io_handle ()) { - /* Open for writing required to be able to set ctime. */ - if (cmd == SETACL) - oret = open (O_WRONLY | O_BINARY, 0); - if (!oret) - { - query_open (cmd == SETACL ? query_write_control - : query_read_control); - if (!(oret = open (O_BINARY, 0))) - return -1; - } + query_open (cmd == SETACL ? query_write_control : query_read_control); + if (!(oret = open (O_BINARY, 0))) + return -1; } switch (cmd) { @@ -588,7 +573,7 @@ fhandler_disk_file::facl (int cmd, int nentries, __aclent32_t *aclbufp) } /* Set ctime on success. */ - if (!res && cmd == SETACL && !query_open ()) + if (!res && cmd == SETACL) has_changed (true); if (oret) @@ -645,6 +630,173 @@ fhandler_disk_file::ftruncate (_off64_t length) return res; } +int +fhandler_disk_file::link (const char *newpath) +{ + int res = -1; + path_conv newpc (newpath, PC_SYM_NOFOLLOW | PC_FULL | PC_POSIX); + extern bool allow_winsymlinks; + + if (newpc.error) + { + set_errno (newpc.case_clash ? ECASECLASH : newpc.error); + goto done; + } + + if (newpc.exists ()) + { + syscall_printf ("file '%s' exists?", (char *) newpc); + set_errno (EEXIST); + goto done; + } + + if (newpc[strlen (newpc) - 1] == '.') + { + syscall_printf ("trailing dot, bailing out"); + set_errno (EINVAL); + goto done; + } + + /* Shortcut hack. */ + char new_lnk_buf[CYG_MAX_PATH + 5]; + if (allow_winsymlinks && pc.is_lnk_symlink () && !newpc.case_clash) + { + strcpy (new_lnk_buf, newpath); + strcat (new_lnk_buf, ".lnk"); + newpath = new_lnk_buf; + newpc.check (newpath, PC_SYM_NOFOLLOW | PC_FULL); + } + + query_open (query_write_control); + if (!open (O_BINARY, 0)) + { + syscall_printf ("Opening file failed"); + __seterrno (); + goto done; + } + + /* Try to make hard link first on Windows NT */ + if (wincap.has_hard_links ()) + { + if (CreateHardLinkA (newpc, pc, NULL)) + goto success; + + /* There are two cases to consider: + - The FS doesn't support hard links ==> ERROR_INVALID_FUNCTION + We copy the file. + - CreateHardLinkA is not supported ==> ERROR_PROC_NOT_FOUND + In that case (<= NT4) we try the old-style method. + Any other error should be taken seriously. */ + if (GetLastError () == ERROR_INVALID_FUNCTION) + { + syscall_printf ("FS doesn't support hard links: Copy file"); + goto docopy; + } + if (GetLastError () != ERROR_PROC_NOT_FOUND) + { + syscall_printf ("CreateHardLinkA failed"); + __seterrno (); + close (); + goto done; + } + + WIN32_STREAM_ID stream_id; + DWORD written; + LPVOID context; + DWORD path_len; + DWORD size; + WCHAR wbuf[CYG_MAX_PATH]; + BOOL ret; + DWORD write_err; + + path_len = sys_mbstowcs (wbuf, newpc, CYG_MAX_PATH) * sizeof (WCHAR); + + stream_id.dwStreamId = BACKUP_LINK; + stream_id.dwStreamAttributes = 0; + stream_id.dwStreamNameSize = 0; + stream_id.Size.HighPart = 0; + stream_id.Size.LowPart = path_len; + size = sizeof (WIN32_STREAM_ID) - sizeof (WCHAR**) + + stream_id.dwStreamNameSize; + context = NULL; + write_err = 0; + /* Write WIN32_STREAM_ID */ + ret = BackupWrite (get_handle (), (LPBYTE) &stream_id, size, + &written, FALSE, FALSE, &context); + if (ret) + { + /* write the buffer containing the path */ + /* FIXME: BackupWrite sometimes traps if linkname is invalid. + Need to handle. */ + ret = BackupWrite (get_handle (), (LPBYTE) wbuf, path_len, + &written, FALSE, FALSE, &context); + if (!ret) + { + write_err = GetLastError (); + syscall_printf ("cannot write linkname, %E"); + } + /* Free context */ + BackupWrite (get_handle (), NULL, 0, &written, + TRUE, FALSE, &context); + } + else + { + write_err = GetLastError (); + syscall_printf ("cannot write stream_id, %E"); + } + + if (!ret) + { + /* Only copy file if FS doesn't support hard links */ + if (write_err == ERROR_INVALID_FUNCTION) + { + syscall_printf ("FS doesn't support hard links: Copy file"); + goto docopy; + } + + close (); + __seterrno_from_win_error (write_err); + goto done; + } + + success: + res = 0; + /* touch st_ctime */ + has_changed (true); + close (); + if (!allow_winsymlinks && pc.is_lnk_symlink ()) + SetFileAttributes (newpc, (DWORD) pc + | FILE_ATTRIBUTE_SYSTEM + | FILE_ATTRIBUTE_READONLY); + + goto done; + } +docopy: + /* do this with a copy */ + if (CopyFileA (pc, newpc, 1)) + { + res = 0; + /* touch st_ctime */ + has_changed (true); + close (); + fhandler_disk_file fh; + fh.set_name (newpc); + fh.query_open (query_write_control); + if (fh.open (O_BINARY, 0)) + { + fh.has_changed (true); + fh.close (); + } + } + else + __seterrno (); + +done: + syscall_printf ("%d = link (%s, %s)", res, get_name (), newpath); + return res; +} + + fhandler_disk_file::fhandler_disk_file () : fhandler_base () { |