summaryrefslogtreecommitdiff
path: root/source3/smbd
diff options
context:
space:
mode:
authorJeremy Allison <jra@samba.org>2004-03-03 23:14:23 +0000
committerJeremy Allison <jra@samba.org>2004-03-03 23:14:23 +0000
commitf0039da19654f0d75617e96d67054d1d1990515d (patch)
tree475097adff0ea3a895842d9139eb5df769e9934b /source3/smbd
parentfba5a722497c1e4577aa463921a0fec5f6d5fe55 (diff)
downloadsamba-f0039da19654f0d75617e96d67054d1d1990515d.tar.gz
samba-f0039da19654f0d75617e96d67054d1d1990515d.tar.bz2
samba-f0039da19654f0d75617e96d67054d1d1990515d.zip
Added client "hardlink" commant to test doing NT rename with hard links.
Added hardlink_internals() code - UNIX extensions now use this too. Jeremy. (This used to be commit aad6eb2240393931940c982e25a981ce32264f38)
Diffstat (limited to 'source3/smbd')
-rw-r--r--source3/smbd/nttrans.c9
-rw-r--r--source3/smbd/trans2.c95
2 files changed, 88 insertions, 16 deletions
diff --git a/source3/smbd/nttrans.c b/source3/smbd/nttrans.c
index 9a0063481a..11518c24f7 100644
--- a/source3/smbd/nttrans.c
+++ b/source3/smbd/nttrans.c
@@ -1521,7 +1521,7 @@ int reply_ntrename(connection_struct *conn,
START_PROFILE(SMBntrename);
- if (rename_type != RENAME_FLAG_RENAME) {
+ if ((rename_type != RENAME_FLAG_RENAME) && (rename_type != RENAME_FLAG_HARD_LINK)) {
END_PROFILE(SMBntrename);
return ERROR_NT(NT_STATUS_ACCESS_DENIED);
}
@@ -1551,7 +1551,12 @@ int reply_ntrename(connection_struct *conn,
DEBUG(3,("reply_ntrename : %s -> %s\n",name,newname));
- status = rename_internals(conn, name, newname, attrs, False);
+ if (rename_type == RENAME_FLAG_RENAME) {
+ status = rename_internals(conn, name, newname, attrs, False);
+ } else {
+ status = hardlink_internals(conn, name, newname);
+ }
+
if (!NT_STATUS_IS_OK(status)) {
END_PROFILE(SMBntrename);
return ERROR_NT(status);
diff --git a/source3/smbd/trans2.c b/source3/smbd/trans2.c
index 1d580e6f5b..e2df517f40 100644
--- a/source3/smbd/trans2.c
+++ b/source3/smbd/trans2.c
@@ -2478,6 +2478,82 @@ static int ensure_link_is_safe(connection_struct *conn, const char *link_dest_in
}
/****************************************************************************
+ Set a hard link (called by UNIX extensions and by NT rename with HARD link
+ code.
+****************************************************************************/
+
+NTSTATUS hardlink_internals(connection_struct *conn, char *name, char *newname)
+{
+ BOOL bad_path_src = False;
+ BOOL bad_path_dest = False;
+ SMB_STRUCT_STAT sbuf1, sbuf2;
+ BOOL rc, rcdest;
+ pstring last_component_src;
+ pstring last_component_dest;
+ NTSTATUS status = NT_STATUS_OK;
+
+ ZERO_STRUCT(sbuf1);
+ ZERO_STRUCT(sbuf2);
+
+ /* No wildcards. */
+ if (ms_has_wild(name) || ms_has_wild(newname)) {
+ return NT_STATUS_OBJECT_PATH_SYNTAX_BAD;
+ }
+
+ rc = unix_convert(name,conn,last_component_src,&bad_path_src,&sbuf1);
+ if (!rc && bad_path_src) {
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ /* Quick check for "." and ".." */
+ if (last_component_src[0] == '.') {
+ if (!last_component_src[1] || (last_component_src[1] == '.' && !last_component_src[2])) {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ }
+
+ /* source must already exist. */
+ if (!VALID_STAT(sbuf1)) {
+ return NT_STATUS_OBJECT_NAME_NOT_FOUND;
+ }
+
+ rcdest = unix_convert(newname,conn,last_component_dest,&bad_path_dest,&sbuf2);
+ if (!rcdest && bad_path_dest) {
+ return NT_STATUS_OBJECT_PATH_NOT_FOUND;
+ }
+
+ /* Quick check for "." and ".." */
+ if (last_component_dest[0] == '.') {
+ if (!last_component_dest[1] || (last_component_dest[1] == '.' && !last_component_dest[2])) {
+ return NT_STATUS_OBJECT_NAME_INVALID;
+ }
+ }
+
+ /* Disallow if already exists. */
+ if (VALID_STAT(sbuf2)) {
+ return NT_STATUS_OBJECT_NAME_COLLISION;
+ }
+
+ /* No links from a directory. */
+ if (S_ISDIR(sbuf1.st_mode)) {
+ return NT_STATUS_FILE_IS_A_DIRECTORY;
+ }
+
+ if (ensure_link_is_safe(conn, newname, newname) != 0)
+ return NT_STATUS_ACCESS_DENIED;
+
+ DEBUG(10,("hardlink_internals: doing hard link %s -> %s\n", name, newname ));
+
+ if (SMB_VFS_LINK(conn,name,newname) != 0) {
+ status = map_nt_error_from_unix(errno);
+ DEBUG(3,("hardlink_internals: Error %s link %s -> %s\n",
+ nt_errstr(status), name,newname));
+ }
+
+ return status;
+}
+
+/****************************************************************************
Reply to a TRANS2_SETFILEINFO (set file info by fileid).
****************************************************************************/
@@ -2964,10 +3040,6 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
if (!lp_symlinks(SNUM(conn)))
return(ERROR_DOS(ERRDOS,ERRnoaccess));
- /* Disallow if already exists. */
- if (VALID_STAT(sbuf))
- return(ERROR_DOS(ERRDOS,ERRbadpath));
-
srvstr_get_path(inbuf, link_dest, pdata, sizeof(link_dest), -1, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
@@ -2991,24 +3063,19 @@ size = %.0f, uid = %u, gid = %u, raw perms = 0%o\n",
pstring link_dest;
/* Set a hard link. */
-
- /* Disallow if already exists. */
- if (VALID_STAT(sbuf))
- return(ERROR_DOS(ERRDOS,ERRbadpath));
-
srvstr_get_path(inbuf, link_dest, pdata, sizeof(link_dest), -1, STR_TERMINATE, &status);
if (!NT_STATUS_IS_OK(status)) {
return ERROR_NT(status);
}
- if (ensure_link_is_safe(conn, link_dest, link_dest) != 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
-
DEBUG(10,("call_trans2setfilepathinfo: SMB_SET_FILE_UNIX_LINK doing hard link %s -> %s\n",
fname, link_dest ));
- if (SMB_VFS_LINK(conn,link_dest,fname) != 0)
- return(UNIXERROR(ERRDOS,ERRnoaccess));
+ status = hardlink_internals(conn, fname, link_dest);
+ if (!NT_STATUS_IS_OK(status)) {
+ return ERROR_NT(status);
+ }
+
SSVAL(params,0,0);
send_trans2_replies(outbuf, bufsize, params, 2, *ppdata, 0);
return(-1);