2 * Copyright (c) 2000-2001, Boris Popov
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by Boris Popov.
16 * 4. Neither the name of the author nor the names of any co-contributors
17 * may be used to endorse or promote products derived from this software
18 * without specific prior written permission.
20 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
21 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
24 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32 * $FreeBSD: src/sys/fs/smbfs/smbfs_subr.c,v 1.1.2.2 2003/01/17 08:20:26 tjr Exp $
33 * $DragonFly: src/sys/vfs/smbfs/smbfs_subr.c,v 1.4 2003/08/07 21:54:36 dillon Exp $
35 #include <sys/param.h>
36 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/malloc.h>
39 #include <machine/clock.h>
41 #include <sys/vnode.h>
42 #include <sys/sysctl.h>
43 #include <sys/iconv.h>
45 #include <netproto/smb/smb.h>
46 #include <netproto/smb/smb_conn.h>
47 #include <netproto/smb/smb_subr.h>
48 #include <netproto/smb/smb_rq.h>
49 #include <netproto/smb/smb_dev.h>
52 #include "smbfs_node.h"
53 #include "smbfs_subr.h"
55 MALLOC_DEFINE(M_SMBFSDATA
, "SMBFS data", "SMBFS private data");
58 * Time & date conversion routines taken from msdosfs. Although leap
59 * year calculation is bogus, it's sufficient before 2100 :)
62 * This is the format of the contents of the deTime field in the direntry
64 * We don't use bitfields because we don't know how compilers for
65 * arbitrary machines will lay them out.
67 #define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */
68 #define DT_2SECONDS_SHIFT 0
69 #define DT_MINUTES_MASK 0x7E0 /* minutes */
70 #define DT_MINUTES_SHIFT 5
71 #define DT_HOURS_MASK 0xF800 /* hours */
72 #define DT_HOURS_SHIFT 11
75 * This is the format of the contents of the deDate field in the direntry
78 #define DD_DAY_MASK 0x1F /* day of month */
79 #define DD_DAY_SHIFT 0
80 #define DD_MONTH_MASK 0x1E0 /* month */
81 #define DD_MONTH_SHIFT 5
82 #define DD_YEAR_MASK 0xFE00 /* year - 1980 */
83 #define DD_YEAR_SHIFT 9
85 * Total number of days that have passed for each month in a regular year.
87 static u_short regyear
[] = {
88 31, 59, 90, 120, 151, 181,
89 212, 243, 273, 304, 334, 365
93 * Total number of days that have passed for each month in a leap year.
95 static u_short leapyear
[] = {
96 31, 60, 91, 121, 152, 182,
97 213, 244, 274, 305, 335, 366
101 * Variables used to remember parts of the last time conversion. Maybe we
102 * can avoid a full conversion.
104 static u_long lasttime
;
105 static u_long lastday
;
106 static u_short lastddate
;
107 static u_short lastdtime
;
110 smb_time_local2server(struct timespec
*tsp
, int tzoff
, u_long
*seconds
)
112 *seconds
= tsp
->tv_sec
- tzoff
* 60 /*- tz.tz_minuteswest * 60 -
113 (wall_cmos_clock ? adjkerntz : 0)*/;
117 smb_time_server2local(u_long seconds
, int tzoff
, struct timespec
*tsp
)
119 tsp
->tv_sec
= seconds
+ tzoff
* 60;
120 /*+ tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0)*/;
124 * Number of seconds between 1970 and 1601 year
126 int64_t DIFF1970TO1601
= 11644473600ULL;
129 * Time from server comes as UTC, so no need to use tz
132 smb_time_NT2local(int64_t nsec
, int tzoff
, struct timespec
*tsp
)
134 smb_time_server2local(nsec
/ 10000000 - DIFF1970TO1601
, 0, tsp
);
138 smb_time_local2NT(struct timespec
*tsp
, int tzoff
, int64_t *nsec
)
142 smb_time_local2server(tsp
, 0, &seconds
);
143 *nsec
= (((int64_t)(seconds
) & ~1) + DIFF1970TO1601
) * (int64_t)10000000;
147 smb_time_unix2dos(struct timespec
*tsp
, int tzoff
, u_int16_t
*ddp
,
148 u_int16_t
*dtp
, u_int8_t
*dhp
)
150 u_long t
, days
, year
, month
, inc
;
154 * If the time from the last conversion is the same as now, then
155 * skip the computations and use the saved result.
157 smb_time_local2server(tsp
, tzoff
, &t
);
161 lastdtime
= (((t
/ 2) % 30) << DT_2SECONDS_SHIFT
)
162 + (((t
/ 60) % 60) << DT_MINUTES_SHIFT
)
163 + (((t
/ 3600) % 24) << DT_HOURS_SHIFT
);
166 * If the number of days since 1970 is the same as the last
167 * time we did the computation then skip all this leap year
170 days
= t
/ (24 * 60 * 60);
171 if (days
!= lastday
) {
173 for (year
= 1970;; year
++) {
174 inc
= year
& 0x03 ? 365 : 366;
179 months
= year
& 0x03 ? regyear
: leapyear
;
180 for (month
= 0; days
>= months
[month
]; month
++)
183 days
-= months
[month
- 1];
184 lastddate
= ((days
+ 1) << DD_DAY_SHIFT
)
185 + ((month
+ 1) << DD_MONTH_SHIFT
);
187 * Remember dos's idea of time is relative to 1980.
188 * unix's is relative to 1970. If somehow we get a
189 * time before 1980 then don't give totally crazy
193 lastddate
+= (year
- 1980) << DD_YEAR_SHIFT
;
199 *dhp
= (tsp
->tv_sec
& 1) * 100 + tsp
->tv_nsec
/ 10000000;
205 * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
206 * interval there were 8 regular years and 2 leap years.
208 #define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
210 static u_short lastdosdate
;
211 static u_long lastseconds
;
214 smb_dos2unixtime(u_int dd
, u_int dt
, u_int dh
, int tzoff
,
215 struct timespec
*tsp
)
228 seconds
= (((dt
& DT_2SECONDS_MASK
) >> DT_2SECONDS_SHIFT
) << 1)
229 + ((dt
& DT_MINUTES_MASK
) >> DT_MINUTES_SHIFT
) * 60
230 + ((dt
& DT_HOURS_MASK
) >> DT_HOURS_SHIFT
) * 3600
233 * If the year, month, and day from the last conversion are the
234 * same then use the saved value.
236 if (lastdosdate
!= dd
) {
239 year
= (dd
& DD_YEAR_MASK
) >> DD_YEAR_SHIFT
;
241 days
+= year
/ 4 + 1; /* add in leap days */
242 if ((year
& 0x03) == 0)
243 days
--; /* if year is a leap year */
244 months
= year
& 0x03 ? regyear
: leapyear
;
245 month
= (dd
& DD_MONTH_MASK
) >> DD_MONTH_SHIFT
;
246 if (month
< 1 || month
> 12) {
250 days
+= months
[month
- 2];
251 days
+= ((dd
& DD_DAY_MASK
) >> DD_DAY_SHIFT
) - 1;
252 lastseconds
= (days
* 24 * 60 * 60) + SECONDSTO1980
;
254 smb_time_server2local(seconds
+ lastseconds
, tzoff
, tsp
);
255 tsp
->tv_nsec
= (dh
% 100) * 10000000;
259 smb_fphelp(struct mbchain
*mbp
, struct smb_vc
*vcp
, struct smbnode
*np
,
262 struct smbmount
*smp
= np
->n_mount
;
263 struct smbnode
**npp
= smp
->sm_npstack
;
266 /* simple_lock(&smp->sm_npslock);*/
268 while (np
->n_parent
) {
269 if (i
++ == SMBFS_MAXPATHCOMP
) {
270 /* simple_unlock(&smp->sm_npslock);*/
274 np
= VTOSMB(np
->n_parent
);
277 return smb_put_dmem(mbp, vcp, "\\", 2, caseopt);*/
280 error
= mb_put_uint8(mbp
, '\\');
283 error
= smb_put_dmem(mbp
, vcp
, np
->n_name
, np
->n_nmlen
, caseopt
);
287 /* simple_unlock(&smp->sm_npslock);*/
292 smbfs_fullpath(struct mbchain
*mbp
, struct smb_vc
*vcp
, struct smbnode
*dnp
,
293 const char *name
, int nmlen
)
295 int caseopt
= SMB_CS_NONE
;
298 if (SMB_DIALECT(vcp
) < SMB_DIALECT_LANMAN1_0
)
299 caseopt
|= SMB_CS_UPPER
;
301 error
= smb_fphelp(mbp
, vcp
, dnp
, caseopt
);
306 error
= mb_put_uint8(mbp
, '\\');
309 error
= smb_put_dmem(mbp
, vcp
, name
, nmlen
, caseopt
);
313 error
= mb_put_uint8(mbp
, 0);
318 smbfs_fname_tolocal(struct smb_vc
*vcp
, char *name
, int nmlen
, int caseopt
)
320 /* if (caseopt & SMB_CS_UPPER)
321 iconv_convmem(vcp->vc_toupper, name, name, nmlen);
322 else if (caseopt & SMB_CS_LOWER)
323 iconv_convmem(vcp->vc_tolower, name, name, nmlen);*/
325 iconv_convmem(vcp
->vc_tolocal
, name
, name
, nmlen
);