Changes to allow Samba to return the same error code as Windows NT.
authorSamba Release Account <samba-bugs@samba.org>
Wed, 20 Aug 1997 20:32:23 +0000 (20:32 +0000)
committerSamba Release Account <samba-bugs@samba.org>
Wed, 20 Aug 1997 20:32:23 +0000 (20:32 +0000)
Takes care of the cases where a Windows program is parsing a pathname
component by component and expects 2 different errors.
ERRbadpath - if a component in the path doesn't exist.
ERRbaddirectory - if a component in the path exists but is not a directory.
Extra error code added to smb.h to support this.
Code based on suggestions from "Christian Groessler" <chris@fast-ag.de>.

Jeremy (jallison@whistle.com)

source/include/proto.h
source/include/smb.h
source/lib/util.c
source/smbd/pipes.c
source/smbd/reply.c
source/smbd/server.c
source/smbd/trans2.c

index 56bdbfe8653d74618839e0eb74074111d2806a57..f716c1f9a92eb68c156be935cf107962d9113eeb 100644 (file)
@@ -691,7 +691,7 @@ void  killkids(void);
 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);
 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,pstring saved_last_component);
+BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_path);
 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);
 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);
index 0f2dc018656f0145f63600ae153a0e48d7eb8499..1dbe04abc87f29562653b415ca604b380bd7a7bd 100644 (file)
@@ -175,14 +175,15 @@ implemented */
 #define ERRbadshare 32 /* Share mode on file conflict with open mode */
 #define ERRlock 33 /* Lock request conflicts with existing lock */
 #define ERRfilexists 80 /* File in operation already exists */
 #define ERRbadshare 32 /* Share mode on file conflict with open mode */
 #define ERRlock 33 /* Lock request conflicts with existing lock */
 #define ERRfilexists 80 /* File in operation already exists */
+#define ERRunknownlevel 124
 #define ERRbadpipe 230 /* Named pipe invalid */
 #define ERRpipebusy 231 /* All instances of pipe are busy */
 #define ERRpipeclosing 232 /* named pipe close in progress */
 #define ERRnotconnected 233 /* No process on other end of named pipe */
 #define ERRmoredata 234 /* More data to be returned */
 #define ERRbadpipe 230 /* Named pipe invalid */
 #define ERRpipebusy 231 /* All instances of pipe are busy */
 #define ERRpipeclosing 232 /* named pipe close in progress */
 #define ERRnotconnected 233 /* No process on other end of named pipe */
 #define ERRmoredata 234 /* More data to be returned */
+#define ERRbaddirectory 267 /* Invalid directory name in a path. */
 #define ERROR_EAS_DIDNT_FIT 275 /* Extended attributes didn't fit */
 #define ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not suppored */
 #define ERROR_EAS_DIDNT_FIT 275 /* Extended attributes didn't fit */
 #define ERROR_EAS_NOT_SUPPORTED 282 /* Extended attributes not suppored */
-#define ERRunknownlevel 124
 #define ERRunknownipc 2142
 
 
 #define ERRunknownipc 2142
 
 
@@ -928,4 +929,7 @@ enum case_handling {CASE_LOWER,CASE_UPPER};
 /* Size of buffer to use when moving files across filesystems. */
 #define COPYBUF_SIZE (8*1024)
 
 /* Size of buffer to use when moving files across filesystems. */
 #define COPYBUF_SIZE (8*1024)
 
+/* Integers used to override error codes. */
+extern int unix_ERR_class;
+extern int unix_ERR_code;
 /* _SMB_H */
 /* _SMB_H */
index ca17fbdcb46dcf1531932e7ffda7bd42236e8c80..a048c8b3a7555c67048e7cc252aafc44cce5035f 100644 (file)
@@ -755,12 +755,17 @@ time_t file_modtime(char *fname)
 BOOL directory_exist(char *dname,struct stat *st)
 {
   struct stat st2;
 BOOL directory_exist(char *dname,struct stat *st)
 {
   struct stat st2;
+  BOOL ret;
+
   if (!st) st = &st2;
 
   if (sys_stat(dname,st) != 0) 
     return(False);
 
   if (!st) st = &st2;
 
   if (sys_stat(dname,st) != 0) 
     return(False);
 
-  return(S_ISDIR(st->st_mode));
+  ret = S_ISDIR(st->st_mode);
+  if(!ret)
+    errno = ENOTDIR;
+  return ret;
 }
 
 /*******************************************************************
 }
 
 /*******************************************************************
index a294ee4f4914c5c5b7b77cc9e75e007d1064b8ef..afab7e1d9112627ee2a57227a69f4d591ce03acc 100644 (file)
@@ -84,6 +84,7 @@ int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   struct stat sbuf;
   int smb_action = 0;
   int i;
   struct stat sbuf;
   int smb_action = 0;
   int i;
+  BOOL bad_path = False;
 
   /* XXXX we need to handle passed times, sattr and flags */
   strcpy(fname,smb_buf(inbuf));
 
   /* XXXX we need to handle passed times, sattr and flags */
   strcpy(fname,smb_buf(inbuf));
@@ -114,7 +115,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 */
 
   Connections[cnum].read_only = 0;
   smb_ofun |= 0x10;            /* Add Create it not exists flag */
 
-  unix_convert(fname,cnum,0);
+  unix_convert(fname,cnum,0,&bad_path);
     
   fnum = find_free_file();
   if (fnum < 0)
     
   fnum = find_free_file();
   if (fnum < 0)
@@ -129,7 +130,15 @@ int reply_open_pipe_and_X(char *inbuf,char *outbuf,int length,int bufsize)
                   &rmode,&smb_action);
       
   if (!Files[fnum].open)
                   &rmode,&smb_action);
       
   if (!Files[fnum].open)
+  {
+    /* Change the error code if bad_path was set. */
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
     close_file(fnum);
 
   if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
     close_file(fnum);
index f630e71e25806d35f6d7fe52f109c394ef19e198..cadd63e045728766a9630f80583f3204d6be18a2 100644 (file)
@@ -534,11 +534,12 @@ int reply_chkpth(char *inbuf,char *outbuf)
   int cnum,mode;
   pstring name;
   BOOL ok = False;
   int cnum,mode;
   pstring name;
   BOOL ok = False;
-  
+  BOOL bad_path = False;
   cnum = SVAL(inbuf,smb_tid);
   
   strcpy(name,smb_buf(inbuf) + 1);
   cnum = SVAL(inbuf,smb_tid);
   
   strcpy(name,smb_buf(inbuf) + 1);
-  unix_convert(name,cnum,0);
+  unix_convert(name,cnum,0,&bad_path);
 
   mode = SVAL(inbuf,smb_vwv0);
 
 
   mode = SVAL(inbuf,smb_vwv0);
 
@@ -546,8 +547,20 @@ int reply_chkpth(char *inbuf,char *outbuf)
     ok = directory_exist(name,NULL);
 
   if (!ok)
     ok = directory_exist(name,NULL);
 
   if (!ok)
+  {
+    /* We special case this - as when a Windows machine
+       is parsing a path is steps through the components
+       one at a time - if a component fails it expects
+       ERRbadpath, not ERRbadfile.
+     */
+    if(errno == ENOENT)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRbadpath));
     return(UNIXERROR(ERRDOS,ERRbadpath));
-  
+  }
   outsize = set_message(outbuf,0,0,True);
   
   DEBUG(3,("%s chkpth %s cnum=%d mode=%d\n",timestring(),name,cnum,mode));
   outsize = set_message(outbuf,0,0,True);
   
   DEBUG(3,("%s chkpth %s cnum=%d mode=%d\n",timestring(),name,cnum,mode));
@@ -569,11 +582,12 @@ int reply_getatr(char *inbuf,char *outbuf)
   int mode=0;
   uint32 size=0;
   time_t mtime=0;
   int mode=0;
   uint32 size=0;
   time_t mtime=0;
-  
+  BOOL bad_path = False;
   cnum = SVAL(inbuf,smb_tid);
 
   strcpy(fname,smb_buf(inbuf) + 1);
   cnum = SVAL(inbuf,smb_tid);
 
   strcpy(fname,smb_buf(inbuf) + 1);
-  unix_convert(fname,cnum,0);
+  unix_convert(fname,cnum,0,&bad_path);
 
   /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
      under WfWg - weird! */
 
   /* dos smetimes asks for a stat of "" - it returns a "hidden directory"
      under WfWg - weird! */
@@ -587,23 +601,31 @@ int reply_getatr(char *inbuf,char *outbuf)
     }
   else
     if (check_name(fname,cnum))
     }
   else
     if (check_name(fname,cnum))
+    {
+      if (sys_stat(fname,&sbuf) == 0)
       {
       {
-       if (sys_stat(fname,&sbuf) == 0)
-         {
-           mode = dos_mode(cnum,fname,&sbuf);
-           size = sbuf.st_size;
-           mtime = sbuf.st_mtime;
-           if (mode & aDIR)
-             size = 0;
-           ok = True;
-         }
-       else
-         DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
+        mode = dos_mode(cnum,fname,&sbuf);
+        size = sbuf.st_size;
+        mtime = sbuf.st_mtime;
+        if (mode & aDIR)
+          size = 0;
+        ok = True;
+      }
+      else
+        DEBUG(3,("stat of %s failed (%s)\n",fname,strerror(errno)));
     }
   
   if (!ok)
     }
   
   if (!ok)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
+
     return(UNIXERROR(ERRDOS,ERRbadfile));
     return(UNIXERROR(ERRDOS,ERRbadfile));
-  
+  }
   outsize = set_message(outbuf,10,0,True);
 
   SSVAL(outbuf,smb_vwv0,mode);
   outsize = set_message(outbuf,10,0,True);
 
   SSVAL(outbuf,smb_vwv0,mode);
@@ -635,11 +657,12 @@ int reply_setatr(char *inbuf,char *outbuf)
   BOOL ok=False;
   int mode;
   time_t mtime;
   BOOL ok=False;
   int mode;
   time_t mtime;
-  
+  BOOL bad_path = False;
   cnum = SVAL(inbuf,smb_tid);
   
   strcpy(fname,smb_buf(inbuf) + 1);
   cnum = SVAL(inbuf,smb_tid);
   
   strcpy(fname,smb_buf(inbuf) + 1);
-  unix_convert(fname,cnum,0);
+  unix_convert(fname,cnum,0,&bad_path);
 
   mode = SVAL(inbuf,smb_vwv0);
   mtime = make_unix_date3(inbuf+smb_vwv1);
 
   mode = SVAL(inbuf,smb_vwv0);
   mtime = make_unix_date3(inbuf+smb_vwv1);
@@ -652,8 +675,16 @@ int reply_setatr(char *inbuf,char *outbuf)
     ok = set_filetime(fname,mtime);
   
   if (!ok)
     ok = set_filetime(fname,mtime);
   
   if (!ok)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
+
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
-  
+  }
   outsize = set_message(outbuf,0,0,True);
   
   DEBUG(3,("%s setatr name=%s mode=%d\n",timestring(),fname,mode));
   outsize = set_message(outbuf,0,0,True);
   
   DEBUG(3,("%s setatr name=%s mode=%d\n",timestring(),fname,mode));
@@ -715,6 +746,7 @@ int reply_search(char *inbuf,char *outbuf)
   BOOL check_descend = False;
   BOOL expect_close = False;
   BOOL can_open = True;
   BOOL check_descend = False;
   BOOL expect_close = False;
   BOOL can_open = True;
+  BOOL bad_path = False;
 
   *mask = *directory = *fname = 0;
 
 
   *mask = *directory = *fname = 0;
 
@@ -742,26 +774,32 @@ int reply_search(char *inbuf,char *outbuf)
 
       strcpy(directory,smb_buf(inbuf)+1);
       strcpy(dir2,smb_buf(inbuf)+1);
 
       strcpy(directory,smb_buf(inbuf)+1);
       strcpy(dir2,smb_buf(inbuf)+1);
-      unix_convert(directory,cnum,0);
+      unix_convert(directory,cnum,0,&bad_path);
       unix_format(dir2);
 
       if (!check_name(directory,cnum))
       unix_format(dir2);
 
       if (!check_name(directory,cnum))
-       can_open = False;
+        can_open = False;
 
       p = strrchr(dir2,'/');
       if (p == NULL) 
 
       p = strrchr(dir2,'/');
       if (p == NULL) 
-       {strcpy(mask,dir2);*dir2 = 0;}
+      {
+        strcpy(mask,dir2);
+        *dir2 = 0;
+      }
       else
       else
-       {*p = 0;strcpy(mask,p+1);}
+      {
+        *p = 0;
+        strcpy(mask,p+1);
+      }
 
       p = strrchr(directory,'/');
       if (!p) 
 
       p = strrchr(directory,'/');
       if (!p) 
-       *directory = 0;
+        *directory = 0;
       else
       else
-       *p = 0;
+        *p = 0;
 
       if (strlen(directory) == 0)
 
       if (strlen(directory) == 0)
-       strcpy(directory,"./");
+        strcpy(directory,"./");
       bzero(status,21);
       CVAL(status,0) = dirtype;
     }
       bzero(status,21);
       CVAL(status,0) = dirtype;
     }
@@ -827,7 +865,14 @@ int reply_search(char *inbuf,char *outbuf)
          if (dptr_num < 0)
         {
           if(dptr_num == -2)
          if (dptr_num < 0)
         {
           if(dptr_num == -2)
+          {
+            if((errno == ENOENT) && bad_path)
+            {
+              unix_ERR_class = ERRDOS;
+              unix_ERR_code = ERRbadpath;
+            }
             return (UNIXERROR(ERRDOS,ERRnofids));
             return (UNIXERROR(ERRDOS,ERRnofids));
+          }
           return(ERROR(ERRDOS,ERRnofids));
         }
        }
           return(ERROR(ERRDOS,ERRnofids));
         }
        }
@@ -974,27 +1019,42 @@ int reply_open(char *inbuf,char *outbuf)
   int unixmode;
   int rmode=0;
   struct stat sbuf;
   int unixmode;
   int rmode=0;
   struct stat sbuf;
-  
+  BOOL bad_path = False;
   cnum = SVAL(inbuf,smb_tid);
 
   share_mode = SVAL(inbuf,smb_vwv0);
 
   strcpy(fname,smb_buf(inbuf)+1);
   cnum = SVAL(inbuf,smb_tid);
 
   share_mode = SVAL(inbuf,smb_vwv0);
 
   strcpy(fname,smb_buf(inbuf)+1);
-  unix_convert(fname,cnum,0);
+  unix_convert(fname,cnum,0,&bad_path);
     
   fnum = find_free_file();
   if (fnum < 0)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
     
   fnum = find_free_file();
   if (fnum < 0)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
-  
+  }
   unixmode = unix_mode(cnum,aARCH);
       
   open_file_shared(fnum,cnum,fname,share_mode,3,unixmode,&rmode,NULL);
 
   if (!Files[fnum].open)
   unixmode = unix_mode(cnum,aARCH);
       
   open_file_shared(fnum,cnum,fname,share_mode,3,unixmode,&rmode,NULL);
 
   if (!Files[fnum].open)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
     close_file(fnum);
 
   if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
     close_file(fnum);
@@ -1047,6 +1107,7 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
   int size=0,fmode=0,mtime=0,rmode=0;
   struct stat sbuf;
   int smb_action = 0;
   int size=0,fmode=0,mtime=0,rmode=0;
   struct stat sbuf;
   int smb_action = 0;
+  BOOL bad_path = False;
 
   /* If it's an IPC, pass off the pipe handler. */
   if (IS_IPC(cnum))
 
   /* If it's an IPC, pass off the pipe handler. */
   if (IS_IPC(cnum))
@@ -1055,14 +1116,21 @@ 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));
   /* XXXX we need to handle passed times, sattr and flags */
 
   strcpy(fname,smb_buf(inbuf));
-  unix_convert(fname,cnum,0);
+  unix_convert(fname,cnum,0,&bad_path);
     
   fnum = find_free_file();
   if (fnum < 0)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
     
   fnum = find_free_file();
   if (fnum < 0)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   unixmode = unix_mode(cnum,smb_attr | aARCH);
       
 
   unixmode = unix_mode(cnum,smb_attr | aARCH);
       
@@ -1070,7 +1138,14 @@ int reply_open_and_X(char *inbuf,char *outbuf,int length,int bufsize)
                   &rmode,&smb_action);
       
   if (!Files[fnum].open)
                   &rmode,&smb_action);
       
   if (!Files[fnum].open)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
     close_file(fnum);
 
   if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
     close_file(fnum);
@@ -1147,13 +1222,14 @@ int reply_mknew(char *inbuf,char *outbuf)
   int createmode;
   mode_t unixmode;
   int ofun = 0;
   int createmode;
   mode_t unixmode;
   int ofun = 0;
+  BOOL bad_path = False;
  
   com = SVAL(inbuf,smb_com);
   cnum = SVAL(inbuf,smb_tid);
 
   createmode = SVAL(inbuf,smb_vwv0);
   strcpy(fname,smb_buf(inbuf)+1);
  
   com = SVAL(inbuf,smb_com);
   cnum = SVAL(inbuf,smb_tid);
 
   createmode = SVAL(inbuf,smb_vwv0);
   strcpy(fname,smb_buf(inbuf)+1);
-  unix_convert(fname,cnum,0);
+  unix_convert(fname,cnum,0,&bad_path);
 
   if (createmode & aVOLID)
     {
 
   if (createmode & aVOLID)
     {
@@ -1167,7 +1243,14 @@ int reply_mknew(char *inbuf,char *outbuf)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   if(com == SMBmknew)
   {
 
   if(com == SMBmknew)
   {
@@ -1184,8 +1267,15 @@ int reply_mknew(char *inbuf,char *outbuf)
   open_file_shared(fnum,cnum,fname,(DENY_FCB<<4)|0xF, ofun, unixmode, NULL, NULL);
   
   if (!Files[fnum].open)
   open_file_shared(fnum,cnum,fname,(DENY_FCB<<4)|0xF, ofun, unixmode, NULL, NULL);
   
   if (!Files[fnum].open)
+  {
+    if((errno == ENOENT) && bad_path) 
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
-  
+  }
   outsize = set_message(outbuf,1,0,True);
   SSVAL(outbuf,smb_vwv0,fnum);
 
   outsize = set_message(outbuf,1,0,True);
   SSVAL(outbuf,smb_vwv0,fnum);
 
@@ -1212,11 +1302,12 @@ int reply_ctemp(char *inbuf,char *outbuf)
   int outsize = 0;
   int createmode;
   mode_t unixmode;
   int outsize = 0;
   int createmode;
   mode_t unixmode;
-  
+  BOOL bad_path = False;
   cnum = SVAL(inbuf,smb_tid);
   createmode = SVAL(inbuf,smb_vwv0);
   sprintf(fname,"%s/TMXXXXXX",smb_buf(inbuf)+1);
   cnum = SVAL(inbuf,smb_tid);
   createmode = SVAL(inbuf,smb_vwv0);
   sprintf(fname,"%s/TMXXXXXX",smb_buf(inbuf)+1);
-  unix_convert(fname,cnum,0);
+  unix_convert(fname,cnum,0,&bad_path);
   
   unixmode = unix_mode(cnum,createmode);
   
   
   unixmode = unix_mode(cnum,createmode);
   
@@ -1225,7 +1316,14 @@ int reply_ctemp(char *inbuf,char *outbuf)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   strcpy(fname2,(char *)mktemp(fname));
 
 
   strcpy(fname2,(char *)mktemp(fname));
 
@@ -1234,7 +1332,14 @@ int reply_ctemp(char *inbuf,char *outbuf)
   open_file_shared(fnum,cnum,fname2,(DENY_FCB<<4)|0xF, 0x10, unixmode, NULL, NULL);
 
   if (!Files[fnum].open)
   open_file_shared(fnum,cnum,fname2,(DENY_FCB<<4)|0xF, 0x10, unixmode, NULL, NULL);
 
   if (!Files[fnum].open)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   outsize = set_message(outbuf,1,2 + strlen(fname2),True);
   SSVAL(outbuf,smb_vwv0,fnum);
 
   outsize = set_message(outbuf,1,2 + strlen(fname2),True);
   SSVAL(outbuf,smb_vwv0,fnum);
@@ -1290,6 +1395,7 @@ int reply_unlink(char *inbuf,char *outbuf)
   int error = ERRnoaccess;
   BOOL has_wild;
   BOOL exists=False;
   int error = ERRnoaccess;
   BOOL has_wild;
   BOOL exists=False;
+  BOOL bad_path = False;
 
   *directory = *mask = 0;
 
 
   *directory = *mask = 0;
 
@@ -1300,7 +1406,7 @@ int reply_unlink(char *inbuf,char *outbuf)
    
   DEBUG(3,("reply_unlink : %s\n",name));
    
    
   DEBUG(3,("reply_unlink : %s\n",name));
    
-  unix_convert(name,cnum,0);
+  unix_convert(name,cnum,0,&bad_path);
 
   p = strrchr(name,'/');
   if (!p) {
 
   p = strrchr(name,'/');
   if (!p) {
@@ -1362,7 +1468,14 @@ int reply_unlink(char *inbuf,char *outbuf)
     if (exists)
       return(ERROR(ERRDOS,error));
     else
     if (exists)
       return(ERROR(ERRDOS,error));
     else
+    {
+      if((errno == ENOENT) && bad_path)
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
       return(UNIXERROR(ERRDOS,error));
       return(UNIXERROR(ERRDOS,error));
+    }
   }
   
   outsize = set_message(outbuf,0,0,True);
   }
   
   outsize = set_message(outbuf,0,0,True);
@@ -2415,17 +2528,25 @@ int reply_mkdir(char *inbuf,char *outbuf)
   pstring directory;
   int cnum;
   int outsize,ret= -1;
   pstring directory;
   int cnum;
   int outsize,ret= -1;
-  
+  BOOL bad_path = False;
   strcpy(directory,smb_buf(inbuf) + 1);
   cnum = SVAL(inbuf,smb_tid);
   strcpy(directory,smb_buf(inbuf) + 1);
   cnum = SVAL(inbuf,smb_tid);
-  unix_convert(directory,cnum,0);
+  unix_convert(directory,cnum,0,&bad_path);
   
   if (check_name(directory,cnum))
     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
   
   if (ret < 0)
   
   if (check_name(directory,cnum))
     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
   
   if (ret < 0)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
-  
+  }
   outsize = set_message(outbuf,0,0,True);
   
   DEBUG(3,("%s mkdir %s cnum=%d ret=%d\n",timestring(),directory,cnum,ret));
   outsize = set_message(outbuf,0,0,True);
   
   DEBUG(3,("%s mkdir %s cnum=%d ret=%d\n",timestring(),directory,cnum,ret));
@@ -2443,10 +2564,11 @@ int reply_rmdir(char *inbuf,char *outbuf)
   int cnum;
   int outsize = 0;
   BOOL ok = False;
   int cnum;
   int outsize = 0;
   BOOL ok = False;
-  
+  BOOL bad_path = False;
+
   cnum = SVAL(inbuf,smb_tid);
   strcpy(directory,smb_buf(inbuf) + 1);
   cnum = SVAL(inbuf,smb_tid);
   strcpy(directory,smb_buf(inbuf) + 1);
-  unix_convert(directory,cnum,0);
+  unix_convert(directory,cnum,0,&bad_path);
   
   if (check_name(directory,cnum))
     {
   
   if (check_name(directory,cnum))
     {
@@ -2524,8 +2646,15 @@ int reply_rmdir(char *inbuf,char *outbuf)
     }
   
   if (!ok)
     }
   
   if (!ok)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRbadpath));
     return(UNIXERROR(ERRDOS,ERRbadpath));
-  
+  }
   outsize = set_message(outbuf,0,0,True);
   
   DEBUG(3,("%s rmdir %s\n",timestring(),directory));
   outsize = set_message(outbuf,0,0,True);
   
   DEBUG(3,("%s rmdir %s\n",timestring(),directory));
@@ -2629,6 +2758,8 @@ int reply_mv(char *inbuf,char *outbuf)
   int error = ERRnoaccess;
   BOOL has_wild;
   BOOL exists=False;
   int error = ERRnoaccess;
   BOOL has_wild;
   BOOL exists=False;
+  BOOL bad_path1 = False;
+  BOOL bad_path2 = False;
 
   *directory = *mask = 0;
 
 
   *directory = *mask = 0;
 
@@ -2639,8 +2770,8 @@ int reply_mv(char *inbuf,char *outbuf)
    
   DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
    
    
   DEBUG(3,("reply_mv : %s -> %s\n",name,newname));
    
-  unix_convert(name,cnum,0);
-  unix_convert(newname,cnum,newname_last_component);
+  unix_convert(name,cnum,0,&bad_path1);
+  unix_convert(newname,cnum,newname_last_component,&bad_path2);
 
   /*
    * Split the old name into directory and last component
 
   /*
    * Split the old name into directory and last component
@@ -2775,7 +2906,14 @@ int reply_mv(char *inbuf,char *outbuf)
     if (exists)
       return(ERROR(ERRDOS,error));
     else
     if (exists)
       return(ERROR(ERRDOS,error));
     else
+    {
+      if((errno == ENOENT) && (bad_path1 || bad_path2))
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
       return(UNIXERROR(ERRDOS,error));
       return(UNIXERROR(ERRDOS,error));
+    }
   }
   
   outsize = set_message(outbuf,0,0,True);
   }
   
   outsize = set_message(outbuf,0,0,True);
@@ -2865,6 +3003,8 @@ int reply_copy(char *inbuf,char *outbuf)
   int ofun = SVAL(inbuf,smb_vwv1);
   int flags = SVAL(inbuf,smb_vwv2);
   BOOL target_is_directory=False;
   int ofun = SVAL(inbuf,smb_vwv1);
   int flags = SVAL(inbuf,smb_vwv2);
   BOOL target_is_directory=False;
+  BOOL bad_path1 = False;
+  BOOL bad_path2 = False;
 
   *directory = *mask = 0;
 
 
   *directory = *mask = 0;
 
@@ -2881,8 +3021,8 @@ int reply_copy(char *inbuf,char *outbuf)
     return(ERROR(ERRSRV,ERRinvdevice));
   }
 
     return(ERROR(ERRSRV,ERRinvdevice));
   }
 
-  unix_convert(name,cnum,0);
-  unix_convert(newname,cnum,0);
+  unix_convert(name,cnum,0,&bad_path1);
+  unix_convert(newname,cnum,0,&bad_path2);
 
   target_is_directory = directory_exist(newname,NULL);
 
 
   target_is_directory = directory_exist(newname,NULL);
 
@@ -2960,7 +3100,14 @@ int reply_copy(char *inbuf,char *outbuf)
     if (exists)
       return(ERROR(ERRDOS,error));
     else
     if (exists)
       return(ERROR(ERRDOS,error));
     else
+    {
+      if((errno == ENOENT) && (bad_path1 || bad_path2))
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
       return(UNIXERROR(ERRDOS,error));
       return(UNIXERROR(ERRDOS,error));
+    }
   }
   
   outsize = set_message(outbuf,1,0,True);
   }
   
   outsize = set_message(outbuf,1,0,True);
index 93d05ffab6415f32037c744c64f3920f392a4197..aaf62fdcad94f802793cb37fca95f92f33fef91c 100644 (file)
@@ -426,14 +426,22 @@ 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.
 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.
+
+The bad_path arg is set to True if the filename walk failed. This is
+used to pick the correct error code to return between ENOENT and ENOTDIR
+as Windows applications depend on ERRbadpath being returned if a component
+of a pathname does not exist.
 ****************************************************************************/
 ****************************************************************************/
-BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
+BOOL unix_convert(char *name,int cnum,pstring saved_last_component, BOOL *bad_path)
 {
   struct stat st;
   char *start, *end;
   pstring dirpath;
 {
   struct stat st;
   char *start, *end;
   pstring dirpath;
+  int saved_errno;
 
   *dirpath = 0;
 
   *dirpath = 0;
+  *bad_path = False;
+
   if(saved_last_component)
     *saved_last_component = 0;
 
   if(saved_last_component)
     *saved_last_component = 0;
 
@@ -480,12 +488,14 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
   if (sys_stat(name,&st) == 0)
     return(True);
 
   if (sys_stat(name,&st) == 0)
     return(True);
 
+  saved_errno = errno;
+
   DEBUG(5,("unix_convert(%s,%d)\n",name,cnum));
 
   /* a special case - if we don't have any mangling chars and are case
      sensitive then searching won't help */
   if (case_sensitive && !is_mangled(name) && 
   DEBUG(5,("unix_convert(%s,%d)\n",name,cnum));
 
   /* a special case - if we don't have any mangling chars and are case
      sensitive then searching won't help */
   if (case_sensitive && !is_mangled(name) && 
-      !lp_strip_dot() && !use_mangled_map)
+      !lp_strip_dot() && !use_mangled_map && (saved_errno != ENOENT))
     return(False);
 
   /* now we need to recursively match the name against the real 
     return(False);
 
   /* now we need to recursively match the name against the real 
@@ -506,7 +516,7 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
       if (end)         *end = 0;
 
       if(saved_last_component != 0)
       if (end)         *end = 0;
 
       if(saved_last_component != 0)
-       strcpy(saved_last_component, end ? end + 1 : start);
+        strcpy(saved_last_component, end ? end + 1 : start);
 
       /* check if the name exists up to this point */
       if (sys_stat(name, &st) == 0) 
 
       /* check if the name exists up to this point */
       if (sys_stat(name, &st) == 0) 
@@ -540,6 +550,13 @@ BOOL unix_convert(char *name,int cnum,pstring saved_last_component)
                  /* an intermediate part of the name can't be found */
                  DEBUG(5,("Intermediate not found %s\n",start));
                  *end = '/';
                  /* an intermediate part of the name can't be found */
                  DEBUG(5,("Intermediate not found %s\n",start));
                  *end = '/';
+                  /* We need to return the fact that the intermediate
+                     name resolution failed. This is used to return an
+                     error of ERRbadpath rather than ERRbadfile. Some
+                     Windows applications depend on the difference between
+                     these two errors.
+                   */
+                  *bad_path = True;
                  return(False);
                }
              
                  return(False);
                }
              
@@ -1940,7 +1957,7 @@ struct
   {EPERM,ERRDOS,ERRnoaccess},
   {EACCES,ERRDOS,ERRnoaccess},
   {ENOENT,ERRDOS,ERRbadfile},
   {EPERM,ERRDOS,ERRnoaccess},
   {EACCES,ERRDOS,ERRnoaccess},
   {ENOENT,ERRDOS,ERRbadfile},
-  {ENOTDIR,ERRDOS,ERRbadpath},
+  {ENOTDIR,ERRDOS,ERRbaddirectory},
   {EIO,ERRHRD,ERRgeneral},
   {EBADF,ERRSRV,ERRsrverror},
   {EINVAL,ERRSRV,ERRsrverror},
   {EIO,ERRHRD,ERRgeneral},
   {EBADF,ERRSRV,ERRsrverror},
   {EINVAL,ERRSRV,ERRsrverror},
index e7fd6824abd2162a302f335a90cc128a68b7700e..9a48fb3ded20b72f6e46c10b63d42576537cee2d 100644 (file)
@@ -184,6 +184,7 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
   int32 inode = 0;
   struct stat sbuf;
   int smb_action = 0;
   int32 inode = 0;
   struct stat sbuf;
   int smb_action = 0;
+  BOOL bad_path = False;
 
   StrnCpy(fname,pname,namelen);
 
 
   StrnCpy(fname,pname,namelen);
 
@@ -192,14 +193,21 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
 
   /* XXXX we need to handle passed times, sattr and flags */
 
 
   /* XXXX we need to handle passed times, sattr and flags */
 
-  unix_convert(fname,cnum,0);
+  unix_convert(fname,cnum,0,&bad_path);
     
   fnum = find_free_file();
   if (fnum < 0)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
     
   fnum = find_free_file();
   if (fnum < 0)
     return(ERROR(ERRSRV,ERRnofids));
 
   if (!check_name(fname,cnum))
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   unixmode = unix_mode(cnum,open_attr | aARCH);
       
 
   unixmode = unix_mode(cnum,open_attr | aARCH);
       
@@ -208,7 +216,14 @@ static int call_trans2open(char *inbuf, char *outbuf, int bufsize, int cnum,
                   &rmode,&smb_action);
       
   if (!Files[fnum].open)
                   &rmode,&smb_action);
       
   if (!Files[fnum].open)
+  {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(UNIXERROR(ERRDOS,ERRnoaccess));
     return(UNIXERROR(ERRDOS,ERRnoaccess));
+  }
 
   if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
     close_file(fnum);
 
   if (fstat(Files[fnum].fd_ptr->fd,&sbuf) != 0) {
     close_file(fnum);
@@ -559,6 +574,7 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
   BOOL dont_descend = False;
   BOOL out_of_space = False;
   int space_remaining;
   BOOL dont_descend = False;
   BOOL out_of_space = False;
   int space_remaining;
+  BOOL bad_path = False;
 
   *directory = *mask = 0;
 
 
   *directory = *mask = 0;
 
@@ -586,8 +602,13 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
 
   DEBUG(5,("path=%s\n",directory));
 
 
   DEBUG(5,("path=%s\n",directory));
 
-  unix_convert(directory,cnum,0);
+  unix_convert(directory,cnum,0,&bad_path);
   if(!check_name(directory,cnum)) {
   if(!check_name(directory,cnum)) {
+    if((errno == ENOENT) && bad_path)
+    {
+      unix_ERR_class = ERRDOS;
+      unix_ERR_code = ERRbadpath;
+    }
     return(ERROR(ERRDOS,ERRbadpath));
   }
 
     return(ERROR(ERRDOS,ERRbadpath));
   }
 
@@ -616,7 +637,14 @@ static int call_trans2findfirst(char *inbuf, char *outbuf, int bufsize, int cnum
   if (dptr_num < 0)
     {
       if(dptr_num == -2)
   if (dptr_num < 0)
     {
       if(dptr_num == -2)
+      {
+        if((errno == ENOENT) && bad_path)
+        {
+          unix_ERR_class = ERRDOS;
+          unix_ERR_code = ERRbadpath;
+        }
         return (UNIXERROR(ERRDOS,ERRbadpath));
         return (UNIXERROR(ERRDOS,ERRbadpath));
+      }
       return(ERROR(ERRDOS,ERRbadpath));
     }
 
       return(ERROR(ERRDOS,ERRbadpath));
     }
 
@@ -1012,7 +1040,7 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
   char *fname;
   char *p;
   int l,pos;
   char *fname;
   char *p;
   int l,pos;
-
+  BOOL bad_path = False;
 
   if (tran_call == TRANSACT2_QFILEINFO) {
     int16 fnum = SVALS(params,0);
 
   if (tran_call == TRANSACT2_QFILEINFO) {
     int16 fnum = SVALS(params,0);
@@ -1032,9 +1060,14 @@ static int call_trans2qfilepathinfo(char *inbuf, char *outbuf, int length,
     info_level = SVAL(params,0);
     fname = &fname1[0];
     strcpy(fname,&params[6]);
     info_level = SVAL(params,0);
     fname = &fname1[0];
     strcpy(fname,&params[6]);
-    unix_convert(fname,cnum,0);
+    unix_convert(fname,cnum,0,&bad_path);
     if (!check_name(fname,cnum) || sys_stat(fname,&sbuf)) {
       DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
     if (!check_name(fname,cnum) || sys_stat(fname,&sbuf)) {
       DEBUG(3,("fileinfo of %s failed (%s)\n",fname,strerror(errno)));
+      if((errno == ENOENT) && bad_path)
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
       return(UNIXERROR(ERRDOS,ERRbadpath));
     }
     pos = 0;
       return(UNIXERROR(ERRDOS,ERRbadpath));
     }
     pos = 0;
@@ -1212,6 +1245,7 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
   pstring fname1;
   char *fname;
   int fd = -1;
   pstring fname1;
   char *fname;
   int fd = -1;
+  BOOL bad_path = False;
 
   if (!CAN_WRITE(cnum))
     return(ERROR(ERRSRV,ERRaccess));
 
   if (!CAN_WRITE(cnum))
     return(ERROR(ERRSRV,ERRaccess));
@@ -1235,13 +1269,25 @@ static int call_trans2setfilepathinfo(char *inbuf, char *outbuf, int length,
     info_level = SVAL(params,0);    
     fname = fname1;
     strcpy(fname,&params[6]);
     info_level = SVAL(params,0);    
     fname = fname1;
     strcpy(fname,&params[6]);
-    unix_convert(fname,cnum,0);
+    unix_convert(fname,cnum,0,&bad_path);
     if(!check_name(fname, cnum))
     if(!check_name(fname, cnum))
-      return(ERROR(ERRDOS,ERRbadpath));
-    
+    {
+      if((errno == ENOENT) && bad_path)
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
+      return(UNIXERROR(ERRDOS,ERRbadpath));
+    }
     if(sys_stat(fname,&st)!=0) {
       DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
     if(sys_stat(fname,&st)!=0) {
       DEBUG(3,("stat of %s failed (%s)\n", fname, strerror(errno)));
-      return(ERROR(ERRDOS,ERRbadpath));
+      if((errno == ENOENT) && bad_path)
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
+      return(UNIXERROR(ERRDOS,ERRbadpath));
     }    
   }
 
     }    
   }
 
@@ -1396,6 +1442,7 @@ static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
   char *params = *pparams;
   pstring directory;
   int ret = -1;
   char *params = *pparams;
   pstring directory;
   int ret = -1;
+  BOOL bad_path = False;
 
   if (!CAN_WRITE(cnum))
     return(ERROR(ERRSRV,ERRaccess));
 
   if (!CAN_WRITE(cnum))
     return(ERROR(ERRSRV,ERRaccess));
@@ -1404,13 +1451,18 @@ static int call_trans2mkdir(char *inbuf, char *outbuf, int length, int bufsize,
 
   DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
 
 
   DEBUG(3,("call_trans2mkdir : name = %s\n", directory));
 
-  unix_convert(directory,cnum,0);
+  unix_convert(directory,cnum,0,&bad_path);
   if (check_name(directory,cnum))
     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
   
   if(ret < 0)
     {
       DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
   if (check_name(directory,cnum))
     ret = sys_mkdir(directory,unix_mode(cnum,aDIR));
   
   if(ret < 0)
     {
       DEBUG(5,("call_trans2mkdir error (%s)\n", strerror(errno)));
+      if((errno == ENOENT) && bad_path)
+      {
+        unix_ERR_class = ERRDOS;
+        unix_ERR_code = ERRbadpath;
+      }
       return(UNIXERROR(ERRDOS,ERRnoaccess));
     }
 
       return(UNIXERROR(ERRDOS,ERRnoaccess));
     }