this is a big global fix for the ptr = Realloc(ptr, size) bug.
[Samba.git] / source3 / msdfs / msdfs.c
blob1fa16d40060d1e141b193124b087346f1e3532c2
1 /*
2 Unix SMB/Netbios implementation.
3 Version 3.0
4 MSDfs services for Samba
5 Copyright (C) Shirish Kalele 2000
7 This program is free software; you can redistribute it and/or modify
8 it under the terms of the GNU General Public License as published by
9 the Free Software Foundation; either version 2 of the License, or
10 (at your option) any later version.
12 This program is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 GNU General Public License for more details.
17 You should have received a copy of the GNU General Public License
18 along with this program; if not, write to the Free Software
19 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
22 #include "includes.h"
24 extern int DEBUGLEVEL;
25 extern pstring global_myname;
26 extern uint32 global_client_caps;
28 #ifdef WITH_MSDFS
30 /**********************************************************************
31 Create a tcon relative path from a dfs_path structure
32 **********************************************************************/
34 static void create_nondfs_path(char* pathname, struct dfs_path* pdp)
36 pstrcpy(pathname,pdp->volumename);
37 pstrcat(pathname,"\\");
38 pstrcat(pathname,pdp->restofthepath);
41 /**********************************************************************
42 Parse the pathname of the form \hostname\service\volume\restofthepath
43 into the dfs_path structure
44 **********************************************************************/
46 static BOOL parse_dfs_path(char* pathname, struct dfs_path* pdp)
48 pstring pathname_local;
49 char* p,*temp;
51 pstrcpy(pathname_local,pathname);
52 p = temp = pathname_local;
54 ZERO_STRUCTP(pdp);
56 trim_string(temp,"\\","\\");
57 DEBUG(10,("temp in parse_dfs_path: .%s. after trimming \\'s\n",temp));
59 /* now tokenize */
60 /* parse out hostname */
61 p = strchr_m(temp,'\\');
62 if(p == NULL)
63 return False;
64 *p = '\0';
65 pstrcpy(pdp->hostname,temp);
66 DEBUG(10,("hostname: %s\n",pdp->hostname));
68 /* parse out servicename */
69 temp = p+1;
70 p = strchr_m(temp,'\\');
71 if(p == NULL) {
72 pstrcpy(pdp->servicename,temp);
73 return True;
75 *p = '\0';
76 pstrcpy(pdp->servicename,temp);
77 DEBUG(10,("servicename: %s\n",pdp->servicename));
79 /* parse out volumename */
80 temp = p+1;
81 p = strchr_m(temp,'\\');
82 if(p == NULL) {
83 pstrcpy(pdp->volumename,temp);
84 return True;
86 *p = '\0';
87 pstrcpy(pdp->volumename,temp);
88 DEBUG(10,("volumename: %s\n",pdp->volumename));
90 /* remaining path .. */
91 pstrcpy(pdp->restofthepath,p+1);
92 DEBUG(10,("rest of the path: %s\n",pdp->restofthepath));
93 return True;
96 /********************************************************
97 Fake up a connection struct for the VFS layer.
98 *********************************************************/
100 static BOOL create_conn_struct( connection_struct *conn, int snum, char *path)
102 ZERO_STRUCTP(conn);
103 conn->service = snum;
104 conn->connectpath = path;
106 if (!vfs_init(conn)) {
107 DEBUG(0,("create_conn_struct: vfs init failed.\n"));
108 return False;
110 return True;
113 /**********************************************************************
114 Forms a valid Unix pathname from the junction
115 **********************************************************************/
117 static BOOL form_path_from_junction(struct junction_map* jn, char* path, int max_pathlen,
118 connection_struct *conn)
120 int snum;
122 if(!path || !jn)
123 return False;
125 snum = lp_servicenumber(jn->service_name);
126 if(snum < 0)
127 return False;
129 safe_strcpy(path, lp_pathname(snum), max_pathlen-1);
130 safe_strcat(path, "/", max_pathlen-1);
131 strlower(jn->volume_name);
132 safe_strcat(path, jn->volume_name, max_pathlen-1);
134 if (!create_conn_struct(conn, snum, path))
135 return False;
137 return True;
140 /**********************************************************************
141 Creates a junction structure from the Dfs pathname
142 **********************************************************************/
144 BOOL create_junction(char* pathname, struct junction_map* jn)
146 struct dfs_path dp;
148 parse_dfs_path(pathname,&dp);
150 /* check if path is dfs : check hostname is the first token */
151 if(global_myname && (strcasecmp(global_myname,dp.hostname)!=0)) {
152 DEBUG(4,("create_junction: Invalid hostname %s in dfs path %s\n", dp.hostname, pathname));
153 return False;
156 /* Check for a non-DFS share */
157 if(!lp_msdfs_root(lp_servicenumber(dp.servicename))) {
158 DEBUG(4,("create_junction: %s is not an msdfs root.\n", dp.servicename));
159 return False;
162 pstrcpy(jn->service_name,dp.servicename);
163 pstrcpy(jn->volume_name,dp.volumename);
164 return True;
167 /**********************************************************************
168 Parse the contents of a symlink to verify if it is an msdfs referral
169 A valid referral is of the form: msdfs:server1\share1,server2\share2
170 **********************************************************************/
172 static BOOL parse_symlink(char* buf,struct referral** preflist, int* refcount)
174 pstring temp;
175 char* prot;
176 char* alt_path[MAX_REFERRAL_COUNT];
177 int count=0, i;
178 struct referral* reflist;
180 pstrcpy(temp,buf);
182 prot = strtok(temp,":");
184 if(!strequal(prot, "msdfs"))
185 return False;
187 /* It's an msdfs referral */
188 if(!preflist)
189 return True;
191 /* parse out the alternate paths */
192 while(((alt_path[count] = strtok(NULL,",")) != NULL) && count<MAX_REFERRAL_COUNT)
193 count++;
195 DEBUG(10,("parse_symlink: count=%d\n", count));
197 reflist = *preflist = (struct referral*) malloc(count * sizeof(struct referral));
198 if(reflist == NULL) {
199 DEBUG(0,("parse_symlink: Malloc failed!\n"));
200 return False;
203 for(i=0;i<count;i++) {
204 /* replace / in the alternate path by a \ */
205 char* p = strchr_m(alt_path[i],'/');
206 if(p)
207 *p = '\\';
209 pstrcpy(reflist[i].alternate_path, "\\");
210 pstrcat(reflist[i].alternate_path, alt_path[i]);
211 reflist[i].proximity = 0;
212 reflist[i].ttl = REFERRAL_TTL;
213 DEBUG(10, ("parse_symlink: Created alt path: %s\n", reflist[i].alternate_path));
216 if(refcount)
217 *refcount = count;
219 return True;
222 /**********************************************************************
223 Returns true if the unix path is a valid msdfs symlink
224 **********************************************************************/
226 BOOL is_msdfs_link(connection_struct* conn, char* path)
228 SMB_STRUCT_STAT st;
229 pstring referral;
230 int referral_len = 0;
232 if(!path || !conn)
233 return False;
235 strlower(path);
237 if(conn->vfs_ops.lstat(conn,path,&st) != 0) {
238 DEBUG(5,("is_msdfs_link: %s does not exist.\n",path));
239 return False;
242 if(S_ISLNK(st.st_mode)) {
243 /* open the link and read it */
244 referral_len = conn->vfs_ops.readlink(conn, path, referral, sizeof(pstring));
245 if(referral_len == -1)
246 DEBUG(0,("is_msdfs_link: Error reading msdfs link %s: %s\n", path, strerror(errno)));
248 referral[referral_len] = '\0';
249 DEBUG(5,("is_msdfs_link: %s -> %s\n",path,referral));
250 if(parse_symlink(referral, NULL, NULL))
251 return True;
253 return False;
256 /**********************************************************************
257 Fills in the junction_map struct with the referrals from the
258 symbolic link
259 **********************************************************************/
261 BOOL get_referred_path(struct junction_map* junction)
263 pstring path;
264 pstring buf;
265 SMB_STRUCT_STAT st;
266 connection_struct conns;
267 connection_struct *conn = &conns;
269 if(!form_path_from_junction(junction, path, sizeof(path), conn))
270 return False;
272 DEBUG(5,("get_referred_path: lstat target: %s\n", path));
274 if(conn->vfs_ops.lstat(conn,path,&st) != 0) {
275 DEBUG(5,("get_referred_path: %s does not exist.\n",path));
276 return False;
279 if(S_ISLNK(st.st_mode)) {
280 /* open the link and read it to get the dfs referral */
281 int linkcnt = 0;
282 linkcnt = conn->vfs_ops.readlink(conn, path, buf, sizeof(buf));
283 buf[linkcnt] = '\0';
284 DEBUG(5,("get_referred_path: Referral: %s\n",buf));
285 if(parse_symlink(buf, &junction->referral_list, &junction->referral_count))
286 return True;
288 return False;
291 /**************************************************************
292 Decides if given pathname is Dfs and if it should be redirected
293 Converts pathname to non-dfs format if Dfs redirection not required
294 **************************************************************/
296 BOOL dfs_redirect(char* pathname, connection_struct* conn)
298 struct dfs_path dp;
299 pstring temp;
300 fstring path;
302 pstrcpy(temp,pathname);
304 if(!lp_msdfs_root(SNUM(conn)) )
305 return False;
307 parse_dfs_path(pathname,&dp);
309 if(global_myname && (strcasecmp(global_myname,dp.hostname)!=0))
310 return False;
312 /* check if need to redirect */
313 fstrcpy(path, conn->connectpath);
314 fstrcat(path, "/");
315 fstrcat(path, dp.volumename);
316 if(is_msdfs_link(conn, path)) {
317 DEBUG(4,("dfs_redirect: Redirecting %s\n",temp));
318 return True;
319 } else {
320 create_nondfs_path(pathname,&dp);
321 DEBUG(4,("dfs_redirect: Not redirecting %s. Converted to non-dfs pathname \'%s\'\n",
322 temp,pathname));
323 return False;
328 Special DFS redirect call for findfirst's.
329 If the findfirst is for the dfs junction, then no redirection,
330 if it is for the underlying directory contents, redirect.
333 BOOL dfs_findfirst_redirect(char* pathname, connection_struct* conn)
335 struct dfs_path dp;
337 pstring temp;
339 pstrcpy(temp,pathname);
341 /* Is the path Dfs-redirectable? */
342 if(!dfs_redirect(temp,conn)) {
343 pstrcpy(pathname,temp);
344 return False;
347 parse_dfs_path(pathname,&dp);
348 DEBUG(8,("dfs_findfirst_redirect: path %s is in Dfs. dp.restofthepath=.%s.\n",
349 pathname,dp.restofthepath));
350 if(!(*(dp.restofthepath))) {
351 create_nondfs_path(pathname,&dp);
352 return False;
355 return True;
358 static int setup_ver2_dfs_referral(char* pathname, char** ppdata,
359 struct junction_map* junction,
360 BOOL self_referral)
362 char* pdata = *ppdata;
364 unsigned char uni_requestedpath[1024];
365 int uni_reqpathoffset1,uni_reqpathoffset2;
366 int uni_curroffset;
367 int requestedpathlen=0;
368 int offset;
369 int reply_size = 0;
370 int i=0;
372 DEBUG(10,("setting up version2 referral\nRequested path:\n"));
374 requestedpathlen = (dos_struni2(uni_requestedpath,pathname,512)+1)*2;
376 dump_data(10,uni_requestedpath,requestedpathlen);
378 DEBUG(10,("ref count = %u\n",junction->referral_count));
380 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE +
381 VERSION2_REFERRAL_SIZE * junction->referral_count;
383 uni_reqpathoffset2 = uni_reqpathoffset1 + requestedpathlen;
385 uni_curroffset = uni_reqpathoffset2 + requestedpathlen;
387 reply_size = REFERRAL_HEADER_SIZE + VERSION2_REFERRAL_SIZE*junction->referral_count +
388 2 * requestedpathlen;
389 DEBUG(10,("reply_size: %u\n",reply_size));
391 /* add up the unicode lengths of all the referral paths */
392 for(i=0;i<junction->referral_count;i++) {
393 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
394 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
397 DEBUG(10,("reply_size = %u\n",reply_size));
398 /* add the unexplained 0x16 bytes */
399 reply_size += 0x16;
401 pdata = Realloc(pdata,reply_size);
402 if(pdata == NULL) {
403 DEBUG(0,("malloc failed for Realloc!\n"));
404 return -1;
406 else *ppdata = pdata;
408 /* copy in the dfs requested paths.. required for offset calculations */
409 memcpy(pdata+uni_reqpathoffset1,uni_requestedpath,requestedpathlen);
410 memcpy(pdata+uni_reqpathoffset2,uni_requestedpath,requestedpathlen);
412 /* create the header */
413 SSVAL(pdata,0,requestedpathlen-2); /* path consumed */
414 SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */
415 if(self_referral)
416 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
417 else
418 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
420 offset = 8;
421 /* add the referral elements */
422 for(i=0;i<junction->referral_count;i++) {
423 struct referral* ref = &(junction->referral_list[i]);
424 int unilen;
426 SSVAL(pdata,offset,2); /* version 2 */
427 SSVAL(pdata,offset+2,VERSION2_REFERRAL_SIZE);
428 if(self_referral)
429 SSVAL(pdata,offset+4,1);
430 else
431 SSVAL(pdata,offset+4,0);
432 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
433 SIVAL(pdata,offset+8,ref->proximity);
434 SIVAL(pdata,offset+12,ref->ttl);
436 SSVAL(pdata,offset+16,uni_reqpathoffset1-offset);
437 SSVAL(pdata,offset+18,uni_reqpathoffset2-offset);
438 /* copy referred path into current offset */
439 unilen = (dos_struni2(pdata+uni_curroffset,ref->alternate_path,512) +1)*2;
440 SSVAL(pdata,offset+20,uni_curroffset-offset);
442 uni_curroffset += unilen;
443 offset += VERSION2_REFERRAL_SIZE;
445 /* add in the unexplained 22 (0x16) bytes at the end */
446 memset(pdata+uni_curroffset,'\0',0x16);
447 free(junction->referral_list);
448 return reply_size;
451 static int setup_ver3_dfs_referral(char* pathname, char** ppdata,
452 struct junction_map* junction,
453 BOOL self_referral)
455 char* pdata = *ppdata;
457 unsigned char uni_reqpath[1024];
458 int uni_reqpathoffset1, uni_reqpathoffset2;
459 int uni_curroffset;
460 int reply_size = 0;
462 int reqpathlen = 0;
463 int offset,i=0;
465 DEBUG(10,("setting up version3 referral\n"));
467 reqpathlen = (dos_struni2(uni_reqpath,pathname,512)+1)*2;
469 dump_data(10,uni_reqpath,reqpathlen);
471 uni_reqpathoffset1 = REFERRAL_HEADER_SIZE + VERSION3_REFERRAL_SIZE * junction->referral_count;
472 uni_reqpathoffset2 = uni_reqpathoffset1 + reqpathlen;
473 reply_size = uni_curroffset = uni_reqpathoffset2 + reqpathlen;
475 for(i=0;i<junction->referral_count;i++) {
476 DEBUG(10,("referral %u : %s\n",i,junction->referral_list[i].alternate_path));
477 reply_size += (strlen(junction->referral_list[i].alternate_path)+1)*2;
480 pdata = Realloc(pdata,reply_size);
481 if(pdata == NULL) {
482 DEBUG(0,("version3 referral setup: malloc failed for Realloc!\n"));
483 return -1;
485 else *ppdata = pdata;
487 /* create the header */
488 SSVAL(pdata,0,reqpathlen-2); /* path consumed */
489 SSVAL(pdata,2,junction->referral_count); /* number of referral in this pkt */
490 if(self_referral)
491 SIVAL(pdata,4,DFSREF_REFERRAL_SERVER | DFSREF_STORAGE_SERVER);
492 else
493 SIVAL(pdata,4,DFSREF_STORAGE_SERVER);
495 /* copy in the reqpaths */
496 memcpy(pdata+uni_reqpathoffset1,uni_reqpath,reqpathlen);
497 memcpy(pdata+uni_reqpathoffset2,uni_reqpath,reqpathlen);
499 offset = 8;
500 for(i=0;i<junction->referral_count;i++) {
501 struct referral* ref = &(junction->referral_list[i]);
502 int unilen;
504 SSVAL(pdata,offset,3); /* version 3 */
505 SSVAL(pdata,offset+2,VERSION3_REFERRAL_SIZE);
506 if(self_referral)
507 SSVAL(pdata,offset+4,1);
508 else
509 SSVAL(pdata,offset+4,0);
511 SSVAL(pdata,offset+6,0); /* ref_flags :use path_consumed bytes? */
512 SIVAL(pdata,offset+8,ref->ttl);
514 SSVAL(pdata,offset+12,uni_reqpathoffset1-offset);
515 SSVAL(pdata,offset+14,uni_reqpathoffset2-offset);
516 /* copy referred path into current offset */
517 unilen = (dos_struni2(pdata+uni_curroffset,ref->alternate_path,512) +1)*2;
518 SSVAL(pdata,offset+16,uni_curroffset-offset);
519 /* copy 0x10 bytes of 00's in the ServiceSite GUID */
520 memset(pdata+offset+18,'\0',16);
522 uni_curroffset += unilen;
523 offset += VERSION3_REFERRAL_SIZE;
525 free(junction->referral_list);
526 return reply_size;
529 /******************************************************************
530 * Set up the Dfs referral for the dfs pathname
531 ******************************************************************/
533 int setup_dfs_referral(char* pathname, int max_referral_level, char** ppdata)
535 struct junction_map junction;
537 BOOL self_referral;
539 int reply_size = 0;
541 ZERO_STRUCT(junction);
543 if(!create_junction(pathname, &junction))
544 return -1;
546 /* get the junction entry */
547 if(!get_referred_path(&junction)) {
549 /* refer the same pathname, create a standard referral struct */
550 struct referral* ref;
551 self_referral = True;
552 junction.referral_count = 1;
553 if((ref = (struct referral*) malloc(sizeof(struct referral))) == NULL) {
554 DEBUG(0,("malloc failed for referral\n"));
555 return -1;
558 pstrcpy(ref->alternate_path,pathname);
559 ref->proximity = 0;
560 ref->ttl = REFERRAL_TTL;
561 junction.referral_list = ref;
562 } else {
563 self_referral = False;
564 if( DEBUGLVL( 3 ) ) {
565 int i=0;
566 dbgtext("setup_dfs_referral: Path %s to alternate path(s):",pathname);
567 for(i=0;i<junction.referral_count;i++)
568 dbgtext(" %s",junction.referral_list[i].alternate_path);
569 dbgtext(".\n");
573 /* create the referral depeding on version */
574 DEBUG(10,("max_referral_level :%d\n",max_referral_level));
575 if(max_referral_level<2 || max_referral_level>3)
576 max_referral_level = 2;
578 switch(max_referral_level) {
579 case 2:
581 reply_size = setup_ver2_dfs_referral(pathname, ppdata, &junction, self_referral);
582 break;
584 case 3:
586 reply_size = setup_ver3_dfs_referral(pathname, ppdata, &junction, self_referral);
587 break;
589 default:
591 DEBUG(0,("setup_dfs_referral: Invalid dfs referral version: %d\n", max_referral_level));
592 return -1;
596 DEBUG(10,("DFS Referral pdata:\n"));
597 dump_data(10,*ppdata,reply_size);
598 return reply_size;
601 int dfs_path_error(char* inbuf, char* outbuf)
603 enum remote_arch_types ra_type = get_remote_arch();
604 BOOL NT_arch = ((ra_type==RA_WINNT) || (ra_type == RA_WIN2K));
605 if(NT_arch && (global_client_caps & (CAP_NT_SMBS | CAP_STATUS32)) ) {
606 SSVAL(outbuf,smb_flg2,SVAL(outbuf,smb_flg2) | FLAGS2_32_BIT_ERROR_CODES);
607 return(ERROR(0,0xc0000000|NT_STATUS_PATH_NOT_COVERED));
609 return(ERROR(ERRSRV,ERRbadpath));
612 /**********************************************************************
613 The following functions are called by the NETDFS RPC pipe functions
614 **********************************************************************/
616 BOOL create_msdfs_link(struct junction_map* jn, BOOL exists)
618 pstring path;
619 pstring msdfs_link;
620 connection_struct conns;
621 connection_struct *conn = &conns;
622 int i=0;
624 if(!form_path_from_junction(jn, path, sizeof(path), conn))
625 return False;
627 /* form the msdfs_link contents */
628 pstrcpy(msdfs_link, "msdfs:");
629 for(i=0; i<jn->referral_count; i++) {
630 char* refpath = jn->referral_list[i].alternate_path;
632 trim_string(refpath, "\\", "\\");
633 if(*refpath == '\0')
634 continue;
636 if(i>0)
637 pstrcat(msdfs_link, ",");
639 pstrcat(msdfs_link, refpath);
642 DEBUG(5,("create_msdfs_link: Creating new msdfs link: %s -> %s\n", path, msdfs_link));
644 if(exists)
645 if(conn->vfs_ops.unlink(conn,path)!=0)
646 return False;
648 if(conn->vfs_ops.symlink(conn, msdfs_link, path) < 0) {
649 DEBUG(1,("create_msdfs_link: symlink failed %s -> %s\nError: %s\n",
650 path, msdfs_link, strerror(errno)));
651 return False;
653 return True;
656 BOOL remove_msdfs_link(struct junction_map* jn)
658 pstring path;
659 connection_struct conns;
660 connection_struct *conn = &conns;
662 if(!form_path_from_junction(jn, path, sizeof(path), conn))
663 return False;
665 if(conn->vfs_ops.unlink(conn, path)!=0)
666 return False;
668 return True;
671 static BOOL form_junctions(int snum, struct junction_map* jn, int* jn_count)
673 int cnt = *jn_count;
674 DIR *dirp;
675 char* dname;
676 pstring connect_path;
677 char* service_name = lp_servicename(snum);
678 connection_struct conns;
679 connection_struct *conn = &conns;
681 pstrcpy(connect_path,lp_pathname(snum));
683 if(*connect_path == '\0')
684 return False;
687 * Fake up a connection struct for the VFS layer.
690 if (!create_conn_struct(conn, snum, connect_path))
691 return False;
693 /* form a junction for the msdfs root - convention */
695 pstrpcy(jn[cnt].service_name, service_name);
696 jn[cnt].volume_name[0] = '\0';
697 jn[cnt].referral_count = 1;
699 slprintf(alt_path,sizeof(alt_path)-1"\\\\%s\\%s", global_myname, service_name);
700 jn[cnt].referral_l
703 dirp = conn->vfs_ops.opendir(conn, connect_path);
704 if(!dirp)
705 return False;
707 while((dname = vfs_readdirname(conn, dirp)) != NULL) {
708 SMB_STRUCT_STAT st;
709 pstring pathreal;
710 fstring buf;
711 int buflen = 0;
712 pstrcpy(pathreal, connect_path);
713 pstrcat(pathreal, "/");
714 pstrcat(pathreal, dname);
716 if(conn->vfs_ops.lstat(conn,pathreal,&st) != 0) {
717 DEBUG(4,("lstat error for %s: %s\n",pathreal, strerror(errno)));
718 continue;
720 if(S_ISLNK(st.st_mode)) {
721 buflen = conn->vfs_ops.readlink(conn, pathreal, buf, sizeof(fstring));
722 buf[buflen] = '\0';
723 if(parse_symlink(buf, &(jn[cnt].referral_list), &(jn[cnt].referral_count))) {
724 pstrcpy(jn[cnt].service_name, service_name);
725 pstrcpy(jn[cnt].volume_name, dname);
726 cnt++;
731 conn->vfs_ops.closedir(conn,dirp);
732 *jn_count = cnt;
733 return True;
736 int enum_msdfs_links(struct junction_map* jn)
738 int i=0;
739 int jn_count = 0;
741 if(!lp_host_msdfs())
742 return -1;
744 for(i=0;*lp_servicename(i);i++) {
745 if(lp_msdfs_root(i))
746 form_junctions(i,jn,&jn_count);
748 return jn_count;
752 #else
753 /* Stub functions if WITH_MSDFS not defined */
754 int setup_dfs_referral(char* pathname, int max_referral_level, char** ppdata)
756 return -1;
759 BOOL is_msdfs_link(connection_struct* conn, char* path)
761 return False;
764 #endif