]> CyberLeo.Net >> Repos - FreeBSD/releng/9.2.git/blob - sys/fs/nwfs/nwfs_subr.c
- Copy stable/9 to releng/9.2 as part of the 9.2-RELEASE cycle.
[FreeBSD/releng/9.2.git] / sys / fs / nwfs / nwfs_subr.c
1 /*-
2  * Copyright (c) 1999, 2001 Boris Popov
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
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  *
14  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24  * SUCH DAMAGE.
25  *
26  * $FreeBSD$
27  */
28 #include <sys/param.h>
29 #include <sys/systm.h>
30 #include <sys/kernel.h>
31 #include <sys/lock.h>
32 #include <sys/lockmgr.h>
33 #include <sys/malloc.h>
34 #include <sys/clock.h>
35 #include <sys/time.h>
36
37 #include <netncp/ncp.h>
38 #include <netncp/ncp_conn.h>
39 #include <netncp/ncp_ncp.h>
40 #include <netncp/ncp_subr.h>
41 #include <netncp/ncp_rq.h>
42 #include <netncp/nwerror.h>
43
44 #include <fs/nwfs/nwfs.h>
45 #include <fs/nwfs/nwfs_node.h>
46 #include <fs/nwfs/nwfs_subr.h>
47
48 #define NCP_INFOSZ      (sizeof(struct nw_entry_info) - 257)
49
50 MALLOC_DEFINE(M_NWFSDATA, "nwfs_data", "NWFS private data");
51
52 static int
53 ncp_extract_file_info(struct nwmount *nmp, struct ncp_rq *rqp,
54         struct nw_entry_info *target, int withname)
55 {
56         u_int8_t name_len;
57
58         md_get_mem(&rqp->rp, (caddr_t)target, NCP_INFOSZ, MB_MSYSTEM);
59         if (!withname)
60                 return 0;
61         md_get_uint8(&rqp->rp, &name_len);
62         target->nameLen = name_len;
63         md_get_mem(&rqp->rp, (caddr_t)target->entryName, name_len, MB_MSYSTEM);
64         target->entryName[name_len] = '\0';
65         ncp_path2unix(target->entryName, target->entryName, name_len, &nmp->m.nls);
66         return 0;
67 }
68
69 int
70 ncp_initsearch(struct vnode *dvp, struct thread *td, struct ucred *cred)
71 {
72         struct nwmount *nmp = VTONWFS(dvp);
73         struct ncp_conn *conn = NWFSTOCONN(nmp);
74         struct nwnode *np = VTONW(dvp);
75         struct ncp_rq *rqp;
76         u_int8_t volnum = nmp->n_volume;
77         u_int32_t dirent = np->n_fid.f_id;
78         int error;
79
80         NCPNDEBUG("vol=%d,dir=%d\n", volnum, dirent);
81         error = ncp_rq_alloc(87, conn, td, cred, &rqp);
82         if (error)
83                 return error;
84         mb_put_uint8(&rqp->rq, 2);              /* subfunction */
85         mb_put_uint8(&rqp->rq, nmp->name_space);
86         mb_put_uint8(&rqp->rq, 0);              /* reserved */
87         ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL);
88         rqp->nr_minrplen = sizeof(np->n_seq);
89         error = ncp_request(rqp);
90         if (error)
91                 return error;
92         md_get_mem(&rqp->rp, (caddr_t)&np->n_seq, sizeof(np->n_seq), MB_MSYSTEM);
93         ncp_rq_done(rqp);
94         return 0;
95 }
96
97 int 
98 ncp_search_for_file_or_subdir(struct nwmount *nmp,
99                               struct nw_search_seq *seq,
100                               struct nw_entry_info *target,
101                               struct thread *td,struct ucred *cred)
102 {
103         struct ncp_conn *conn = NWFSTOCONN(nmp);
104         struct ncp_rq *rqp;
105         int error;
106
107         error = ncp_rq_alloc(87, conn, td, cred, &rqp);
108         if (error)
109                 return error;
110         mb_put_uint8(&rqp->rq, 3);              /* subfunction */
111         mb_put_uint8(&rqp->rq, nmp->name_space);
112         mb_put_uint8(&rqp->rq, 0);              /* data stream */
113         mb_put_uint16le(&rqp->rq, 0xffff);      /* Search attribs */
114         mb_put_uint32le(&rqp->rq, IM_ALL);      /* return info mask */
115         mb_put_mem(&rqp->rq, (caddr_t)seq, 9, MB_MSYSTEM);
116         mb_put_uint8(&rqp->rq, 2);              /* 2 byte pattern */
117         mb_put_uint8(&rqp->rq, 0xff);           /* following is a wildcard */
118         mb_put_uint8(&rqp->rq, '*');
119         rqp->nr_minrplen = sizeof(*seq) +  1 + NCP_INFOSZ + 1;
120         error = ncp_request(rqp);
121         if (error)
122                 return error;
123         md_get_mem(&rqp->rp, (caddr_t)seq, sizeof(*seq), MB_MSYSTEM);
124         md_get_uint8(&rqp->rp, NULL);           /* skip */
125         error = ncp_extract_file_info(nmp, rqp, target, 1);
126         ncp_rq_done(rqp);
127         return error;
128 }
129
130 /*
131  * Returns information for a (one-component) name relative to the specified
132  * directory.
133  */
134 int 
135 ncp_obtain_info(struct nwmount *nmp,  u_int32_t dirent,
136                 int namelen, char *path, struct nw_entry_info *target,
137                 struct thread *td,struct ucred *cred)
138 {
139         struct ncp_conn *conn=NWFSTOCONN(nmp);
140         struct ncp_rq *rqp;
141         int error;
142         u_char volnum = nmp->n_volume, ns;
143
144         if (target == NULL) {
145                 NCPFATAL("target == NULL\n");
146                 return EINVAL;
147         }
148         ns = (path == NULL || path[0] == 0) ? NW_NS_DOS : nmp->name_space;
149         error = ncp_rq_alloc(87, conn, td, cred, &rqp);
150         if (error)
151                 return error;
152         mb_put_uint8(&rqp->rq, 6);      /* subfunction */
153         mb_put_uint8(&rqp->rq, ns);
154         mb_put_uint8(&rqp->rq, ns);     /* DestNameSpace */
155         mb_put_uint16le(&rqp->rq, 0xff);        /* get all */
156         mb_put_uint32le(&rqp->rq, IM_ALL);
157         ncp_rq_dbase_path(rqp, volnum, dirent, namelen, path, &nmp->m.nls);
158         error = ncp_request(rqp);
159         if (error)
160                 return error;
161         error = ncp_extract_file_info(nmp, rqp, target, path != NULL);
162         ncp_rq_done(rqp);
163         return error;
164 }
165 /* 
166  * lookup name pointed by cnp in directory dvp and return file info in np.
167  * May be I should create a little cache, but another way is to minimize
168  * number of calls, on other hand, in multiprocess environment ...
169  */
170 int
171 ncp_lookup(struct vnode *dvp, int len, char *name, struct nw_entry_info *fap,
172                 struct thread *td,struct ucred *cred)
173 {
174         struct nwmount *nmp;
175         struct nwnode *dnp;
176         int error;
177
178         if (!dvp || dvp->v_type != VDIR) {
179                 nwfs_printf("dvp is NULL or not a directory.\n");
180                 return (ENOENT);
181         }
182         dnp = VTONW(dvp);
183         nmp = VTONWFS(dvp);
184
185         if (len == 1 && name[0] == '.') {
186                 if (dnp->n_flag & NVOLUME) {
187                         error = ncp_obtain_info(nmp, dnp->n_fid.f_id, 0, NULL,
188                                 fap, td, cred);
189                 } else {
190                         error = ncp_obtain_info(nmp, dnp->n_fid.f_parent, 
191                                 dnp->n_nmlen, dnp->n_name, fap, td, cred);
192                 }
193                 return error;
194         } else if (len == 2 && name[0] == '.' && name[1] == '.') {
195                 printf("%s: knows NOTHING about '..'\n", __func__);
196                 return EIO;
197         } else {
198                 error = ncp_obtain_info(nmp, dnp->n_fid.f_id, 
199                         len, name, fap, td, cred);
200         }
201         return error;
202 }
203
204 static void ConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh);
205 static void 
206 ConvertToNWfromDWORD(u_int32_t sfd, ncp_fh *fh) {
207         fh->val1 = (fh->val.val32 = sfd);
208         return;
209 }
210
211 /*
212  * If both dir and name are NULL, then in target there's already a looked-up
213  * entry that wants to be opened.
214  */
215 int 
216 ncp_open_create_file_or_subdir(struct nwmount *nmp,struct vnode *dvp,int namelen,
217             char *name, int open_create_mode, u_int32_t create_attributes,
218             int desired_acc_rights, struct ncp_open_info *nop,
219             struct thread *td,struct ucred *cred)
220 {
221         
222         struct ncp_conn *conn=NWFSTOCONN(nmp);
223         struct ncp_rq *rqp;
224         u_int16_t search_attribs = SA_ALL & (~SA_SUBDIR_FILES);
225         u_int8_t volnum;
226         u_int32_t dirent;
227         int error;
228
229         error = ncp_rq_alloc(87, conn, td, cred, &rqp);
230         if (error)
231                 return error;
232         volnum = nmp->n_volume;
233         dirent = VTONW(dvp)->n_fid.f_id;
234         if ((create_attributes & aDIR) != 0) {
235                 search_attribs |= SA_SUBDIR_FILES;
236         }
237         mb_put_uint8(&rqp->rq, 1);/* subfunction */
238         mb_put_uint8(&rqp->rq, nmp->name_space);
239         mb_put_uint8(&rqp->rq, open_create_mode);
240         mb_put_uint16le(&rqp->rq, search_attribs);
241         mb_put_uint32le(&rqp->rq, IM_ALL);
242         mb_put_uint32le(&rqp->rq, create_attributes);
243         /*
244          * The desired acc rights seem to be the inherited rights mask for
245          * directories
246          */
247         mb_put_uint16le(&rqp->rq, desired_acc_rights);
248         ncp_rq_dbase_path(rqp, volnum, dirent, namelen, name, &nmp->m.nls);
249         error = ncp_request(rqp);
250         if (error) {
251                 if (error == NWE_FILE_NO_CREATE_PRIV)
252                         error = EACCES;
253                 return error;
254         }
255         md_get_uint32le(&rqp->rp, &nop->origfh);
256         md_get_uint8(&rqp->rp, &nop->action);
257         md_get_uint8(&rqp->rp, NULL);   /* skip */
258         error = ncp_extract_file_info(nmp, rqp, &nop->fattr, 1);
259         ncp_rq_done(rqp);
260         ConvertToNWfromDWORD(nop->origfh, &nop->fh);
261         return error;
262 }
263
264 int
265 ncp_close_file(struct ncp_conn *conn, ncp_fh *fh,struct thread *td,struct ucred *cred)
266 {
267         struct ncp_rq *rqp;
268         int error;
269
270         error = ncp_rq_alloc(66, conn, td, cred, &rqp);
271         if (error)
272                 return error;
273         mb_put_uint8(&rqp->rq, 0);
274         mb_put_mem(&rqp->rq, (caddr_t)fh, 6, MB_MSYSTEM);
275         error = ncp_request(rqp);
276         if (error)
277                 return error;
278         ncp_rq_done(rqp);
279         return error;
280 }
281
282 int
283 ncp_DeleteNSEntry(struct nwmount *nmp, u_int32_t dirent,
284         int namelen,char *name,struct thread *td,struct ucred *cred)
285 {
286         struct ncp_rq *rqp;
287         int error;
288         struct ncp_conn *conn=NWFSTOCONN(nmp);
289
290         error = ncp_rq_alloc(87, conn, td, cred, &rqp);
291         if (error)
292                 return error;
293         mb_put_uint8(&rqp->rq, 8);              /* subfunction */
294         mb_put_uint8(&rqp->rq, nmp->name_space);
295         mb_put_uint8(&rqp->rq, 0);              /* reserved */
296         mb_put_uint16le(&rqp->rq, SA_ALL);      /* search attribs: all */
297         ncp_rq_dbase_path(rqp, nmp->n_volume, dirent, namelen, name, &nmp->m.nls);
298         error = ncp_request(rqp);
299         if (!error)
300                 ncp_rq_done(rqp);
301         return error;
302 }
303
304 int 
305 ncp_nsrename(struct ncp_conn *conn, int volume, int ns, int oldtype, 
306         struct ncp_nlstables *nt,
307         nwdirent fdir, char *old_name, int oldlen,
308         nwdirent tdir, char *new_name, int newlen,
309         struct thread *td, struct ucred *cred)
310 {
311         struct ncp_rq *rqp;
312         int error;
313
314         error = ncp_rq_alloc(87, conn, td, cred, &rqp);
315         if (error)
316                 return error;
317         mb_put_uint8(&rqp->rq, 4);
318         mb_put_uint8(&rqp->rq, ns);
319         mb_put_uint8(&rqp->rq, 1);      /* RRenameToMySelf */
320         mb_put_uint16le(&rqp->rq, oldtype);
321         /* source Handle Path */
322         mb_put_uint8(&rqp->rq, volume);
323         mb_put_mem(&rqp->rq, (c_caddr_t)&fdir, sizeof(fdir), MB_MSYSTEM);
324         mb_put_uint8(&rqp->rq, 1);
325         mb_put_uint8(&rqp->rq, 1);      /* 1 source component */
326         /* dest Handle Path */
327         mb_put_uint8(&rqp->rq, volume);
328         mb_put_mem(&rqp->rq, (c_caddr_t)&tdir, sizeof(tdir), MB_MSYSTEM);
329         mb_put_uint8(&rqp->rq, 1);
330         mb_put_uint8(&rqp->rq, 1);      /* 1 destination component */
331         ncp_rq_pathstring(rqp, oldlen, old_name, nt);
332         ncp_rq_pathstring(rqp, newlen, new_name, nt);
333         error = ncp_request(rqp);
334         if (!error)
335                 ncp_rq_done(rqp);
336         return error;
337 }
338
339 int
340 ncp_modify_file_or_subdir_dos_info(struct nwmount *nmp, struct vnode *vp, 
341                                 u_int32_t info_mask,
342                                 struct nw_modify_dos_info *info,
343                                 struct thread *td,struct ucred *cred)
344 {
345         struct nwnode *np=VTONW(vp);
346         struct ncp_rq *rqp;
347         u_int8_t volnum = nmp->n_volume;
348         u_int32_t dirent = np->n_fid.f_id;
349         struct ncp_conn *conn=NWFSTOCONN(nmp);
350         int             error;
351
352         error = ncp_rq_alloc(87, conn, td, cred, &rqp);
353         if (error)
354                 return error;
355         mb_put_uint8(&rqp->rq, 7);      /* subfunction */
356         mb_put_uint8(&rqp->rq, nmp->name_space);
357         mb_put_uint8(&rqp->rq, 0);      /* reserved */
358         mb_put_uint16le(&rqp->rq, SA_ALL);      /* search attribs: all */
359         mb_put_uint32le(&rqp->rq, info_mask);
360         mb_put_mem(&rqp->rq, (caddr_t)info, sizeof(*info), MB_MSYSTEM);
361         ncp_rq_dbase_path(rqp, volnum, dirent, 0, NULL, NULL);
362         error = ncp_request(rqp);
363         if (!error)
364                 ncp_rq_done(rqp);
365         return error;
366 }
367
368 int
369 ncp_setattr(vp, vap, cred, td)
370         struct vnode *vp;
371         struct vattr *vap;
372         struct ucred *cred;
373         struct thread *td;
374 {
375         struct nwmount *nmp=VTONWFS(vp);
376         struct nwnode *np=VTONW(vp);
377         struct ncp_open_info nwn;
378         struct ncp_conn *conn=NWFSTOCONN(nmp);
379         struct nw_modify_dos_info info;
380         struct ncp_rq *rqp;
381         int error = 0, info_mask;
382
383         if (vap->va_size != VNOVAL) {
384                 error = ncp_open_create_file_or_subdir(nmp, vp, 0, NULL, OC_MODE_OPEN, 0,
385                                                    AR_WRITE | AR_READ, &nwn,td,cred);
386                 if (error)
387                         return error;
388                 error = ncp_rq_alloc(73, conn, td, cred, &rqp);
389                 if (error) {
390                         ncp_close_file(conn, &nwn.fh, td, cred);
391                         return error;
392                 }
393                 mb_put_uint8(&rqp->rq, 0);
394                 mb_put_mem(&rqp->rq, (caddr_t)&nwn.fh, 6, MB_MSYSTEM);
395                 mb_put_uint32be(&rqp->rq, vap->va_size);
396                 mb_put_uint16be(&rqp->rq, 0);
397                 error = ncp_request(rqp);
398                 np->n_vattr.va_size = np->n_size = vap->va_size;
399                 if (!error)
400                         ncp_rq_done(rqp);
401                 ncp_close_file(conn, &nwn.fh, td, cred);
402                 if (error)
403                         return error;
404         }
405         info_mask = 0;
406         bzero(&info, sizeof(info));
407
408         if (vap->va_mtime.tv_sec != VNOVAL) {
409                 info_mask |= (DM_MODIFY_TIME | DM_MODIFY_DATE);
410                 ncp_unix2dostime(&vap->va_mtime, nmp->m.tz, &info.modifyDate, &info.modifyTime, NULL);
411         }
412         if (vap->va_atime.tv_sec != VNOVAL) {
413                 info_mask |= (DM_LAST_ACCESS_DATE);
414                 ncp_unix2dostime(&vap->va_atime, nmp->m.tz, &info.lastAccessDate, NULL, NULL);
415         }
416         if (info_mask) {
417                 error = ncp_modify_file_or_subdir_dos_info(nmp, vp, info_mask, &info,td,cred);
418         }
419         return (error);
420 }
421
422 int
423 ncp_get_volume_info_with_number(struct ncp_conn *conn, 
424         int n, struct ncp_volume_info *target,
425         struct thread *td,struct ucred *cred)
426 {
427         struct ncp_rq *rqp;
428         u_int32_t tmp32;
429         u_int8_t len;
430         int error;
431
432         error = ncp_rq_alloc_subfn(22, 44, conn, td, cred, &rqp);
433         if (error)
434                 return error;
435         mb_put_uint8(&rqp->rq,n);
436         error = ncp_request(rqp);
437         if (error)
438                 return error;
439         md_get_uint32le(&rqp->rp, &target->total_blocks);
440         md_get_uint32le(&rqp->rp, &target->free_blocks);
441         md_get_uint32le(&rqp->rp, &target->purgeable_blocks);
442         md_get_uint32le(&rqp->rp, &target->not_yet_purgeable_blocks);
443         md_get_uint32le(&rqp->rp, &target->total_dir_entries);
444         md_get_uint32le(&rqp->rp, &target->available_dir_entries);
445         md_get_uint32le(&rqp->rp, &tmp32);
446         md_get_uint8(&rqp->rp, &target->sectors_per_block);
447         bzero(&target->volume_name, sizeof(target->volume_name));
448         md_get_uint8(&rqp->rp, &len);
449         if (len > NCP_VOLNAME_LEN) {
450                 error = ENAMETOOLONG;
451         } else {
452                 md_get_mem(&rqp->rp, (caddr_t)&target->volume_name, len, MB_MSYSTEM);
453         }
454         ncp_rq_done(rqp);
455         return error;
456 }
457
458 int
459 ncp_get_namespaces(struct ncp_conn *conn, u_int32_t volume, int *nsf,
460         struct thread *td,struct ucred *cred)
461 {
462         struct ncp_rq *rqp;
463         int error;
464         u_int8_t ns;
465         u_int16_t nscnt;
466
467         error = ncp_rq_alloc(87, conn, td, cred, &rqp);
468         if (error)
469                 return error;
470         mb_put_uint8(&rqp->rq, 24);     /* Subfunction: Get Loaded Name Spaces */
471         mb_put_uint16le(&rqp->rq, 0);   /* reserved */
472         mb_put_uint8(&rqp->rq, volume);
473         error = ncp_request(rqp);
474         if (error)
475                 return error;
476         md_get_uint16le(&rqp->rp, &nscnt);
477         *nsf = 0;
478         while (nscnt-- > 0) {
479                 md_get_uint8(&rqp->rp, &ns);
480                 *nsf |= 1 << ns;
481         }
482         ncp_rq_done(rqp);
483         return error;
484 }
485
486 int
487 ncp_lookup_volume(struct ncp_conn *conn, char *volname, 
488                 u_char *volNum, u_int32_t *dirEnt,
489                 struct thread *td,struct ucred *cred)
490 {
491         struct ncp_rq *rqp;
492         u_int32_t tmp32;
493         int error;
494
495         NCPNDEBUG("looking up vol %s\n", volname);
496         error = ncp_rq_alloc(87, conn, td, cred, &rqp);
497         if (error)
498                 return error;
499         mb_put_uint8(&rqp->rq, 22);     /* Subfunction: Generate dir handle */
500         mb_put_uint8(&rqp->rq, 0);      /* src name space */
501         mb_put_uint8(&rqp->rq, 0);      /* dst name space, always zero */
502         mb_put_uint16le(&rqp->rq, 0);   /* dstNSIndicator (Jn) */
503
504         mb_put_uint8(&rqp->rq, 0);      /* faked volume number */
505         mb_put_uint32be(&rqp->rq, 0);   /* faked dir_base */
506         mb_put_uint8(&rqp->rq, 0xff);   /* Don't have a dir_base */
507         mb_put_uint8(&rqp->rq, 1);      /* 1 path component */
508         ncp_rq_pstring(rqp, volname);
509         error = ncp_request(rqp);
510         if (error)
511                 return error;
512         md_get_uint32le(&rqp->rp, &tmp32);
513         md_get_uint32le(&rqp->rp, dirEnt);
514         md_get_uint8(&rqp->rp, volNum);
515         ncp_rq_done(rqp);
516         return error;
517 }
518
519 /*
520  * XXX: I think the timezone in struct nwfs_args is truly bogus, especially
521  * XXX: considering that nwfs_mount(8) picks this up from the kernel in
522  * XXX: the first place.  Since I can't test this, I won't attempt to fix it.
523  * XXX: /phk
524  */
525
526 void
527 ncp_unix2dostime(tsp, tzoff, ddp, dtp, dhp)
528         struct timespec *tsp;
529         int tzoff;
530         u_int16_t *ddp;
531         u_int16_t *dtp;
532         u_int8_t *dhp;
533 {
534         struct timespec t;
535
536         t = *tsp;
537         
538         t.tv_sec = - tzoff * 60 - utc_offset();
539         timespec2fattime(&t, 1, ddp, dtp, dhp);
540 }
541
542 void
543 ncp_dos2unixtime(dd, dt, dh, tzoff, tsp)
544         u_int dd;
545         u_int dt;
546         u_int dh;
547         int tzoff;
548         struct timespec *tsp;
549 {
550
551         fattime2timespec(dd, dt, dh, 1, tsp);
552         tsp->tv_sec += tzoff * 60 + utc_offset();
553 }