1da6c28aaSamw /*
2da6c28aaSamw * CDDL HEADER START
3da6c28aaSamw *
4da6c28aaSamw * The contents of this file are subject to the terms of the
5da6c28aaSamw * Common Development and Distribution License (the "License").
6da6c28aaSamw * You may not use this file except in compliance with the License.
7da6c28aaSamw *
8da6c28aaSamw * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9da6c28aaSamw * or http://www.opensolaris.org/os/licensing.
10da6c28aaSamw * See the License for the specific language governing permissions
11da6c28aaSamw * and limitations under the License.
12da6c28aaSamw *
13da6c28aaSamw * When distributing Covered Code, include this CDDL HEADER in each
14da6c28aaSamw * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15da6c28aaSamw * If applicable, add the following below this CDDL HEADER, with the
16da6c28aaSamw * fields enclosed by brackets "[]" replaced with your own identifying
17da6c28aaSamw * information: Portions Copyright [yyyy] [name of copyright owner]
18da6c28aaSamw *
19da6c28aaSamw * CDDL HEADER END
20da6c28aaSamw */
21da6c28aaSamw /*
22148c5f43SAlan Wright * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved.
23*d2488fe8SGordon Ross * Copyright 2017 Nexenta Systems, Inc. All rights reserved.
24da6c28aaSamw */
25da6c28aaSamw
26da6c28aaSamw #include <sys/types.h>
272c2961f8Sjose borrego #include <sys/param.h>
28da6c28aaSamw #include <sys/sunddi.h>
29da6c28aaSamw #include <sys/errno.h>
30b819cea2SGordon Ross #include <sys/extdirent.h>
31da6c28aaSamw #include <smbsrv/string.h>
32da6c28aaSamw #include <smbsrv/smb_vops.h>
33bbf6f00cSJordan Brown #include <smbsrv/smb_kproto.h>
34da6c28aaSamw #include <smbsrv/smb_fsops.h>
35da6c28aaSamw
362c2961f8Sjose borrego /*
372c2961f8Sjose borrego * Characters we don't allow in DOS file names.
382c2961f8Sjose borrego * If a filename contains any of these chars, it should get mangled.
392c2961f8Sjose borrego *
402c2961f8Sjose borrego * '.' is also an invalid DOS char but since it's a special
412c2961f8Sjose borrego * case it doesn't appear in the list.
422c2961f8Sjose borrego */
438622ec45SGordon Ross static const char invalid_dos_chars[] =
442c2961f8Sjose borrego "\001\002\003\004\005\006\007\010\011\012\013\014\015\016\017"
452c2961f8Sjose borrego "\020\021\022\023\024\025\026\027\030\031\032\033\034\035\036\037"
462c2961f8Sjose borrego " \"/\\:|<>*?";
472c2961f8Sjose borrego
482c2961f8Sjose borrego /*
492c2961f8Sjose borrego * According to MSKB article #142982, Windows deletes invalid chars and
502c2961f8Sjose borrego * spaces from file name in mangling process; and invalid chars include:
512c2961f8Sjose borrego * ."/\[]:;=,
522c2961f8Sjose borrego *
532c2961f8Sjose borrego * But some of these chars and some other chars (e.g. +) are replaced
542c2961f8Sjose borrego * with underscore (_). They are introduced here as special chars.
552c2961f8Sjose borrego */
568622ec45SGordon Ross static const char special_chars[] = "[];=,+";
572c2961f8Sjose borrego
582c2961f8Sjose borrego #define isinvalid(c) (strchr(invalid_dos_chars, c) || (c & 0x80))
592c2961f8Sjose borrego
60148c5f43SAlan Wright static int smb_generate_mangle(uint64_t, char *, size_t);
61148c5f43SAlan Wright static char smb_mangle_char(char);
62da6c28aaSamw
63da6c28aaSamw /*
642c2961f8Sjose borrego * Return true if name contains characters that are invalid in a file
652c2961f8Sjose borrego * name or it is a reserved DOS device name. Otherwise, returns false.
66da6c28aaSamw *
672c2961f8Sjose borrego * Control characters (values 0 - 31) and the following characters are
682c2961f8Sjose borrego * invalid:
692c2961f8Sjose borrego * < > : " / \ | ? *
70da6c28aaSamw */
712c2961f8Sjose borrego boolean_t
smb_is_invalid_filename(const char * name)722c2961f8Sjose borrego smb_is_invalid_filename(const char *name)
73da6c28aaSamw {
742c2961f8Sjose borrego const char *p;
75da6c28aaSamw
762c2961f8Sjose borrego if ((p = strpbrk(name, invalid_dos_chars)) != NULL) {
772c2961f8Sjose borrego if (*p != ' ')
782c2961f8Sjose borrego return (B_TRUE);
792c2961f8Sjose borrego }
802c2961f8Sjose borrego
812c2961f8Sjose borrego return (smb_is_reserved_dos_name(name));
82da6c28aaSamw }
83da6c28aaSamw
84da6c28aaSamw /*
85da6c28aaSamw * smb_is_reserved_dos_name
86da6c28aaSamw *
872c2961f8Sjose borrego * This function checks if the name is a reserved DOS device name.
882c2961f8Sjose borrego * The device name should not be followed immediately by an extension,
892c2961f8Sjose borrego * for example, NUL.txt.
90da6c28aaSamw */
91cb174861Sjoyce mcintosh boolean_t
smb_is_reserved_dos_name(const char * name)922c2961f8Sjose borrego smb_is_reserved_dos_name(const char *name)
93da6c28aaSamw {
942c2961f8Sjose borrego static char *cnames[] = { "CLOCK$", "COM1", "COM2", "COM3", "COM4",
952c2961f8Sjose borrego "COM5", "COM6", "COM7", "COM8", "COM9", "CON" };
962c2961f8Sjose borrego static char *lnames[] = { "LPT1", "LPT2", "LPT3", "LPT4", "LPT5",
972c2961f8Sjose borrego "LPT6", "LPT7", "LPT8", "LPT9" };
982c2961f8Sjose borrego static char *others[] = { "AUX", "NUL", "PRN" };
992c2961f8Sjose borrego char **reserved;
100da6c28aaSamw char ch;
1012c2961f8Sjose borrego int n_reserved;
1022c2961f8Sjose borrego int len;
1032c2961f8Sjose borrego int i;
104da6c28aaSamw
105bbf6f00cSJordan Brown ch = smb_toupper(*name);
106da6c28aaSamw
107da6c28aaSamw switch (ch) {
108da6c28aaSamw case 'A':
1092c2961f8Sjose borrego case 'N':
1102c2961f8Sjose borrego case 'P':
1112c2961f8Sjose borrego reserved = others;
1122c2961f8Sjose borrego n_reserved = sizeof (others) / sizeof (others[0]);
113da6c28aaSamw break;
114da6c28aaSamw case 'C':
1152c2961f8Sjose borrego reserved = cnames;
1162c2961f8Sjose borrego n_reserved = sizeof (cnames) / sizeof (cnames[0]);
117da6c28aaSamw break;
118da6c28aaSamw case 'L':
1192c2961f8Sjose borrego reserved = lnames;
1202c2961f8Sjose borrego n_reserved = sizeof (lnames) / sizeof (lnames[0]);
121da6c28aaSamw break;
1222c2961f8Sjose borrego default:
1232c2961f8Sjose borrego return (B_FALSE);
124da6c28aaSamw }
125da6c28aaSamw
1262c2961f8Sjose borrego for (i = 0; i < n_reserved; ++i) {
1272c2961f8Sjose borrego len = strlen(reserved[i]);
1282c2961f8Sjose borrego
129bbf6f00cSJordan Brown if (smb_strcasecmp(reserved[i], name, len) == 0) {
1302c2961f8Sjose borrego ch = *(name + len);
1312c2961f8Sjose borrego if ((ch == '\0') || (ch == '.'))
1322c2961f8Sjose borrego return (B_TRUE);
133da6c28aaSamw }
134da6c28aaSamw }
135da6c28aaSamw
1362c2961f8Sjose borrego return (B_FALSE);
137da6c28aaSamw }
138da6c28aaSamw
139da6c28aaSamw /*
140148c5f43SAlan Wright * smb_needs_mangled
141148c5f43SAlan Wright *
142148c5f43SAlan Wright * A name needs to be mangled if any of the following are true:
143148c5f43SAlan Wright * - the first character is dot (.) and the name is not "." or ".."
144148c5f43SAlan Wright * - the name contains illegal or special charsacter
145148c5f43SAlan Wright * - the name name length > 12
146148c5f43SAlan Wright * - the number of dots == 0 and length > 8
147148c5f43SAlan Wright * - the number of dots > 1
148148c5f43SAlan Wright * - the number of dots == 1 and name is not 8.3
149da6c28aaSamw */
150148c5f43SAlan Wright boolean_t
smb_needs_mangled(const char * name)151148c5f43SAlan Wright smb_needs_mangled(const char *name)
152da6c28aaSamw {
153148c5f43SAlan Wright int len, extlen, ndots;
154148c5f43SAlan Wright const char *p;
155148c5f43SAlan Wright const char *last_dot;
156da6c28aaSamw
157da6c28aaSamw if ((strcmp(name, ".") == 0) || (strcmp(name, "..") == 0))
158148c5f43SAlan Wright return (B_FALSE);
159da6c28aaSamw
160da6c28aaSamw if (*name == '.')
161148c5f43SAlan Wright return (B_TRUE);
162148c5f43SAlan Wright
163148c5f43SAlan Wright len = 0;
164148c5f43SAlan Wright ndots = 0;
165148c5f43SAlan Wright last_dot = NULL;
166148c5f43SAlan Wright for (p = name; *p != '\0'; ++p) {
167148c5f43SAlan Wright if (smb_iscntrl(*p) ||
168148c5f43SAlan Wright (strchr(special_chars, *p) != NULL) ||
169148c5f43SAlan Wright (strchr(invalid_dos_chars, *p)) != NULL)
170148c5f43SAlan Wright return (B_TRUE);
171da6c28aaSamw
172148c5f43SAlan Wright if (*p == '.') {
173148c5f43SAlan Wright ++ndots;
174148c5f43SAlan Wright last_dot = p;
175148c5f43SAlan Wright }
176148c5f43SAlan Wright ++len;
177da6c28aaSamw }
178da6c28aaSamw
179148c5f43SAlan Wright if ((len > SMB_NAME83_LEN) ||
180148c5f43SAlan Wright (ndots == 0 && len > SMB_NAME83_BASELEN) ||
181148c5f43SAlan Wright (ndots > 1)) {
182148c5f43SAlan Wright return (B_TRUE);
183da6c28aaSamw }
184da6c28aaSamw
185148c5f43SAlan Wright if (last_dot != NULL) {
186148c5f43SAlan Wright extlen = strlen(last_dot + 1);
187148c5f43SAlan Wright if ((extlen == 0) || (extlen > SMB_NAME83_EXTLEN))
188148c5f43SAlan Wright return (B_TRUE);
189da6c28aaSamw
190148c5f43SAlan Wright if ((len - extlen - 1) > SMB_NAME83_BASELEN)
191148c5f43SAlan Wright return (B_TRUE);
192da6c28aaSamw }
193da6c28aaSamw
194148c5f43SAlan Wright return (B_FALSE);
195da6c28aaSamw }
196da6c28aaSamw
197da6c28aaSamw /*
198da6c28aaSamw * smb_mangle_char
199da6c28aaSamw *
200148c5f43SAlan Wright * If c is an invalid DOS character or non-ascii, it should
201148c5f43SAlan Wright * not be used in the mangled name. We return -1 to indicate
202148c5f43SAlan Wright * an invalid character.
203da6c28aaSamw *
204148c5f43SAlan Wright * If c is a special chars, it should be replaced with '_'.
205da6c28aaSamw *
206148c5f43SAlan Wright * Otherwise c is returned as uppercase.
207da6c28aaSamw */
208148c5f43SAlan Wright static char
smb_mangle_char(char c)209148c5f43SAlan Wright smb_mangle_char(char c)
210da6c28aaSamw {
211148c5f43SAlan Wright if (isinvalid(c))
212148c5f43SAlan Wright return (-1);
213da6c28aaSamw
214148c5f43SAlan Wright if (strchr(special_chars, c))
215da6c28aaSamw return ('_');
216da6c28aaSamw
217148c5f43SAlan Wright return (smb_toupper(c));
218da6c28aaSamw }
219da6c28aaSamw
220da6c28aaSamw /*
221da6c28aaSamw * smb_generate_mangle
222da6c28aaSamw *
223148c5f43SAlan Wright * Generate a mangle string containing at least 2 characters and
224148c5f43SAlan Wright * at most (buflen - 1) characters.
225da6c28aaSamw *
226da6c28aaSamw * Returns the number of chars in the generated mangle.
227da6c28aaSamw */
228da6c28aaSamw static int
smb_generate_mangle(uint64_t fid,char * buf,size_t buflen)229148c5f43SAlan Wright smb_generate_mangle(uint64_t fid, char *buf, size_t buflen)
230da6c28aaSamw {
231da6c28aaSamw static char *base36 = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
232148c5f43SAlan Wright char *p = buf;
23348557149Sjoyce mcintosh int i;
234da6c28aaSamw
23548557149Sjoyce mcintosh if (fid == 0)
23648557149Sjoyce mcintosh fid = (uint64_t)-1;
237da6c28aaSamw
23848557149Sjoyce mcintosh *p++ = '~';
23948557149Sjoyce mcintosh for (i = 2; (i < buflen) && (fid > 0); fid /= 36, ++i)
24048557149Sjoyce mcintosh *p++ = base36[fid % 36];
24148557149Sjoyce mcintosh *p = '\0';
24248557149Sjoyce mcintosh
24348557149Sjoyce mcintosh return (i - 1);
244da6c28aaSamw }
245da6c28aaSamw
246da6c28aaSamw /*
247148c5f43SAlan Wright * smb_maybe_mangled
248da6c28aaSamw *
2492c2961f8Sjose borrego * Mangled names should be valid DOS file names: less than 12 characters
2502c2961f8Sjose borrego * long, contain at least one tilde character and conform to an 8.3 name
2512c2961f8Sjose borrego * format.
252da6c28aaSamw *
2532c2961f8Sjose borrego * Returns true if the name looks like a mangled name.
254da6c28aaSamw */
255148c5f43SAlan Wright boolean_t
smb_maybe_mangled(char * name)256148c5f43SAlan Wright smb_maybe_mangled(char *name)
257da6c28aaSamw {
2582c2961f8Sjose borrego const char *p;
2592c2961f8Sjose borrego boolean_t has_tilde = B_FALSE;
2602c2961f8Sjose borrego int ndots = 0;
2612c2961f8Sjose borrego int i;
2622c2961f8Sjose borrego
2632c2961f8Sjose borrego for (p = name, i = 0; (*p != '\0') && (i < SMB_NAME83_LEN); i++, p++) {
2642c2961f8Sjose borrego if ((strchr(special_chars, *p) != NULL) ||
2652c2961f8Sjose borrego (strchr(invalid_dos_chars, *p) != NULL))
2662c2961f8Sjose borrego return (B_FALSE);
2672c2961f8Sjose borrego
2682c2961f8Sjose borrego if (*p == '.') {
2692c2961f8Sjose borrego if ((++ndots) > 1)
2702c2961f8Sjose borrego return (B_FALSE);
2712c2961f8Sjose borrego }
272da6c28aaSamw
2732c2961f8Sjose borrego if ((*p == '~') && (i < SMB_NAME83_BASELEN))
2742c2961f8Sjose borrego has_tilde = B_TRUE;
275da6c28aaSamw
2762c2961f8Sjose borrego if (*p == '.' && !has_tilde)
2772c2961f8Sjose borrego return (B_FALSE);
278da6c28aaSamw }
279da6c28aaSamw
280148c5f43SAlan Wright return ((*p == '\0') && has_tilde);
281da6c28aaSamw }
282da6c28aaSamw
283da6c28aaSamw /*
284148c5f43SAlan Wright * smb_mangle
285da6c28aaSamw *
286da6c28aaSamw * Microsoft knowledge base article #142982 describes how Windows
287da6c28aaSamw * generates 8.3 filenames from long file names. Some other details
288da6c28aaSamw * can be found in article #114816.
289da6c28aaSamw *
290148c5f43SAlan Wright * This function will mangle the name whether mangling is required
291148c5f43SAlan Wright * or not. Callers should use smb_needs_mangled() to determine whether
292148c5f43SAlan Wright * mangling is required.
293da6c28aaSamw *
294148c5f43SAlan Wright * name original file name
295148c5f43SAlan Wright * fid inode number to generate unique mangle
296148c5f43SAlan Wright * buf output buffer (buflen bytes) to contain mangled name
297da6c28aaSamw */
298148c5f43SAlan Wright void
smb_mangle(const char * name,ino64_t fid,char * buf,size_t buflen)299148c5f43SAlan Wright smb_mangle(const char *name, ino64_t fid, char *buf, size_t buflen)
300da6c28aaSamw {
301148c5f43SAlan Wright int i, avail;
302148c5f43SAlan Wright const char *p;
303148c5f43SAlan Wright char c;
304148c5f43SAlan Wright char *pbuf;
305148c5f43SAlan Wright char mangle_buf[SMB_NAME83_BASELEN];
306da6c28aaSamw
307148c5f43SAlan Wright ASSERT(name && buf && (buflen >= SMB_SHORTNAMELEN));
308da6c28aaSamw
309148c5f43SAlan Wright avail = SMB_NAME83_BASELEN -
310148c5f43SAlan Wright smb_generate_mangle(fid, mangle_buf, SMB_NAME83_BASELEN);
311148c5f43SAlan Wright name += strspn(name, ".");
312da6c28aaSamw
313da6c28aaSamw /*
314148c5f43SAlan Wright * Copy up to avail characters from the base part of name
315148c5f43SAlan Wright * to buf then append the generated mangle string.
316da6c28aaSamw */
317148c5f43SAlan Wright p = name;
318148c5f43SAlan Wright pbuf = buf;
319148c5f43SAlan Wright for (i = 0; (i < avail) && (*p != '\0') && (*p != '.'); ++i, ++p) {
320148c5f43SAlan Wright if ((c = smb_mangle_char(*p)) == -1)
321da6c28aaSamw continue;
322148c5f43SAlan Wright *pbuf++ = c;
323da6c28aaSamw }
324148c5f43SAlan Wright *pbuf = '\0';
325148c5f43SAlan Wright (void) strlcat(pbuf, mangle_buf, SMB_NAME83_BASELEN);
326148c5f43SAlan Wright pbuf = strchr(pbuf, '\0');
327da6c28aaSamw
328148c5f43SAlan Wright /*
329148c5f43SAlan Wright * Find the last dot in the name. If there is a dot and an
330148c5f43SAlan Wright * extension, append '.' and up to SMB_NAME83_EXTLEN extension
331148c5f43SAlan Wright * characters to the mangled name.
332148c5f43SAlan Wright */
333148c5f43SAlan Wright if (((p = strrchr(name, '.')) != NULL) && (*(++p) != '\0')) {
334148c5f43SAlan Wright *pbuf++ = '.';
335148c5f43SAlan Wright for (i = 0; (i < SMB_NAME83_EXTLEN) && (*p != '\0'); ++i, ++p) {
336148c5f43SAlan Wright if ((c = smb_mangle_char(*p)) == -1)
337148c5f43SAlan Wright continue;
338148c5f43SAlan Wright *pbuf++ = c;
339da6c28aaSamw }
340da6c28aaSamw }
341da6c28aaSamw
342148c5f43SAlan Wright *pbuf = '\0';
343da6c28aaSamw }
344da6c28aaSamw
345da6c28aaSamw /*
346148c5f43SAlan Wright * smb_unmangle
347da6c28aaSamw *
348da6c28aaSamw * Given a mangled name, try to find the real file name as it appears
3498b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * in the directory entry.
3508b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States *
351148c5f43SAlan Wright * smb_unmangle should only be called on names for which
352148c5f43SAlan Wright * smb_maybe_mangled() is true
3538b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States *
354*d2488fe8SGordon Ross * The flags arg is no longer used, but retained just to avoid
355*d2488fe8SGordon Ross * changing the many callers of this function.
3568b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States *
3578b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * Returns:
3588b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * 0 - SUCCESS. Unmangled name is returned in namebuf.
3598b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * EINVAL - a parameter was invalid.
3608b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * ENOTDIR - dnode is not a directory node.
3618b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States * ENOENT - an unmangled name could not be found.
362da6c28aaSamw */
3638b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States #define SMB_UNMANGLE_BUFSIZE (4 * 1024)
364da6c28aaSamw int
smb_unmangle(smb_node_t * dnode,char * name,char * namebuf,int buflen,uint32_t flags)365148c5f43SAlan Wright smb_unmangle(smb_node_t *dnode, char *name, char *namebuf,
366e3f2c991SKeyur Desai int buflen, uint32_t flags)
367da6c28aaSamw {
368*d2488fe8SGordon Ross _NOTE(ARGUNUSED(flags)) // avoid changing all callers
369*d2488fe8SGordon Ross int err, eof, bufsize;
3708b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States uint64_t offset;
3718b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States ino64_t ino;
3728b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States char *namep, *buf;
3738b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States char shortname[SMB_SHORTNAMELEN];
3748b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States vnode_t *vp;
375*d2488fe8SGordon Ross char *bufptr;
376*d2488fe8SGordon Ross dirent64_t *dp;
377*d2488fe8SGordon Ross cred_t *cr = zone_kcred();
378*d2488fe8SGordon Ross int rc = ENOENT;
3798b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
3808b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States if (dnode == NULL || name == NULL || namebuf == NULL || buflen == 0)
381da6c28aaSamw return (EINVAL);
382da6c28aaSamw
383148c5f43SAlan Wright ASSERT(smb_maybe_mangled(name) == B_TRUE);
384da6c28aaSamw
3859fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States if (!smb_node_is_dir(dnode))
3868b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States return (ENOTDIR);
387da6c28aaSamw
3889fb67ea3Safshin salek ardakani - Sun Microsystems - Irvine United States vp = dnode->vp;
3898b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States *namebuf = '\0';
390da6c28aaSamw
3918b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States buf = kmem_alloc(SMB_UNMANGLE_BUFSIZE, KM_SLEEP);
392*d2488fe8SGordon Ross bufptr = buf;
393*d2488fe8SGordon Ross bufsize = 0;
394*d2488fe8SGordon Ross offset = 0; // next entry offset
395*d2488fe8SGordon Ross eof = B_FALSE;
396*d2488fe8SGordon Ross
397*d2488fe8SGordon Ross for (;;) {
398*d2488fe8SGordon Ross /*
399*d2488fe8SGordon Ross * Read some entries, if buffer empty or
400*d2488fe8SGordon Ross * we've scanned all of it. Flags zero
401*d2488fe8SGordon Ross * (no edirent, no ABE wanted here)
402*d2488fe8SGordon Ross */
403*d2488fe8SGordon Ross if (bufsize <= 0) {
404*d2488fe8SGordon Ross bufsize = SMB_UNMANGLE_BUFSIZE;
405*d2488fe8SGordon Ross rc = smb_vop_readdir(vp, offset, buf,
406*d2488fe8SGordon Ross &bufsize, &eof, 0, cr);
407*d2488fe8SGordon Ross if (rc != 0)
408*d2488fe8SGordon Ross break; /* error */
409*d2488fe8SGordon Ross if (bufsize == 0) {
410*d2488fe8SGordon Ross eof = B_TRUE;
411*d2488fe8SGordon Ross rc = ENOENT;
412*d2488fe8SGordon Ross break;
4138b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States }
414*d2488fe8SGordon Ross bufptr = buf;
415*d2488fe8SGordon Ross }
416*d2488fe8SGordon Ross /* LINTED pointer alignment */
417*d2488fe8SGordon Ross dp = (dirent64_t *)bufptr;
418*d2488fe8SGordon Ross
419*d2488fe8SGordon Ross /*
420*d2488fe8SGordon Ross * Partial records are not supposed to happen,
421*d2488fe8SGordon Ross * but let's be defensive. If this happens,
422*d2488fe8SGordon Ross * restart at the current offset.
423*d2488fe8SGordon Ross */
424*d2488fe8SGordon Ross bufptr += dp->d_reclen;
425*d2488fe8SGordon Ross bufsize -= dp->d_reclen;
426*d2488fe8SGordon Ross if (bufsize < 0)
427*d2488fe8SGordon Ross continue;
4288b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
429*d2488fe8SGordon Ross offset = dp->d_off;
430*d2488fe8SGordon Ross ino = dp->d_ino;
431*d2488fe8SGordon Ross namep = dp->d_name;
432da6c28aaSamw
433*d2488fe8SGordon Ross /* skip non utf8 filename */
434*d2488fe8SGordon Ross if (u8_validate(namep, strlen(namep), NULL,
435*d2488fe8SGordon Ross U8_VALIDATE_ENTIRE, &err) < 0)
436*d2488fe8SGordon Ross continue;
4378b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States
438*d2488fe8SGordon Ross smb_mangle(namep, ino, shortname, SMB_SHORTNAMELEN);
439*d2488fe8SGordon Ross if (smb_strcasecmp(name, shortname, 0) == 0) {
440*d2488fe8SGordon Ross (void) strlcpy(namebuf, namep, buflen);
441*d2488fe8SGordon Ross rc = 0;
4428b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States break;
4438b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States }
444da6c28aaSamw }
445da6c28aaSamw
4468b2cc8acSafshin salek ardakani - Sun Microsystems - Irvine United States kmem_free(buf, SMB_UNMANGLE_BUFSIZE);
447*d2488fe8SGordon Ross return (rc);
448da6c28aaSamw }
449