From cdafa35f9dba6eb0073700e3a214348c432a3e84 Mon Sep 17 00:00:00 2001 From: Samba Release Account Date: Mon, 13 Jan 1997 19:41:08 +0000 Subject: [PATCH] Added an extra parameter for unix_convert. If present this is the last component of the modified pathname before modification. This is needed due to an exceptional condition in reply_mv when the filesystem is case preserving, but not case sensitive and the user wants to change the case of a filename. Code for this is also added to reply.c Jeremy (jra@cygnus.com). --- source/include/proto.h | 2 +- source/smbd/pipes.c | 2 +- source/smbd/reply.c | 73 +++++++++++++++++++++++++++++++++++++++----------- source/smbd/server.c | 26 +++++++++++++++--- source/smbd/trans2.c | 10 +++---- 5 files changed, 88 insertions(+), 25 deletions(-) diff --git a/source/include/proto.h b/source/include/proto.h index bbe74e32702..7f6c7d38929 100644 --- a/source/include/proto.h +++ b/source/include/proto.h @@ -662,7 +662,7 @@ int reply_getattrE(char *inbuf,char *outbuf); mode_t unix_mode(int cnum,int dosmode); int dos_mode(int cnum,char *path,struct stat *sbuf); int dos_chmod(int cnum,char *fname,int dosmode,struct stat *st); -BOOL unix_convert(char *name,int cnum); +BOOL unix_convert(char *name,int cnum,char *); int disk_free(char *path,int *bsize,int *dfree,int *dsize); int sys_disk_free(char *path,int *bsize,int *dfree,int *dsize); BOOL check_name(char *name,int cnum); diff --git a/source/smbd/pipes.c b/source/smbd/pipes.c index cb498a61954..efa6a68b9d7 100644 --- a/source/smbd/pipes.c +++ b/source/smbd/pipes.c @@ -114,7 +114,7 @@ int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize) Connections[cnum].read_only = 0; smb_ofun |= 0x10; /* Add Create it not exists flag */ - unix_convert(fname,cnum); + unix_convert(fname,cnum,0); fnum = find_free_file(); if (fnum < 0) diff --git a/source/smbd/reply.c b/source/smbd/reply.c index 812618b2c70..3698787ba46 100644 --- a/source/smbd/reply.c +++ b/source/smbd/reply.c @@ -36,6 +36,7 @@ extern char magic_char; extern connection_struct Connections[]; extern files_struct Files[]; extern BOOL case_sensitive; +extern BOOL case_preserve; extern pstring sesssetup_user; extern int Client; @@ -528,7 +529,7 @@ int reply_chkpth(char *inbuf,char *outbuf) cnum = SVAL(inbuf,smb_tid); strcpy(name,smb_buf(inbuf) + 1); - unix_convert(name,cnum); + unix_convert(name,cnum,0); mode = SVAL(inbuf,smb_vwv0); @@ -563,7 +564,7 @@ int reply_getatr(char *inbuf,char *outbuf) cnum = SVAL(inbuf,smb_tid); strcpy(fname,smb_buf(inbuf) + 1); - unix_convert(fname,cnum); + unix_convert(fname,cnum,0); /* dos smetimes asks for a stat of "" - it returns a "hidden directory" under WfWg - weird! */ @@ -629,7 +630,7 @@ int reply_setatr(char *inbuf,char *outbuf) cnum = SVAL(inbuf,smb_tid); strcpy(fname,smb_buf(inbuf) + 1); - unix_convert(fname,cnum); + unix_convert(fname,cnum,0); mode = SVAL(inbuf,smb_vwv0); mtime = make_unix_date3(inbuf+smb_vwv1); @@ -732,7 +733,7 @@ int reply_search(char *inbuf,char *outbuf) strcpy(directory,smb_buf(inbuf)+1); strcpy(dir2,smb_buf(inbuf)+1); - unix_convert(directory,cnum); + unix_convert(directory,cnum,0); unix_format(dir2); if (!check_name(directory,cnum)) @@ -966,7 +967,7 @@ int reply_open(char *inbuf,char *outbuf) share_mode = SVAL(inbuf,smb_vwv0); strcpy(fname,smb_buf(inbuf)+1); - unix_convert(fname,cnum); + unix_convert(fname,cnum,0); fnum = find_free_file(); if (fnum < 0) @@ -1042,7 +1043,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize) /* XXXX we need to handle passed times, sattr and flags */ strcpy(fname,smb_buf(inbuf)); - unix_convert(fname,cnum); + unix_convert(fname,cnum,0); /* now add create and trunc bits */ if (smb_ofun & 0x10) @@ -1145,7 +1146,7 @@ int reply_mknew(char *inbuf,char *outbuf) createmode = SVAL(inbuf,smb_vwv0); strcpy(fname,smb_buf(inbuf)+1); - unix_convert(fname,cnum); + unix_convert(fname,cnum,0); if (createmode & aVOLID) { @@ -1199,7 +1200,7 @@ int reply_ctemp(char *inbuf,char *outbuf) cnum = SVAL(inbuf,smb_tid); createmode = SVAL(inbuf,smb_vwv0); sprintf(fname,"%s/TMXXXXXX",smb_buf(inbuf)+1); - unix_convert(fname,cnum); + unix_convert(fname,cnum,0); unixmode = unix_mode(cnum,createmode); @@ -1281,7 +1282,7 @@ int reply_unlink(char *inbuf,char *outbuf) DEBUG(3,("reply_unlink : %s\n",name)); - unix_convert(name,cnum); + unix_convert(name,cnum,0); p = strrchr(name,'/'); if (!p) { @@ -2393,7 +2394,7 @@ int reply_mkdir(char *inbuf,char *outbuf) strcpy(directory,smb_buf(inbuf) + 1); cnum = SVAL(inbuf,smb_tid); - unix_convert(directory,cnum); + unix_convert(directory,cnum,0); if (check_name(directory,cnum)) ret = sys_mkdir(directory,unix_mode(cnum,aDIR)); @@ -2421,7 +2422,7 @@ int reply_rmdir(char *inbuf,char *outbuf) cnum = SVAL(inbuf,smb_tid); strcpy(directory,smb_buf(inbuf) + 1); - unix_convert(directory,cnum); + unix_convert(directory,cnum,0); if (check_name(directory,cnum)) { @@ -2532,6 +2533,7 @@ int reply_mv(char *inbuf,char *outbuf) int cnum; pstring directory; pstring mask,newname; + pstring newname_last_component; char *p; int count=0; int error = ERRnoaccess; @@ -2547,8 +2549,8 @@ int reply_mv(char *inbuf,char *outbuf) DEBUG(3,("reply_mv : %s -> %s\n",name,newname)); - unix_convert(name,cnum); - unix_convert(newname,cnum); + unix_convert(name,cnum,0); + unix_convert(newname,cnum,newname_last_component); p = strrchr(name,'/'); if (!p) { @@ -2558,6 +2560,7 @@ int reply_mv(char *inbuf,char *outbuf) *p = 0; strcpy(directory,name); strcpy(mask,p+1); + *p = '/'; /* Replace needed for exceptional test below. */ } if (is_mangled(mask)) @@ -2568,10 +2571,50 @@ int reply_mv(char *inbuf,char *outbuf) if (!has_wild) { strcat(directory,"/"); strcat(directory,mask); + + DEBUG(3,("reply_mv : case_sensitive = %d, case_preserve = %d, name = %s, newname = %s, newname_last_component = %s\n", case_sensitive, case_preserve, name, newname, newname_last_component)); + + /* + * Check for special case with case preserving and not + * case sensitive, if name and newname are identical, + * and the old last component differs from the original + * last component only by case, then we should allow + * the rename (user is trying to change the case of the + * filename). + */ + if((case_sensitive == False) && (case_preserve == True) && + strcsequal(name, newname)) { + pstring newname_modified_last_component; + + /* + * Get the last component of the modified name. + */ + p = strrchr(newname,'/'); + if (!p) + strcpy(newname_modified_last_component,name); + else + strcpy(newname_modified_last_component,p+1); + + if(strcsequal(newname_modified_last_component, + newname_last_component) == False) { + /* + * Replace the modified last component with + * the original. + */ + if(p) + strcpy(p+1, newname_last_component); + else + strcpy(newname, newname_last_component); + } + } + if (resolve_wildcards(directory,newname) && can_rename(directory,cnum) && !file_exist(newname,NULL) && !sys_rename(directory,newname)) count++; + + DEBUG(3,("reply_mv : doing rename on %s -> %s\n",directory,newname)); + if (!count) exists = file_exist(directory,NULL); if (!count && exists && file_exist(newname,NULL)) { exists = True; @@ -2727,8 +2770,8 @@ int reply_copy(char *inbuf,char *outbuf) return(ERROR(ERRSRV,ERRinvdevice)); } - unix_convert(name,cnum); - unix_convert(newname,cnum); + unix_convert(name,cnum,0); + unix_convert(newname,cnum,0); target_is_directory = directory_exist(newname,NULL); diff --git a/source/smbd/server.c b/source/smbd/server.c index 75e7279e6da..623a3fb2bdf 100644 --- a/source/smbd/server.c +++ b/source/smbd/server.c @@ -378,14 +378,21 @@ for this service. The function will return False if some part of the name except for the last part cannot be resolved + +If the saved_last_component != 0, then the unmodified last component +of the pathname is returned there. This is used in an exceptional +case in reply_mv (so far). If saved_last_component == 0 then nothing +is returned there. ****************************************************************************/ -BOOL unix_convert(char *name,int cnum) +BOOL unix_convert(char *name,int cnum,pstring saved_last_component) { struct stat st; char *start, *end; pstring dirpath; *dirpath = 0; + if(saved_last_component) + *saved_last_component = 0; /* convert to basic unix format - removing \ chars and cleaning it up */ unix_format(name); @@ -415,6 +422,17 @@ BOOL unix_convert(char *name,int cnum) return(True); } + /* + * Ensure saved_last_component is valid even if file exists. + */ + if(saved_last_component) { + end = strrchr(name, '/'); + if(end) + strcpy(saved_last_component, end + 1); + else + strcpy(saved_last_component, name); + } + /* stat the name - if it exists then we are all done! */ if (sys_stat(name,&st) == 0) return(True); @@ -442,7 +460,10 @@ BOOL unix_convert(char *name,int cnum) end = strchr(start, '/'); /* chop the name at this point */ - if (end) *end = 0; + if (end) *end = 0; + + if(saved_last_component != 0) + strcpy(saved_last_component, end ? end + 1 : start); /* check if the name exists up to this point */ if (sys_stat(name, &st) == 0) @@ -467,7 +488,6 @@ BOOL unix_convert(char *name,int cnum) later */ if (end) strcpy(rest,end+1); - /* try to find this part of the path in the directory */ if (strchr(start,'?') || strchr(start,'*') || !scan_directory(dirpath, start, SNUM(cnum), end?True:False)) diff --git a/source/smbd/trans2.c b/source/smbd/trans2.c index b2bee17eead..94c4f26359e 100644 --- a/source/smbd/trans2.c +++ b/source/smbd/trans2.c @@ -192,7 +192,7 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum, /* XXXX we need to handle passed times, sattr and flags */ - unix_convert(fname,cnum); + unix_convert(fname,cnum,0); fnum = find_free_file(); if (fnum < 0) @@ -581,7 +581,7 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum DEBUG(5,("path=%s\n",directory)); - unix_convert(directory,cnum); + unix_convert(directory,cnum,0); if(!check_name(directory,cnum)) { return(ERROR(ERRDOS,ERRbadpath)); } @@ -1024,7 +1024,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length, info_level = SVAL(params,0); fname = &fname1[0]; strcpy(fname,¶ms[6]); - unix_convert(fname,cnum); + unix_convert(fname,cnum,0); if (!check_name(fname,cnum) || sys_stat(fname,&sbuf)) { DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno))); return(UNIXERROR(ERRDOS,ERRbadpath)); @@ -1219,7 +1219,7 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length, info_level = SVAL(params,0); fname = fname1; strcpy(fname,¶ms[6]); - unix_convert(fname,cnum); + unix_convert(fname,cnum,0); if(!check_name(fname, cnum)) return(ERROR(ERRDOS,ERRbadpath)); @@ -1353,7 +1353,7 @@ static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize, DEBUG(3,("call_trans2mkdir : name = %s\n", directory)); - unix_convert(directory,cnum); + unix_convert(directory,cnum,0); if (check_name(directory,cnum)) ret = sys_mkdir(directory,unix_mode(cnum,aDIR)); -- 2.11.4.GIT