2 Unix SMB/Netbios implementation.
4 SMB client library implementation
5 Copyright (C) Andrew Tridgell 1998
6 Copyright (C) Richard Sharpe 2000
7 Copyright (C) John Terpstra 2000
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
25 #include "libsmbclient.h"
27 /* Structure for servers ... Held here so we don't need an include ...
28 * May be better to put in an include file
32 struct smbc_server
*next
, *prev
;
42 /* Keep directory entries in a list */
43 struct smbc_dir_list
{
44 struct smbc_dir_list
*next
;
45 struct smbc_dirent
*dirent
;
53 struct smbc_server
*srv
;
55 struct smbc_dir_list
*dir_list
, *dir_end
, *dir_next
;
56 int dir_type
, dir_error
;
59 extern BOOL in_client
;
60 static int smbc_initialized
= 0;
61 static smbc_get_auth_data_fn smbc_auth_fn
= NULL
;
62 static int smbc_debug
;
63 static int smbc_start_fd
;
64 static int smbc_max_fd
= 10000;
65 static struct smbc_file
**smbc_file_table
;
66 static struct smbc_server
*smbc_srvs
;
67 static pstring my_netbios_name
;
68 static pstring smbc_user
;
71 * Clean up a filename by removing redundent stuff
75 smbc_clean_fname(char *name
)
86 DEBUG(5,("cleaning %s\n", name
));
88 if ((p
=strstr(name
,"/./"))) {
96 if ((p
=strstr(name
,"//"))) {
104 if (strcmp(name
,"/../")==0) {
109 if ((p
=strstr(name
,"/../"))) {
111 for (p2
=(p
>name
?p
-1:p
);p2
>name
;p2
--) {
112 if (p2
[0] == '/') break;
120 if (strcmp(name
,"/..")==0) {
126 p
= l
>=3?(name
+l
-3):name
;
127 if (strcmp(p
,"/..")==0) {
129 for (p2
=p
-1;p2
>name
;p2
--) {
130 if (p2
[0] == '/') break;
141 p
= l
>=2?(name
+l
-2):name
;
142 if (strcmp(p
,"/.")==0) {
150 if (strncmp(p
=name
,"./",2) == 0) {
158 if (l
> 1 && p
[l
-1] == '/') {
166 * Function to parse a path and turn it into components
168 * We accept smb://[[[domain;]user[:password@]]server[/share[/path[/file]]]]
170 * smb:// means show all the workgroups
171 * smb://name/ means, if name<1D> exists, list servers in workgroup,
172 * else, if name<20> exists, list all shares for server ...
175 static const char *smbc_prefix
= "smb:";
178 smbc_parse_path(const char *fname
, char *server
, char *share
, char *path
,
179 char *user
, char *password
) /* FIXME, lengths of strings */
186 server
[0] = share
[0] = path
[0] = user
[0] = password
[0] = (char)0;
189 /* clean_fname(s); causing problems ... */
191 /* see if it has the right prefix */
192 len
= strlen(smbc_prefix
);
193 if (strncmp(s
,smbc_prefix
,len
) ||
194 (s
[len
] != '/' && s
[len
] != 0)) return -1; /* What about no smb: ? */
198 /* Watch the test below, we are testing to see if we should exit */
200 if (strncmp(p
, "//", 2) && strncmp(p
, "\\\\", 2)) {
206 p
+= 2; /* Skip the // or \\ */
213 strncpy(server
, lp_workgroup(), 16); /* FIXME: Danger here */
218 /* ok, its for us. Now parse out the server, share etc. */
220 if (!next_token(&p
, server
, "/", sizeof(fstring
))) {
226 if (*p
== (char)0) return 0; /* That's it ... */
228 if (!next_token(&p
, share
, "/", sizeof(fstring
))) {
236 all_string_sub(path
, "/", "\\", 0);
242 * Convert an SMB error into a UNIX error ...
245 int smbc_errno(struct cli_state
*c
)
251 ret
= cli_error(c
, &eclass
, &ecode
, NULL
);
254 DEBUG(3,("smbc_error %d %d (0x%x) -> %d\n",
255 (int)eclass
, (int)ecode
, (int)ecode
, ret
));
261 * Connect to a server, possibly on an existing connection
263 * Here, what we want to do is: If the server and username
264 * match an existing connection, reuse that, otherwise, establish a
267 * If we have to create a new connection, call the auth_fn to get the
268 * info we need, unless the username and password were passed in.
271 struct smbc_server
*smbc_server(char *server
, char *share
,
272 char *workgroup
, char *username
,
275 struct smbc_server
*srv
=NULL
;
277 struct nmb_name called
, calling
;
278 char *p
, *server_n
= server
;
282 extern struct in_addr ipzero
;
287 /* try to use an existing connection */
288 for (srv
=smbc_srvs
;srv
;srv
=srv
->next
) {
289 if (strcmp(server
,srv
->server_name
)==0 &&
290 strcmp(share
,srv
->share_name
)==0 &&
291 strcmp(workgroup
,srv
->workgroup
)==0 &&
292 strcmp(username
, srv
->username
) == 0)
296 if (server
[0] == 0) {
301 /* Pick up the auth info here, once we know we need to connect */
303 smbc_auth_fn(server
, share
, workgroup
, sizeof(fstring
),
304 username
, sizeof(fstring
), password
, sizeof(fstring
));
307 * However, smbc_auth_fn may have picked up info relating to an
308 * existing connection, so try for and existing connection again ...
311 for (srv
=smbc_srvs
;srv
;srv
=srv
->next
) {
312 if (strcmp(server
,srv
->server_name
)==0 &&
313 strcmp(share
,srv
->share_name
)==0 &&
314 strcmp(workgroup
,srv
->workgroup
)==0 &&
315 strcmp(username
, srv
->username
) == 0)
319 make_nmb_name(&calling
, my_netbios_name
, 0x0);
320 make_nmb_name(&called
, server
, 0x20);
322 DEBUG(4,("server_n=[%s] server=[%s]\n", server_n
, server
));
324 if ((p
=strchr(server_n
,'#')) &&
325 (strcmp(p
+1,"1D")==0 || strcmp(p
+1,"01")==0)) {
329 fstrcpy(group
, server_n
);
330 p
= strchr(group
,'#');
335 DEBUG(4,(" -> server_n=[%s] server=[%s]\n", server_n
, server
));
338 slprintf(ipenv
,sizeof(ipenv
)-1,"HOST_%s", server_n
);
342 /* have to open a new connection */
343 if (!cli_initialise(&c
) || !cli_connect(&c
, server_n
, &ip
)) {
348 if (!cli_session_request(&c
, &calling
, &called
)) {
350 if (strcmp(called
.name
, "*SMBSERVER")) {
351 make_nmb_name(&called
, "*SMBSERVER", 0x20);
358 DEBUG(4,(" session request ok\n"));
360 if (!cli_negprot(&c
)) {
366 if (!cli_session_setup(&c
, username
,
367 password
, strlen(password
),
368 password
, strlen(password
),
370 /* try an anonymous login if it failed */
371 !cli_session_setup(&c
, "", "", 1,"", 0, workgroup
)) {
377 DEBUG(4,(" session setup ok\n"));
379 if (!cli_send_tconX(&c
, share
, "?????",
380 password
, strlen(password
)+1)) {
381 errno
= smbc_errno(&c
);
386 DEBUG(4,(" tconx ok\n"));
388 srv
= (struct smbc_server
*)malloc(sizeof(*srv
));
398 srv
->dev
= (dev_t
)(str_checksum(server
) ^ str_checksum(share
));
400 srv
->server_name
= strdup(server
);
401 if (!srv
->server_name
) {
406 srv
->share_name
= strdup(share
);
407 if (!srv
->share_name
) {
412 srv
->workgroup
= strdup(workgroup
);
413 if (!srv
->workgroup
) {
418 srv
->username
= strdup(username
);
419 if (!srv
->username
) {
424 DLIST_ADD(smbc_srvs
, srv
);
430 if (!srv
) return NULL
;
432 if (srv
->server_name
) free(srv
->server_name
);
433 if (srv
->share_name
) free(srv
->share_name
);
439 *Initialise the library etc
442 int smbc_init(smbc_get_auth_data_fn fn
, const char *wgroup
, int debug
)
444 static pstring workgroup
;
447 char *user
= NULL
, *host
= NULL
, *home
= NULL
, *pname
="libsmbclient";
449 smbc_initialized
= 1;
455 setup_logging(pname
, False
);
458 * We try to construct our netbios name from our hostname etc
461 user
= getenv("USER");
462 if (!user
) user
= ""; /* FIXME: What to do about this? */
465 * FIXME: Is this the best way to get the user info? */
467 pstrcpy(smbc_user
, user
); /* Save for use elsewhere */
472 * Hmmm, I want to get hostname as well, but I am too lazy for the moment
475 slprintf(my_netbios_name
, 16, "smbc%s%d", user
, pid
);
476 pstrcpy(workgroup
, wgroup
);
478 charset_initialise();
480 /* Here we would open the smb.conf file if needed ... */
482 home
= getenv("HOME");
484 slprintf(conf
, sizeof(conf
), "%s/.smb/smb.conf", home
);
486 load_interfaces(); /* Load the list of interfaces ... */
488 in_client
= True
; /* FIXME, make a param */
492 if (!lp_load(conf
, True
, False
, False
)) {
495 * Hmmm, what the hell do we do here ... we could not parse the
496 * config file ... We must return an error ... and keep info around
497 * about why we failed
500 errno = ENOENT; /* Hmmm, what error resp does lp_load return ? */
505 codepage_initialise(lp_client_code_page()); /* Get a codepage */
507 reopen_logs(); /* Get logging working ... */
510 * Now initialize the file descriptor array and figure out what the
511 * max open files is, so we can return FD's that are above the max
512 * open file, and separated by a guard band
515 #if (defined(HAVE_GETRLIMIT) && defined(RLIMIT_NOFILE))
519 if (getrlimit(RLIMIT_NOFILE
, &rlp
)) {
521 DEBUG(0, ("smbc_init: getrlimit(1) for RLIMIT_NOFILE failed with error %s\n", strerror(errno
)));
523 smbc_start_fd
= 1000000;
524 smbc_max_fd
= 10000; /* FIXME, should be a define ... */
529 smbc_start_fd
= rlp
.rlim_max
+ 10000; /* Leave a guard space of 10,000 */
534 #else /* !defined(HAVE_GETRLIMIT) || !defined(RLIMIT_NOFILE) */
536 smbc_start_fd
= 1000000;
537 smbc_max_fd
= 10000; /* FIXME, should be a define ... */
541 smbc_file_table
= malloc(smbc_max_fd
* sizeof(struct smbc_file
*));
543 for (p
= 0; p
< smbc_max_fd
; p
++)
544 smbc_file_table
[p
] = NULL
;
546 if (!smbc_file_table
)
549 return 0; /* Success */
554 * Routine to open() a file ...
557 int smbc_open(const char *fname
, int flags
, mode_t mode
)
559 fstring server
, share
, user
, password
;
561 struct smbc_server
*srv
= NULL
;
562 struct smbc_file
*file
= NULL
;
565 if (!smbc_initialized
) {
567 errno
= EUCLEAN
; /* Best I can think of ... */
579 smbc_parse_path(fname
, server
, share
, path
, user
, password
); /* FIXME, check errors */
581 if (user
[0] == (char)0) pstrcpy(user
, smbc_user
);
583 srv
= smbc_server(server
, share
, lp_workgroup(), user
, password
);
587 return -1; /* smbc_server sets errno */
591 if (path
[strlen(path
) - 1] == '\\') {
600 /* Find a free slot first */
602 while (smbc_file_table
[slot
])
605 if (slot
> smbc_max_fd
) {
607 errno
= ENOMEM
; /* FIXME, is this best? */
612 smbc_file_table
[slot
] = malloc(sizeof(struct smbc_file
));
614 if (!smbc_file_table
[slot
]) {
621 if ((fd
= cli_open(&srv
->cli
, path
, flags
, DENY_NONE
)) < 0) {
623 /* Handle the error ... */
625 free(smbc_file_table
[slot
]);
626 smbc_file_table
[slot
] = NULL
;
627 errno
= smbc_errno(&srv
->cli
);
632 /* Fill in file struct */
634 smbc_file_table
[slot
]->cli_fd
= fd
;
635 smbc_file_table
[slot
]->smbc_fd
= slot
+ smbc_start_fd
;
636 smbc_file_table
[slot
]->fname
= strdup(fname
);
637 smbc_file_table
[slot
]->srv
= srv
;
638 smbc_file_table
[slot
]->offset
= 0;
639 smbc_file_table
[slot
]->file
= True
;
641 return smbc_file_table
[slot
]->smbc_fd
;
645 /* Check if opendir needed ... */
650 eno
= smbc_errno(&srv
->cli
);
651 fd
= smbc_opendir(fname
);
652 if (fd
< 0) errno
= eno
;
657 return 1; /* Success, with fd ... */
661 /*FIXME, clean up things ... */
667 * Routine to create a file
670 static int creat_bits
= O_WRONLY
| O_CREAT
| O_TRUNC
; /* FIXME: Do we need this */
672 int smbc_creat(const char *path
, mode_t mode
)
675 if (!smbc_initialized
) {
682 return smbc_open(path
, creat_bits
, mode
);
686 * Routine to read() a file ...
689 ssize_t
smbc_read(int fd
, void *buf
, size_t count
)
691 struct smbc_file
*fe
;
694 if (!smbc_initialized
) {
701 DEBUG(4, ("smbc_read(%d, %d)\n", fd
, (int)count
));
703 if (fd
< smbc_start_fd
|| fd
>= (smbc_start_fd
+ smbc_max_fd
)) {
710 fe
= smbc_file_table
[fd
- smbc_start_fd
];
719 ret
= cli_read(&fe
->srv
->cli
, fe
->cli_fd
, buf
, fe
->offset
, count
);
723 errno
= smbc_errno(&fe
->srv
->cli
);
730 DEBUG(4, (" --> %d\n", ret
));
732 return ret
; /* Success, ret bytes of data ... */
737 * Routine to write() a file ...
740 ssize_t
smbc_write(int fd
, void *buf
, size_t count
)
743 struct smbc_file
*fe
;
745 if (!smbc_initialized
) {
752 if (fd
< smbc_start_fd
|| fd
>= (smbc_start_fd
+ smbc_max_fd
)) {
759 fe
= smbc_file_table
[fd
- smbc_start_fd
];
761 ret
= cli_write(&fe
->srv
->cli
, fe
->cli_fd
, 0, buf
, fe
->offset
, count
);
765 errno
= smbc_errno(&fe
->srv
->cli
);
772 return ret
; /* Success, 0 bytes of data ... */
776 * Routine to close() a file ...
779 int smbc_close(int fd
)
781 struct smbc_file
*fe
;
783 if (!smbc_initialized
) {
790 if (fd
< smbc_start_fd
|| fd
>= (smbc_start_fd
+ smbc_max_fd
)) {
797 fe
= smbc_file_table
[fd
- smbc_start_fd
];
801 return smbc_closedir(fd
);
805 if (!cli_close(&fe
->srv
->cli
, fe
->cli_fd
)) {
807 errno
= smbc_errno(&fe
->srv
->cli
); /* FIXME, should we deallocate slot? */
813 smbc_file_table
[fd
- smbc_start_fd
] = NULL
;
819 * Routine to unlink() a file
822 int smbc_unlink(const char *fname
)
824 fstring server
, share
, user
, password
;
826 struct smbc_server
*srv
= NULL
;
828 if (!smbc_initialized
) {
830 errno
= EUCLEAN
; /* Best I can think of ... */
842 smbc_parse_path(fname
, server
, share
, path
, user
, password
); /* FIXME, check errors */
844 if (user
[0] == (char)0) pstrcpy(user
, smbc_user
);
846 srv
= smbc_server(server
, share
, lp_workgroup(), user
, password
);
850 return -1; /* smbc_server sets errno */
854 /* if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
856 int job = smbc_stat_printjob(srv, path, NULL, NULL);
862 if (cli_printjob_del(&srv->cli, job) != 0) {
869 if (!cli_unlink(&srv
->cli
, path
)) {
871 errno
= smbc_errno(&srv
->cli
);
873 if (errno
== EACCES
) { /* Check if the file is a directory */
875 int err
, saverr
= errno
;
879 time_t m_time
= 0, a_time
= 0, c_time
= 0;
882 if (!smbc_getatr(srv
, path
, &mode
, &size
,
883 &c_time
, &a_time
, &m_time
, &ino
)) {
885 /* Hmmm, bad error ... What? */
887 errno
= smbc_errno(&srv
->cli
);
893 if (IS_DOS_DIR(mode
))
896 errno
= saverr
; /* Restore this */
905 return 0; /* Success ... */
910 * Routine to rename() a file
913 int smbc_rename(const char *oname
, const char *nname
)
915 fstring server1
, share1
, server2
, share2
, user1
, user2
, password1
, password2
;
916 pstring path1
, path2
;
917 struct smbc_server
*srv
= NULL
;
919 if (!smbc_initialized
) {
921 errno
= EUCLEAN
; /* Best I can think of ... */
926 if (!oname
|| !nname
) {
933 DEBUG(4, ("smbc_rename(%s,%s)\n", oname
, nname
));
935 smbc_parse_path(oname
, server1
, share1
, path1
, user1
, password1
);
937 if (user1
[0] == (char)0) pstrcpy(user1
, smbc_user
);
939 smbc_parse_path(nname
, server2
, share2
, path2
, user2
, password2
);
941 if (user2
[0] == (char)0) pstrcpy(user2
, smbc_user
);
943 if (strcmp(server1
, server2
) || strcmp(share1
, share2
) ||
944 strcmp(user1
, user2
)) {
946 /* Can't rename across file systems, or users?? */
953 srv
= smbc_server(server1
, share1
, lp_workgroup(), user1
, password1
);
960 if (!cli_rename(&srv
->cli
, path1
, path2
)) {
961 int eno
= smbc_errno(&srv
->cli
);
964 !cli_unlink(&srv
->cli
, path2
) ||
965 !cli_rename(&srv
->cli
, path1
, path2
)) {
973 return 0; /* Success */
978 * A routine to lseek() a file
981 off_t
smbc_lseek(int fd
, off_t offset
, int whence
)
983 struct smbc_file
*fe
;
986 if (!smbc_initialized
) {
993 if (fd
< smbc_start_fd
|| fd
>= (smbc_start_fd
+ smbc_max_fd
)) {
1000 fe
= smbc_file_table
[fd
- smbc_start_fd
];
1004 return smbc_lseekdir(fd
, offset
, whence
);
1010 fe
->offset
= offset
;
1014 fe
->offset
+= offset
;
1018 if (!cli_qfileinfo(&fe
->srv
->cli
, fe
->cli_fd
, NULL
, &size
, NULL
, NULL
,
1019 NULL
, NULL
, NULL
) &&
1020 !cli_getattrE(&fe
->srv
->cli
, fe
->cli_fd
, NULL
, &size
, NULL
, NULL
,
1026 fe
->offset
= size
+ offset
;
1040 * Generate an inode number from file name for those things that need it
1044 ino_t
smbc_inode(const char *name
)
1047 if (!*name
) return 2; /* FIXME, why 2 ??? */
1048 return (ino_t
)str_checksum(name
);
1053 * Routine to put basic stat info into a stat structure ... Used by stat and
1058 int smbc_setup_stat(struct stat
*st
, char *fname
, size_t size
, int mode
)
1063 if (IS_DOS_DIR(mode
)) {
1064 st
->st_mode
= SMBC_DIR_MODE
;
1066 st
->st_mode
= SMBC_FILE_MODE
;
1069 if (IS_DOS_ARCHIVE(mode
)) st
->st_mode
|= S_IXUSR
;
1070 if (IS_DOS_SYSTEM(mode
)) st
->st_mode
|= S_IXGRP
;
1071 if (IS_DOS_HIDDEN(mode
)) st
->st_mode
|= S_IXOTH
;
1072 if (!IS_DOS_READONLY(mode
)) st
->st_mode
|= S_IWUSR
;
1075 st
->st_blksize
= 512;
1076 st
->st_blocks
= (size
+511)/512;
1077 st
->st_uid
= getuid();
1078 st
->st_gid
= getgid();
1080 if (IS_DOS_DIR(mode
)) {
1086 if (st
->st_ino
== 0) {
1087 st
->st_ino
= smbc_inode(fname
);
1092 * Get info from an SMB server on a file. Use a qpathinfo call first
1093 * and if that fails, use getatr, as Win95 sometimes refuses qpathinfo
1096 BOOL
smbc_getatr(struct smbc_server
*srv
, char *path
,
1097 uint16
*mode
, size_t *size
,
1098 time_t *c_time
, time_t *a_time
, time_t *m_time
,
1102 if (!smbc_initialized
) {
1109 DEBUG(4,("sending qpathinfo\n"));
1111 if (!srv
->no_pathinfo2
&&
1112 cli_qpathinfo2(&srv
->cli
, path
, c_time
, a_time
, m_time
, NULL
,
1113 size
, mode
, ino
)) return True
;
1115 /* if this is NT then don't bother with the getatr */
1116 if (srv
->cli
.capabilities
& CAP_NT_SMBS
) return False
;
1118 if (cli_getatr(&srv
->cli
, path
, mode
, size
, m_time
)) {
1119 a_time
= c_time
= m_time
;
1120 srv
->no_pathinfo2
= True
;
1127 * Routine to stat a file given a name
1130 int smbc_stat(const char *fname
, struct stat
*st
)
1132 struct smbc_server
*srv
;
1133 fstring server
, share
, user
, password
;
1135 time_t m_time
= 0, a_time
= 0, c_time
= 0;
1140 if (!smbc_initialized
) {
1142 errno
= EUCLEAN
; /* Best I can think of ... */
1154 DEBUG(4, ("stat(%s)\n", fname
));
1156 smbc_parse_path(fname
, server
, share
, path
, user
, password
); /*FIXME, errors*/
1158 if (user
[0] == (char)0) pstrcpy(user
, smbc_user
);
1160 srv
= smbc_server(server
, share
, lp_workgroup(), user
, password
);
1164 return -1; /* errno set by smbc_server */
1168 /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
1170 mode = aDIR | aRONLY;
1173 else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
1175 if (strcmp(path, "\\") == 0) {
1177 mode = aDIR | aRONLY;
1183 smbc_stat_printjob(srv, path, &size, &m_time);
1184 c_time = a_time = m_time;
1189 if (!smbc_getatr(srv
, path
, &mode
, &size
,
1190 &c_time
, &a_time
, &m_time
, &ino
)) {
1192 errno
= smbc_errno(&srv
->cli
);
1201 smbc_setup_stat(st
, path
, size
, mode
);
1203 st
->st_atime
= a_time
;
1204 st
->st_ctime
= c_time
;
1205 st
->st_mtime
= m_time
;
1206 st
->st_dev
= srv
->dev
;
1213 * Routine to stat a file given an fd
1216 int smbc_fstat(int fd
, struct stat
*st
)
1218 struct smbc_file
*fe
;
1219 time_t c_time
, a_time
, m_time
;
1224 if (!smbc_initialized
) {
1231 if (fd
< smbc_start_fd
|| fd
>= (smbc_start_fd
+ smbc_max_fd
)) {
1238 fe
= smbc_file_table
[fd
- smbc_start_fd
];
1242 return smbc_fstatdir(fd
, st
);
1246 if (!cli_qfileinfo(&fe
->srv
->cli
, fe
->cli_fd
,
1247 &mode
, &size
, &c_time
, &a_time
, &m_time
, NULL
, &ino
) &&
1248 !cli_getattrE(&fe
->srv
->cli
, fe
->cli_fd
,
1249 &mode
, &size
, &c_time
, &a_time
, &m_time
)) {
1258 smbc_setup_stat(st
, fe
->fname
, size
, mode
);
1260 st
->st_atime
= a_time
;
1261 st
->st_ctime
= c_time
;
1262 st
->st_mtime
= m_time
;
1263 st
->st_dev
= fe
->srv
->dev
;
1270 * Routine to open a directory
1274 * smb: which should list all the workgroups available
1276 * smb:workgroup//server
1278 * smb://server/share
1281 static void smbc_remove_dir(struct smbc_file
*dir
)
1283 struct smbc_dir_list
*d
,*f
;
1290 if (f
->dirent
) free(f
->dirent
);
1295 dir
->dir_list
= dir
->dir_end
= dir
->dir_next
= NULL
;
1299 static int add_dirent(struct smbc_file
*dir
, const char *name
, const char *comment
, uint32 type
)
1301 struct smbc_dirent
*dirent
;
1305 * Allocate space for the dirent, which must be increased by the
1306 * size of the name and the comment and 1 for the null on the comment.
1307 * The null on the name is already accounted for.
1310 size
= sizeof(struct smbc_dirent
) + (name
?strlen(name
):0) +
1311 (comment
?strlen(comment
):0) + 1;
1313 dirent
= malloc(size
);
1317 dir
->dir_error
= ENOMEM
;
1322 if (dir
->dir_list
== NULL
) {
1324 dir
->dir_list
= malloc(sizeof(struct smbc_dir_list
));
1325 if (!dir
->dir_list
) {
1328 dir
->dir_error
= ENOMEM
;
1333 dir
->dir_end
= dir
->dir_next
= dir
->dir_list
;
1338 dir
->dir_end
->next
= malloc(sizeof(struct smbc_dir_list
));
1340 if (!dir
->dir_end
) {
1343 dir
->dir_error
= ENOMEM
;
1348 dir
->dir_end
= dir
->dir_end
->next
;
1352 dir
->dir_end
->next
= NULL
;
1353 dir
->dir_end
->dirent
= dirent
;
1355 dirent
->smbc_type
= type
;
1356 dirent
->namelen
= (name
?strlen(name
):0);
1357 dirent
->commentlen
= (comment
?strlen(comment
):0);
1358 dirent
->dirlen
= size
;
1360 strncpy(dirent
->name
, (name
?name
:""), dirent
->namelen
+ 1);
1362 dirent
->comment
= (char *)(&dirent
->name
+ dirent
->namelen
+ 1);
1363 strncpy(dirent
->comment
, (comment
?comment
:""), dirent
->commentlen
+ 1);
1370 list_fn(const char *name
, uint32 type
, const char *comment
, void *state
)
1372 struct smbc_file
*dir
= (struct smbc_file
*)state
;
1375 /* We need to process the type a little ... */
1377 if (dir
->dir_type
== SMBC_FILE_SHARE
) {
1380 case 0: /* Directory tree */
1381 dirent_type
= SMBC_FILE_SHARE
;
1385 dirent_type
= SMBC_PRINTER_SHARE
;
1389 dirent_type
= SMBC_COMMS_SHARE
;
1393 dirent_type
= SMBC_IPC_SHARE
;
1397 dirent_type
= SMBC_FILE_SHARE
; /* FIXME, error? */
1402 else dirent_type
= dir
->dir_type
;
1404 if (add_dirent(dir
, name
, comment
, dirent_type
) < 0) {
1406 /* An error occurred, what do we do? */
1413 dir_list_fn(file_info
*finfo
, const char *mask
, void *state
)
1416 fprintf(stderr
, "Finfo->name=%s, mask=%s\n", finfo
->name
, mask
);
1417 if (add_dirent((struct smbc_file
*)state
, finfo
->name
, "",
1418 (finfo
->mode
&aDIR
?SMBC_DIR
:SMBC_FILE
)) < 0) {
1420 /* Handle an error ... */
1426 int smbc_opendir(const char *fname
)
1428 struct in_addr addr
;
1429 fstring server
, share
, user
, password
;
1431 struct smbc_server
*srv
= NULL
;
1432 struct in_addr rem_ip
;
1437 if (!smbc_initialized
) {
1451 if (smbc_parse_path(fname
, server
, share
, path
, user
, password
)) {
1458 if (user
[0] == (char)0) pstrcpy(user
, smbc_user
);
1460 /* Get a file entry ... */
1464 while (smbc_file_table
[slot
])
1467 if (slot
> smbc_max_fd
) {
1470 return -1; /* FIXME, ... move into a func */
1474 smbc_file_table
[slot
] = malloc(sizeof(struct smbc_file
));
1476 if (!smbc_file_table
[slot
]) {
1483 smbc_file_table
[slot
]->cli_fd
= 0;
1484 smbc_file_table
[slot
]->smbc_fd
= slot
+ smbc_start_fd
;
1485 smbc_file_table
[slot
]->fname
= strdup(fname
);
1486 smbc_file_table
[slot
]->srv
= NULL
;
1487 smbc_file_table
[slot
]->offset
= 0;
1488 smbc_file_table
[slot
]->file
= False
;
1489 smbc_file_table
[slot
]->dir_list
=
1490 smbc_file_table
[slot
]->dir_next
=
1491 smbc_file_table
[slot
]->dir_end
= NULL
;
1493 if (server
[0] == (char)0) {
1495 if (share
[0] != (char)0 || path
[0] != (char)0) {
1498 if (smbc_file_table
[slot
]) free(smbc_file_table
[slot
]);
1499 smbc_file_table
[slot
] = NULL
;
1504 /* We have server and share and path empty ... so list the workgroups */
1506 /* fprintf(stderr, "Workgroup is: %s\n", lp_workgroup()); */
1507 cli_get_backup_server(my_netbios_name
, lp_workgroup(), server
, sizeof(server
));
1509 smbc_file_table
[slot
]->dir_type
= SMBC_WORKGROUP
;
1512 * Get a connection to IPC$ on the server if we do not already have one
1515 srv
= smbc_server(server
, "IPC$", lp_workgroup(), user
, password
);
1519 if (smbc_file_table
[slot
]) free(smbc_file_table
[slot
]);
1520 smbc_file_table
[slot
] = NULL
;
1525 smbc_file_table
[slot
]->srv
= srv
;
1527 /* Now, list the stuff ... */
1529 if (!cli_NetServerEnum(&srv
->cli
, lp_workgroup(), 0x80000000, list_fn
,
1530 (void *)smbc_file_table
[slot
])) {
1532 if (smbc_file_table
[slot
]) free(smbc_file_table
[slot
]);
1533 smbc_file_table
[slot
] = NULL
;
1534 errno
= cli_error(&srv
->cli
, &eclass
, &ecode
, NULL
);
1539 else { /* Server not an empty string ... Check the rest and see what gives */
1541 if (share
[0] == (char)0) {
1543 if (path
[0] != (char)0) { /* Should not have empty share with path */
1546 if (smbc_file_table
[slot
]) free(smbc_file_table
[slot
]);
1547 smbc_file_table
[slot
] = NULL
;
1552 /* Check to see if <server><1D> translates, or <server><20> translates */
1554 if (resolve_name(server
, &rem_ip
, 0x1d)) { /* Found LMB */
1557 smbc_file_table
[slot
]->dir_type
= SMBC_SERVER
;
1560 * Get the backup list ...
1563 cli_get_backup_server(my_netbios_name
, server
, buserver
, sizeof(buserver
));
1566 * Get a connection to IPC$ on the server if we do not already have one
1569 srv
= smbc_server(buserver
, "IPC$", lp_workgroup(), user
, password
);
1573 if (smbc_file_table
[slot
]) free(smbc_file_table
[slot
]);
1574 smbc_file_table
[slot
] = NULL
; /* FIXME: Memory leaks ... */
1579 smbc_file_table
[slot
]->srv
= srv
;
1581 /* Now, list the servers ... */
1583 if (!cli_NetServerEnum(&srv
->cli
, server
, 0x0000FFFE, list_fn
,
1584 (void *)smbc_file_table
[slot
])) {
1586 if (smbc_file_table
[slot
]) free(smbc_file_table
[slot
]);
1587 smbc_file_table
[slot
] = NULL
;
1588 errno
= cli_error(&srv
->cli
, &eclass
, &ecode
, NULL
);
1596 if (resolve_name(server
, &rem_ip
, 0x20)) {
1598 /* Now, list the shares ... */
1600 smbc_file_table
[slot
]->dir_type
= SMBC_FILE_SHARE
;
1602 srv
= smbc_server(server
, "IPC$", lp_workgroup(), user
, password
);
1606 if (smbc_file_table
[slot
]) free(smbc_file_table
[slot
]);
1607 smbc_file_table
[slot
] = NULL
;
1612 smbc_file_table
[slot
]->srv
= srv
;
1614 /* Now, list the servers ... */
1616 if (cli_RNetShareEnum(&srv
->cli
, list_fn
,
1617 (void *)smbc_file_table
[slot
]) < 0) {
1619 errno
= cli_error(&srv
->cli
, &eclass
, &ecode
, NULL
);
1620 if (smbc_file_table
[slot
]) free(smbc_file_table
[slot
]);
1621 smbc_file_table
[slot
] = NULL
;
1630 if (smbc_file_table
[slot
]) free(smbc_file_table
[slot
]);
1631 smbc_file_table
[slot
] = NULL
;
1639 else { /* The server and share are specified ... work from there ... */
1641 /* Well, we connect to the server and list the directory */
1643 smbc_file_table
[slot
]->dir_type
= SMBC_FILE_SHARE
;
1645 srv
= smbc_server(server
, share
, lp_workgroup(), user
, password
);
1649 if (smbc_file_table
[slot
]) free(smbc_file_table
[slot
]);
1650 smbc_file_table
[slot
] = NULL
;
1655 smbc_file_table
[slot
]->srv
= srv
;
1657 /* Now, list the files ... */
1659 pstrcat(path
, "\\*");
1661 if (!cli_list(&srv
->cli
, path
, aDIR
| aSYSTEM
| aHIDDEN
, dir_list_fn
,
1662 (void *)smbc_file_table
[slot
])) {
1664 if (smbc_file_table
[slot
]) free(smbc_file_table
[slot
]);
1665 smbc_file_table
[slot
] = NULL
;
1666 errno
= smbc_errno(&srv
->cli
);
1674 return smbc_file_table
[slot
]->smbc_fd
;
1679 * Routine to close a directory
1682 int smbc_closedir(int fd
)
1684 struct smbc_file
*fe
;
1686 if (!smbc_initialized
) {
1693 if (fd
< smbc_start_fd
|| fd
>= (smbc_start_fd
+ smbc_max_fd
)) {
1700 fe
= smbc_file_table
[fd
- smbc_start_fd
];
1704 errno
= ENOENT
; /* FIXME: Is this correct */
1709 smbc_remove_dir(fe
); /* Clean it up */
1711 if (fe
) free(fe
); /* Free the space too */
1713 smbc_file_table
[fd
- smbc_start_fd
] = NULL
;
1720 * Routine to get a directory entry
1723 static char smbc_local_dirent
[512]; /* Make big enough */
1725 struct smbc_dirent
*smbc_readdir(unsigned int fd
)
1727 struct smbc_file
*fe
;
1728 struct smbc_dirent
*dirp
, *dirent
;
1730 /* Check that all is ok first ... */
1732 if (!smbc_initialized
) {
1739 if (fd
< smbc_start_fd
|| fd
>= (smbc_start_fd
+ smbc_max_fd
)) {
1746 fe
= smbc_file_table
[fd
- smbc_start_fd
];
1748 if (fe
->file
!= False
) { /* FIXME, should be dir, perhaps */
1759 dirent
= fe
->dir_next
->dirent
;
1768 /* Hmmm, do I even need to copy it? */
1770 bcopy(dirent
, smbc_local_dirent
, dirent
->dirlen
); /* Copy the dirent */
1772 dirp
= (struct smbc_dirent
*)smbc_local_dirent
;
1774 dirp
->comment
= (char *)(&dirp
->name
+ dirent
->namelen
+ 1);
1776 fe
->dir_next
= fe
->dir_next
->next
;
1778 return (struct smbc_dirent
*)smbc_local_dirent
;
1784 * Routine to get directory entries
1787 int smbc_getdents(unsigned int fd
, struct smbc_dirent
*dirp
, int count
)
1789 struct smbc_file
*fe
;
1790 struct smbc_dir_list
*dir
;
1791 int rem
= count
, reqd
;
1793 /* Check that all is ok first ... */
1795 if (!smbc_initialized
) {
1802 if (fd
< smbc_start_fd
|| fd
>= (smbc_start_fd
+ smbc_max_fd
)) {
1809 fe
= smbc_file_table
[fd
- smbc_start_fd
];
1811 if (fe
->file
!= False
) { /* FIXME, should be dir, perhaps */
1819 * Now, retrieve the number of entries that will fit in what was passed
1820 * We have to figure out if the info is in the list, or we need to
1821 * send a request to the server to get the info.
1824 while ((dir
= fe
->dir_next
)) {
1825 struct smbc_dirent
*dirent
;
1829 errno
= ENOENT
; /* Bad error */
1834 if (rem
< (reqd
= (sizeof(struct smbc_dirent
) + dir
->dirent
->namelen
+
1835 dir
->dirent
->commentlen
+ 1))) {
1837 if (rem
< count
) { /* We managed to copy something */
1843 else { /* Nothing copied ... */
1845 errno
= EINVAL
; /* Not enough space ... */
1852 dirent
= dir
->dirent
;
1854 bcopy(dirent
, dirp
, reqd
); /* Copy the data in ... */
1856 dirp
->comment
= (char *)(&dirp
->name
+ dirent
->namelen
+ 1);
1858 (char *)dirp
+= reqd
;
1862 fe
->dir_next
= dir
= dir
-> next
;
1873 * Routine to create a directory ...
1876 int smbc_mkdir(const char *fname
, mode_t mode
)
1878 struct smbc_server
*srv
;
1879 fstring server
, share
, user
, password
;
1882 if (!smbc_initialized
) {
1896 DEBUG(4, ("stat(%s)\n", fname
));
1898 smbc_parse_path(fname
, server
, share
, path
, user
, password
); /*FIXME, errors*/
1900 if (user
[0] == (char)0) pstrcpy(user
, smbc_user
);
1902 srv
= smbc_server(server
, share
, lp_workgroup(), user
, password
);
1906 return -1; /* errno set by smbc_server */
1910 /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
1912 mode = aDIR | aRONLY;
1915 else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
1917 if (strcmp(path, "\\") == 0) {
1919 mode = aDIR | aRONLY;
1925 smbc_stat_printjob(srv, path, &size, &m_time);
1926 c_time = a_time = m_time;
1931 if (!cli_mkdir(&srv
->cli
, path
)) {
1933 errno
= smbc_errno(&srv
->cli
);
1943 * Routine to remove a directory
1946 int smbc_rmdir(const char *fname
)
1948 struct smbc_server
*srv
;
1949 fstring server
, share
, user
, password
;
1952 if (!smbc_initialized
) {
1966 DEBUG(4, ("stat(%s)\n", fname
));
1968 smbc_parse_path(fname
, server
, share
, path
, user
, password
); /*FIXME, errors*/
1970 if (user
[0] == (char)0) pstrcpy(user
, smbc_user
);
1972 srv
= smbc_server(server
, share
, lp_workgroup(), user
, password
);
1976 return -1; /* errno set by smbc_server */
1980 /* if (strncmp(srv->cli.dev, "IPC", 3) == 0) {
1982 mode = aDIR | aRONLY;
1985 else if (strncmp(srv->cli.dev, "LPT", 3) == 0) {
1987 if (strcmp(path, "\\") == 0) {
1989 mode = aDIR | aRONLY;
1995 smbc_stat_printjob(srv, path, &size, &m_time);
1996 c_time = a_time = m_time;
2001 if (!cli_rmdir(&srv
->cli
, path
)) {
2003 errno
= smbc_errno(&srv
->cli
);
2013 * Routine to return the current directory position
2016 off_t
smbc_telldir(int fd
)
2018 struct smbc_file
*fe
;
2020 if (!smbc_initialized
) {
2027 if (fd
< smbc_start_fd
|| fd
>= (smbc_start_fd
+ smbc_max_fd
)) {
2034 fe
= smbc_file_table
[fd
- smbc_start_fd
];
2036 if (fe
->file
!= False
) { /* FIXME, should be dir, perhaps */
2043 return (off_t
) fe
->dir_next
;
2048 * Routine to seek on a directory
2051 int smbc_lseekdir(int fd
, off_t offset
, int whence
)
2054 if (!smbc_initialized
) {
2066 * Routine to fstat a dir
2069 int smbc_fstatdir(int fd
, struct stat
*st
)
2072 if (!smbc_initialized
) {