s3: Differentiate between posix files with colons and actual streams
authorTim Prouty <tprouty@samba.org>
Sat, 3 Jan 2009 01:35:04 +0000 (17:35 -0800)
committerTim Prouty <tprouty@samba.org>
Mon, 12 Jan 2009 06:13:37 +0000 (22:13 -0800)
It is possible for a posix file created locally or over nfs to have a
":" in the name.  Since ":" is a reserved character in windows,
filenames containing a colon must be mangled in a directory listing.
Right now files containing colons will not even be displayed in
directory listings if streams modules are in use.  During the
directory listing the file will be detected as a stream because of the
colon, but the streams module will fail to find the stream since it
doesn't exist.  This fix adds a step to is_ntfs_stream_name that stats
the filename to differentiate between actual streams and files
containing colons.

While this is an improvement, it isn't perfect. Consider the case
where there is a file on disk called "a.txt:s1" and also a file called
"a.txt" that has a stream called "s1".  This patch will always
preference "a.txt:s1" over a.txt's s1 stream.

The real issue is that at the vfs level, the vfs modules have no way
to tell between a demangled name with a colon and an actual stream.  A
more invasive, but better, long-term fix would be to add all paths
that come over the wire into a struct containing metadata about the
path.  This metadata could include a flag to indicate whether the path
came over the wire with a colon ":" (guaranteeing that the client is
requesting a stream). Passing this struct down to the lower levels,
including all path-based vfs calls, would allow the above case to be
handled correctly in all cases.

source3/smbd/nttrans.c

index f1423c028e1b3cf08507ba922714e0b64b8a0ac8..63b4776fbc29fbb401993fcb66be250b439214ee 100644 (file)
@@ -259,14 +259,46 @@ void send_nt_replies(connection_struct *conn,
  An NTFS file name is <path>.<extention>:<stream name>:<stream type>
  $DATA can be used as both a stream name and a stream type. A missing stream
  name or type implies $DATA.
+
+ Both Windows stream names and POSIX files can contain the ':' character.
+ This function first checks for the existence of a colon in the last component
+ of the given name.  If the name contains a colon we differentiate between a
+ stream and POSIX file by checking if the latter exists through a POSIX stat.
+
+ Function assumes we've already chdir() to the "root" directory of fname.
 ****************************************************************************/
 
 bool is_ntfs_stream_name(const char *fname)
 {
+       const char *lastcomp;
+       SMB_STRUCT_STAT sbuf;
+
+       /* If all pathnames are treated as POSIX we ignore streams. */
        if (lp_posix_pathnames()) {
-               return False;
+               return false;
        }
-       return (strchr_m(fname, ':') != NULL) ? True : False;
+
+       /* Find the last component of the name. */
+       if ((lastcomp = strrchr_m(fname, '/')) != NULL)
+               ++lastcomp;
+       else
+               lastcomp = fname;
+
+       /* If there is no colon in the last component, it's not a stream. */
+       if (strchr_m(lastcomp, ':') == NULL)
+               return false;
+
+       /*
+        * If file already exists on disk, it's not a stream. The stat must
+        * bypass the vfs layer so streams modules don't intefere.
+        */
+       if (sys_stat(fname, &sbuf) == 0) {
+               DEBUG(5, ("is_ntfs_stream_name: file %s contains a ':' but is "
+                       "not a stream\n", fname));
+               return false;
+       }
+
+       return true;
 }
 
 /****************************************************************************