1 /* $NetBSD: smbfs_subr.c,v 1.13 2006/11/16 01:33:37 christos Exp $ */
4 * Copyright (c) 2000-2001, Boris Popov
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. All advertising materials mentioning features or use of this software
16 * must display the following acknowledgement:
17 * This product includes software developed by Boris Popov.
18 * 4. Neither the name of the author nor the names of any co-contributors
19 * may be used to endorse or promote products derived from this software
20 * without specific prior written permission.
22 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
23 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
26 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * FreeBSD: src/sys/fs/smbfs/smbfs_subr.c,v 1.1 2001/04/10 07:59:05 bp Exp
37 #include <sys/cdefs.h>
38 __KERNEL_RCSID(0, "$NetBSD: smbfs_subr.c,v 1.13 2006/11/16 01:33:37 christos Exp $");
40 #include <sys/param.h>
41 #include <sys/systm.h>
42 #include <sys/kernel.h>
43 #include <sys/malloc.h>
44 #include <sys/mount.h>
46 #include <sys/vnode.h>
47 #include <sys/sysctl.h>
48 #include <netsmb/iconv.h>
50 #include <netsmb/smb.h>
51 #include <netsmb/smb_conn.h>
52 #include <netsmb/smb_subr.h>
53 #include <netsmb/smb_rq.h>
54 #include <netsmb/smb_dev.h>
56 #include <fs/smbfs/smbfs.h>
57 #include <fs/smbfs/smbfs_node.h>
58 #include <fs/smbfs/smbfs_subr.h>
60 MALLOC_JUSTDEFINE(M_SMBFSDATA
, "SMBFS data", "SMBFS private data");
63 * Time & date conversion routines taken from msdosfs. Although leap
64 * year calculation is bogus, it's sufficient before 2100 :)
67 * This is the format of the contents of the deTime field in the direntry
69 * We don't use bitfields because we don't know how compilers for
70 * arbitrary machines will lay them out.
72 #define DT_2SECONDS_MASK 0x1F /* seconds divided by 2 */
73 #define DT_2SECONDS_SHIFT 0
74 #define DT_MINUTES_MASK 0x7E0 /* minutes */
75 #define DT_MINUTES_SHIFT 5
76 #define DT_HOURS_MASK 0xF800 /* hours */
77 #define DT_HOURS_SHIFT 11
80 * This is the format of the contents of the deDate field in the direntry
83 #define DD_DAY_MASK 0x1F /* day of month */
84 #define DD_DAY_SHIFT 0
85 #define DD_MONTH_MASK 0x1E0 /* month */
86 #define DD_MONTH_SHIFT 5
87 #define DD_YEAR_MASK 0xFE00 /* year - 1980 */
88 #define DD_YEAR_SHIFT 9
90 * Total number of days that have passed for each month in a regular year.
92 static const u_short regyear
[] = {
93 31, 59, 90, 120, 151, 181,
94 212, 243, 273, 304, 334, 365
98 * Total number of days that have passed for each month in a leap year.
100 static const u_short leapyear
[] = {
101 31, 60, 91, 121, 152, 182,
102 213, 244, 274, 305, 335, 366
106 * Variables used to remember parts of the last time conversion. Maybe we
107 * can avoid a full conversion.
109 static u_long lasttime
;
110 static u_long lastday
;
111 static u_short lastddate
;
112 static u_short lastdtime
;
115 smb_time_local2server(struct timespec
*tsp
, int tzoff
, u_long
*seconds
)
117 *seconds
= tsp
->tv_sec
- tzoff
* 60 /*- tz.tz_minuteswest * 60 -
118 (wall_cmos_clock ? adjkerntz : 0)*/;
122 smb_time_server2local(u_long seconds
, int tzoff
, struct timespec
*tsp
)
124 tsp
->tv_sec
= seconds
+ tzoff
* 60;
125 /*+ tz.tz_minuteswest * 60 + (wall_cmos_clock ? adjkerntz : 0)*/;
129 * Number of seconds between 1970 and 1601 year
131 static const int64_t DIFF1970TO1601
= 11644473600ULL;
134 * Time from server comes as UTC, so no need to use tz
137 smb_time_NT2local(int64_t nsec
, int tzoff
, struct timespec
*tsp
)
139 smb_time_server2local(nsec
/ 10000000 - DIFF1970TO1601
, 0, tsp
);
143 smb_time_local2NT(struct timespec
*tsp
, int tzoff
, int64_t *nsec
)
147 smb_time_local2server(tsp
, 0, &seconds
);
148 *nsec
= (((int64_t)(seconds
) & ~1) + DIFF1970TO1601
) * (int64_t)10000000;
152 smb_time_unix2dos(struct timespec
*tsp
, int tzoff
, u_int16_t
*ddp
,
153 u_int16_t
*dtp
, u_int8_t
*dhp
)
155 u_long t
, days
, year
, month
, inc
;
156 const u_short
*months
;
159 * If the time from the last conversion is the same as now, then
160 * skip the computations and use the saved result.
162 smb_time_local2server(tsp
, tzoff
, &t
);
166 lastdtime
= (((t
/ 2) % 30) << DT_2SECONDS_SHIFT
)
167 + (((t
/ 60) % 60) << DT_MINUTES_SHIFT
)
168 + (((t
/ 3600) % 24) << DT_HOURS_SHIFT
);
171 * If the number of days since 1970 is the same as the last
172 * time we did the computation then skip all this leap year
175 days
= t
/ (24 * 60 * 60);
176 if (days
!= lastday
) {
178 for (year
= 1970;; year
++) {
179 inc
= year
& 0x03 ? 365 : 366;
184 months
= year
& 0x03 ? regyear
: leapyear
;
185 for (month
= 0; days
>= months
[month
]; month
++)
188 days
-= months
[month
- 1];
189 lastddate
= ((days
+ 1) << DD_DAY_SHIFT
)
190 + ((month
+ 1) << DD_MONTH_SHIFT
);
192 * Remember dos's idea of time is relative to 1980.
193 * unix's is relative to 1970. If somehow we get a
194 * time before 1980 then don't give totally crazy
198 lastddate
+= (year
- 1980) << DD_YEAR_SHIFT
;
204 *dhp
= (tsp
->tv_sec
& 1) * 100 + tsp
->tv_nsec
/ 10000000;
210 * The number of seconds between Jan 1, 1970 and Jan 1, 1980. In that
211 * interval there were 8 regular years and 2 leap years.
213 #define SECONDSTO1980 (((8 * 365) + (2 * 366)) * (24 * 60 * 60))
215 static u_short lastdosdate
;
216 static u_long lastseconds
;
219 smb_dos2unixtime(u_int dd
, u_int dt
, u_int dh
, int tzoff
,
220 struct timespec
*tsp
)
226 const u_short
*months
;
233 seconds
= (((dt
& DT_2SECONDS_MASK
) >> DT_2SECONDS_SHIFT
) << 1)
234 + ((dt
& DT_MINUTES_MASK
) >> DT_MINUTES_SHIFT
) * 60
235 + ((dt
& DT_HOURS_MASK
) >> DT_HOURS_SHIFT
) * 3600
238 * If the year, month, and day from the last conversion are the
239 * same then use the saved value.
241 if (lastdosdate
!= dd
) {
244 year
= (dd
& DD_YEAR_MASK
) >> DD_YEAR_SHIFT
;
246 days
+= year
/ 4 + 1; /* add in leap days */
247 if ((year
& 0x03) == 0)
248 days
--; /* if year is a leap year */
249 months
= year
& 0x03 ? regyear
: leapyear
;
250 month
= (dd
& DD_MONTH_MASK
) >> DD_MONTH_SHIFT
;
251 if (month
< 1 || month
> 12) {
255 days
+= months
[month
- 2];
256 days
+= ((dd
& DD_DAY_MASK
) >> DD_DAY_SHIFT
) - 1;
257 lastseconds
= (days
* 24 * 60 * 60) + SECONDSTO1980
;
259 smb_time_server2local(seconds
+ lastseconds
, tzoff
, tsp
);
260 tsp
->tv_nsec
= (dh
% 100) * 10000000;
264 smb_fphelp(struct mbchain
*mbp
, struct smb_vc
*vcp
, struct smbnode
*np
,
267 struct smbmount
*smp
= np
->n_mount
;
268 struct smbnode
**npp
= smp
->sm_npstack
;
271 /* simple_lock(&smp->sm_npslock);*/
273 while (np
->n_parent
) {
274 if (i
++ == SMBFS_MAXPATHCOMP
) {
275 /* simple_unlock(&smp->sm_npslock);*/
279 np
= VTOSMB(np
->n_parent
);
283 error
= mb_put_uint8(mbp
, '\\');
286 error
= smb_put_dmem(mbp
, vcp
, np
->n_name
, np
->n_nmlen
, caseopt
);
290 /* simple_unlock(&smp->sm_npslock);*/
295 smbfs_fullpath(struct mbchain
*mbp
, struct smb_vc
*vcp
, struct smbnode
*dnp
,
296 const char *name
, int nmlen
)
298 int caseopt
= SMB_CS_NONE
;
301 if (SMB_DIALECT(vcp
) < SMB_DIALECT_LANMAN1_0
)
302 caseopt
|= SMB_CS_UPPER
;
304 error
= smb_fphelp(mbp
, vcp
, dnp
, caseopt
);
309 error
= mb_put_uint8(mbp
, '\\');
312 error
= smb_put_dmem(mbp
, vcp
, name
, nmlen
, caseopt
);
316 error
= mb_put_uint8(mbp
, 0);
321 smbfs_fname_tolocal(struct smb_vc
*vcp
, char *name
, int nmlen
,
324 /* if (caseopt & SMB_CS_UPPER)
325 iconv_convmem(vcp->vc_toupper, name, name, nmlen);
326 else if (caseopt & SMB_CS_LOWER)
327 iconv_convmem(vcp->vc_tolower, name, name, nmlen);*/
329 iconv_convmem(vcp
->vc_tolocal
, name
, name
, nmlen
);