1/*
2   Unix SMB/CIFS implementation.
3   SMB wrapper stat functions
4   Copyright (C) Andrew Tridgell 1998
5
6   This program is free software; you can redistribute it and/or modify
7   it under the terms of the GNU General Public License as published by
8   the Free Software Foundation; either version 2 of the License, or
9   (at your option) any later version.
10
11   This program is distributed in the hope that it will be useful,
12   but WITHOUT ANY WARRANTY; without even the implied warranty of
13   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14   GNU General Public License for more details.
15
16   You should have received a copy of the GNU General Public License
17   along with this program; if not, write to the Free Software
18   Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
19*/
20
21#include "includes.h"
22
23extern int smbw_busy;
24
25/*****************************************************
26setup basic info in a stat structure
27*******************************************************/
28void smbw_setup_stat(struct stat *st, char *fname, size_t size, int mode)
29{
30	st->st_mode = 0;
31
32	if (IS_DOS_DIR(mode)) {
33		st->st_mode = SMBW_DIR_MODE;
34	} else {
35		st->st_mode = SMBW_FILE_MODE;
36	}
37
38	if (IS_DOS_ARCHIVE(mode)) st->st_mode |= S_IXUSR;
39	if (IS_DOS_SYSTEM(mode)) st->st_mode |= S_IXGRP;
40	if (IS_DOS_HIDDEN(mode)) st->st_mode |= S_IXOTH;
41	if (!IS_DOS_READONLY(mode)) st->st_mode |= S_IWUSR;
42
43	st->st_size = size;
44#ifdef HAVE_STAT_ST_BLKSIZE
45	st->st_blksize = 512;
46#endif
47#ifdef HAVE_STAT_ST_BLOCKS
48	st->st_blocks = (size+511)/512;
49#endif
50	st->st_uid = getuid();
51	st->st_gid = getgid();
52	if (IS_DOS_DIR(mode)) {
53		st->st_nlink = 2;
54	} else {
55		st->st_nlink = 1;
56	}
57	if (st->st_ino == 0) {
58		st->st_ino = smbw_inode(fname);
59	}
60}
61
62
63/*****************************************************
64try to do a QPATHINFO and if that fails then do a getatr
65this is needed because win95 sometimes refuses the qpathinfo
66*******************************************************/
67BOOL smbw_getatr(struct smbw_server *srv, char *path,
68		 uint16 *mode, size_t *size,
69		 time_t *c_time, time_t *a_time, time_t *m_time,
70		 SMB_INO_T *ino)
71{
72	DEBUG(4,("sending qpathinfo\n"));
73
74	if (!srv->no_pathinfo2 &&
75	    cli_qpathinfo2(&srv->cli, path, c_time, a_time, m_time, NULL,
76			   size, mode, ino)) return True;
77
78	/* if this is NT then don't bother with the getatr */
79	if (srv->cli.capabilities & CAP_NT_SMBS) return False;
80
81	if (cli_getatr(&srv->cli, path, mode, size, m_time)) {
82		a_time = c_time = m_time;
83		srv->no_pathinfo2 = True;
84		return True;
85	}
86	return False;
87}
88
89
90static struct print_job_info printjob;
91
92/*****************************************************
93gather info from a printjob listing
94*******************************************************/
95static void smbw_printjob_stat(struct print_job_info *job)
96{
97	if (strcmp(job->name, printjob.name) == 0) {
98		printjob = *job;
99	}
100}
101
102/*****************************************************
103stat a printjob
104*******************************************************/
105int smbw_stat_printjob(struct smbw_server *srv,char *path,
106		       size_t *size, time_t *m_time)
107{
108	if (path[0] == '\\') path++;
109
110	ZERO_STRUCT(printjob);
111
112	fstrcpy(printjob.name, path);
113	cli_print_queue(&srv->cli, smbw_printjob_stat);
114
115	if (size) {
116		*size = printjob.size;
117	}
118	if (m_time) {
119		*m_time = printjob.t;
120	}
121	return printjob.id;
122}
123
124
125/*****************************************************
126a wrapper for fstat()
127*******************************************************/
128int smbw_fstat(int fd, struct stat *st)
129{
130	struct smbw_file *file;
131	time_t c_time, a_time, m_time;
132	size_t size;
133	uint16 mode;
134	SMB_INO_T ino = 0;
135
136	smbw_busy++;
137
138	ZERO_STRUCTP(st);
139
140	file = smbw_file(fd);
141	if (!file) {
142		int ret = smbw_dir_fstat(fd, st);
143		smbw_busy--;
144		return ret;
145	}
146
147	if (!cli_qfileinfo(&file->srv->cli, file->f->cli_fd,
148			   &mode, &size, &c_time, &a_time, &m_time, NULL,
149			   &ino) &&
150	    !cli_getattrE(&file->srv->cli, file->f->cli_fd,
151			  &mode, &size, &c_time, &a_time, &m_time)) {
152		errno = EINVAL;
153		smbw_busy--;
154		return -1;
155	}
156
157	st->st_ino = ino;
158
159	smbw_setup_stat(st, file->f->fname, size, mode);
160
161	st->st_atime = a_time;
162	st->st_ctime = c_time;
163	st->st_mtime = m_time;
164	st->st_dev = file->srv->dev;
165
166	smbw_busy--;
167	return 0;
168}
169
170
171/*****************************************************
172a wrapper for stat()
173*******************************************************/
174int smbw_stat(const char *fname, struct stat *st)
175{
176	struct smbw_server *srv;
177	fstring server, share;
178	pstring path;
179	time_t m_time=0, a_time=0, c_time=0;
180	size_t size=0;
181	uint16 mode=0;
182	SMB_INO_T ino = 0;
183	int result = 0;
184
185	ZERO_STRUCTP(st);
186
187	if (!fname) {
188		errno = EINVAL;
189		return -1;
190	}
191
192	DEBUG(4,("stat(%s)\n", fname));
193
194	smbw_init();
195
196	smbw_busy++;
197
198	/* work out what server they are after */
199	smbw_parse_path(fname, server, share, path);
200
201	/* get a connection to the server */
202	srv = smbw_server(server, share);
203	if (!srv) {
204
205		/* For shares we aren't allowed to connect to, or no master
206		   browser found, return an empty directory */
207
208		if ((server[0] && share[0] && !path[0] && errno == EACCES) ||
209		    (!path[0] && errno == ENOENT)) {
210			mode = aDIR | aRONLY;
211			smbw_setup_stat(st, path, size, mode);
212			goto done;
213		}
214
215		/* smbw_server sets errno */
216		result = -1;
217		goto done;
218	}
219
220	DEBUG(4,("smbw_stat\n"));
221
222	if (strncmp(srv->cli.dev,"IPC",3) == 0) {
223		mode = aDIR | aRONLY;
224	} else if (strncmp(srv->cli.dev,"LPT",3) == 0) {
225		if (strcmp(path,"\\") == 0) {
226			mode = aDIR | aRONLY;
227		} else {
228			mode = aRONLY;
229			smbw_stat_printjob(srv, path, &size, &m_time);
230			c_time = a_time = m_time;
231		}
232	} else {
233		if (!smbw_getatr(srv, path,
234				 &mode, &size, &c_time, &a_time, &m_time,
235				 &ino)) {
236			errno = smbw_errno(&srv->cli);
237			result = -1;
238			goto done;
239		}
240	}
241
242	st->st_ino = ino;
243
244	smbw_setup_stat(st, path, size, mode);
245
246	st->st_atime = a_time;
247	st->st_ctime = c_time;
248	st->st_mtime = m_time;
249	st->st_dev = srv->dev;
250
251 done:
252	smbw_busy--;
253	return result;
254}
255