0N/A/*
2362N/A * Copyright (c) 2004, Oracle and/or its affiliates. All rights reserved.
0N/A * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
0N/A *
0N/A * This code is free software; you can redistribute it and/or modify it
0N/A * under the terms of the GNU General Public License version 2 only, as
2362N/A * published by the Free Software Foundation. Oracle designates this
0N/A * particular file as subject to the "Classpath" exception as provided
2362N/A * by Oracle in the LICENSE file that accompanied this code.
0N/A *
0N/A * This code is distributed in the hope that it will be useful, but WITHOUT
0N/A * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
0N/A * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
0N/A * version 2 for more details (a copy is included in the LICENSE file that
0N/A * accompanied this code).
0N/A *
0N/A * You should have received a copy of the GNU General Public License version
0N/A * 2 along with this work; if not, write to the Free Software Foundation,
0N/A * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
0N/A *
2362N/A * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
2362N/A * or visit www.oracle.com if you need additional information or have any
2362N/A * questions.
0N/A */
0N/A
0N/A#include <stdlib.h>
0N/A#include <string.h>
0N/A#include <malloc.h>
0N/A
0N/A#include "FileSystemSupport_md.h"
0N/A
0N/A/*
0N/A * Windows implementation of file system support functions
0N/A */
0N/A
0N/A#define slash '\\'
0N/A#define altSlash '/'
0N/A
0N/Astatic int isSlash(char c) {
0N/A return (c == '\\') || (c == '/');
0N/A}
0N/A
0N/Astatic int isLetter(char c) {
0N/A return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));
0N/A}
0N/A
0N/Achar pathSeparator() {
0N/A return ';';
0N/A}
0N/A
0N/A/* filename are case insensitive on windows */
0N/Aint filenameStrcmp(const char* s1, const char* s2) {
0N/A return strcasecmp(s1, s2);
0N/A}
0N/A
0N/Achar* basePath(const char* path) {
0N/A char* pos = strchr(path, slash);
0N/A char* last = NULL;
0N/A while (pos != NULL) {
0N/A last = pos;
0N/A pos++;
0N/A pos = strchr(pos, slash);
0N/A }
0N/A if (last == NULL) {
0N/A return (char*)path;
0N/A } else {
0N/A int len = (int)(last - path);
0N/A char* str = (char*)malloc(len+1);
0N/A if (len > 0) {
0N/A memcpy(str, path, len);
0N/A }
0N/A str[len] = '\0';
0N/A return str;
0N/A }
0N/A}
0N/A
0N/A
0N/A
0N/A/* -- Normalization - src/windows/classes/java/io/Win32FileSystem.java */
0N/A
0N/A
0N/A/* A normal Win32 pathname contains no duplicate slashes, except possibly
0N/A * for a UNC prefix, and does not end with a slash. It may be the empty
0N/A * string. Normalized Win32 pathnames have the convenient property that
0N/A * the length of the prefix almost uniquely identifies the type of the path
0N/A * and whether it is absolute or relative:
0N/A *
0N/A * 0 relative to both drive and directory
0N/A * 1 drive-relative (begins with '\\')
0N/A * 2 absolute UNC (if first char is '\\'),
0N/A * else directory-relative (has form "z:foo")
0N/A * 3 absolute local pathname (begins with "z:\\")
0N/A */
0N/Astatic int normalizePrefix(const char* path, int len, char* sb, int* sbLen) {
0N/A char c;
0N/A int src = 0;
0N/A while ((src < len) && isSlash(path[src])) src++;
0N/A if ((len - src >= 2)
0N/A && isLetter(c = path[src])
0N/A && path[src + 1] == ':') {
0N/A /* Remove leading slashes if followed by drive specifier.
0N/A This hack is necessary to support file URLs containing drive
0N/A specifiers (e.g., "file://c:/path"). As a side effect,
0N/A "/c:/path" can be used as an alternative to "c:/path". */
0N/A sb[(*sbLen)++] = c;
0N/A sb[(*sbLen)++] = ':';
0N/A src += 2;
0N/A } else {
0N/A src = 0;
0N/A if ((len >= 2)
0N/A && isSlash(path[0])
0N/A && isSlash(path[1])) {
0N/A /* UNC pathname: Retain first slash; leave src pointed at
0N/A second slash so that further slashes will be collapsed
0N/A into the second slash. The result will be a pathname
0N/A beginning with "\\\\" followed (most likely) by a host
0N/A name. */
0N/A src = 1;
0N/A sb[(*sbLen)++] = slash;
0N/A }
0N/A }
0N/A return src;
0N/A}
0N/A
0N/A/*
0N/A * Normalize the given pathname, whose length is len, starting at the given
0N/A * offset; everything before this offset is already normal.
0N/A */
0N/Astatic char* normalizePath(const char* path, int len, int off) {
0N/A int src;
0N/A char* sb;
0N/A int sbLen;
0N/A
0N/A if (len == 0) return (char*)path;
0N/A if (off < 3) off = 0; /* Avoid fencepost cases with UNC pathnames */
0N/A
0N/A sb = (char*)malloc(len+1);
0N/A sbLen = 0;
0N/A
0N/A if (off == 0) {
0N/A /* Complete normalization, including prefix */
0N/A src = normalizePrefix(path, len, sb, &sbLen);
0N/A } else {
0N/A /* Partial normalization */
0N/A src = off;
0N/A memcpy(sb+sbLen, path, off);
0N/A sbLen += off;
0N/A }
0N/A
0N/A /* Remove redundant slashes from the remainder of the path, forcing all
0N/A slashes into the preferred slash */
0N/A while (src < len) {
0N/A char c = path[src++];
0N/A if (isSlash(c)) {
0N/A while ((src < len) && isSlash(path[src])) src++;
0N/A if (src == len) {
0N/A /* Check for trailing separator */
0N/A if ((sbLen == 2) && (sb[1] == ':')) {
0N/A /* "z:\\" */
0N/A sb[sbLen++] = slash;
0N/A break;
0N/A }
0N/A if (sbLen == 0) {
0N/A /* "\\" */
0N/A sb[sbLen++] = slash;
0N/A break;
0N/A }
0N/A if ((sbLen == 1) && (isSlash(sb[0]))) {
0N/A /* "\\\\" is not collapsed to "\\" because "\\\\" marks
0N/A the beginning of a UNC pathname. Even though it is
0N/A not, by itself, a valid UNC pathname, we leave it as
0N/A is in order to be consistent with the win32 APIs,
0N/A which treat this case as an invalid UNC pathname
0N/A rather than as an alias for the root directory of
0N/A the current drive. */
0N/A sb[sbLen++] = slash;
0N/A break;
0N/A }
0N/A /* Path does not denote a root directory, so do not append
0N/A trailing slash */
0N/A break;
0N/A } else {
0N/A sb[sbLen++] = slash;
0N/A }
0N/A } else {
0N/A sb[sbLen++] = c;
0N/A }
0N/A }
0N/A
0N/A sb[sbLen] = '\0';
0N/A return sb;
0N/A}
0N/A
0N/A/*
0N/A * Check that the given pathname is normal. If not, invoke the real
0N/A * normalizer on the part of the pathname that requires normalization.
0N/A * This way we iterate through the whole pathname string only once.
0N/A */
0N/Achar* normalize(char* path) {
0N/A int n = (int)strlen(path);
0N/A int i;
0N/A char c = 0;
0N/A int prev = 0;
0N/A for (i = 0; i < n; i++) {
0N/A char c = path[i];
0N/A if (c == altSlash)
0N/A return normalizePath(path, n, (prev == slash) ? i - 1 : i);
0N/A if ((c == slash) && (prev == slash) && (i > 1))
0N/A return normalizePath(path, n, i - 1);
0N/A if ((c == ':') && (i > 1))
0N/A return normalizePath(path, n, 0);
0N/A prev = c;
0N/A }
0N/A if (prev == slash)
0N/A return normalizePath(path, n, n - 1);
0N/A return path;
0N/A}
0N/A
0N/A
0N/A/* -- Resolution - src/windows/classes/java/io/Win32FileSystem.java */
0N/A
0N/A
0N/Achar* resolve(const char* parent, const char* child) {
0N/A char* c;
0N/A char* theChars;
0N/A int parentEnd, childStart, len;
0N/A
0N/A int pn = (int)strlen(parent);
0N/A int cn = (int)strlen(child);
0N/A
0N/A if (pn == 0) return (char*)child;
0N/A if (cn == 0) return (char*)parent;
0N/A
0N/A c = (char*)child;
0N/A childStart = 0;
0N/A parentEnd = pn;
0N/A
0N/A if ((cn > 1) && (c[0] == slash)) {
0N/A if (c[1] == slash) {
0N/A /* Drop prefix when child is a UNC pathname */
0N/A childStart = 2;
0N/A } else {
0N/A /* Drop prefix when child is drive-relative */
0N/A childStart = 1;
0N/A
0N/A }
0N/A if (cn == childStart) { // Child is double slash
0N/A if (parent[pn - 1] == slash) {
0N/A char* str = strdup(parent);
0N/A str[pn-1] = '\0';
0N/A return str;
0N/A }
0N/A return (char*)parent;
0N/A }
0N/A }
0N/A
0N/A if (parent[pn - 1] == slash)
0N/A parentEnd--;
0N/A
0N/A len = parentEnd + cn - childStart;
0N/A
0N/A if (child[childStart] == slash) {
0N/A theChars = (char*)malloc(len+1);
0N/A memcpy(theChars, parent, parentEnd);
0N/A memcpy(theChars+parentEnd, child+childStart, (cn-childStart));
0N/A theChars[len] = '\0';
0N/A } else {
0N/A theChars = (char*)malloc(len+2);
0N/A memcpy(theChars, parent, parentEnd);
0N/A theChars[parentEnd] = slash;
0N/A memcpy(theChars+parentEnd+1, child+childStart, (cn-childStart));
0N/A theChars[len+1] = '\0';
0N/A }
0N/A return theChars;
0N/A}
0N/A
0N/A
0N/Astatic int prefixLength(const char* path) {
0N/A char c0, c1;
0N/A
0N/A int n = (int)strlen(path);
0N/A if (n == 0) return 0;
0N/A c0 = path[0];
0N/A c1 = (n > 1) ? path[1] : 0;
0N/A if (c0 == slash) {
0N/A if (c1 == slash) return 2; /* Absolute UNC pathname "\\\\foo" */
0N/A return 1; /* Drive-relative "\\foo" */
0N/A }
0N/A if (isLetter(c0) && (c1 == ':')) {
0N/A if ((n > 2) && (path[2] == slash))
0N/A return 3; /* Absolute local pathname "z:\\foo" */
0N/A return 2; /* Directory-relative "z:foo" */
0N/A }
0N/A return 0; /* Completely relative */
0N/A}
0N/A
0N/A
0N/Aint isAbsolute(const char* path) {
0N/A int pl = prefixLength(path);
0N/A return (((pl == 2) && (path[0] == slash)) || (pl == 3));
0N/A}
0N/A
0N/A
0N/Achar* fromURIPath(const char* path) {
0N/A int start = 0;
0N/A int len = (int)strlen(path);
0N/A
0N/A if ((len > 2) && (path[2] == ':')) {
0N/A // "/c:/foo" --> "c:/foo"
0N/A start = 1;
0N/A // "c:/foo/" --> "c:/foo", but "c:/" --> "c:/"
0N/A if ((len > 3) && path[len-1] == '/')
0N/A len--;
0N/A } else if ((len > 1) && path[len-1] == '/') {
0N/A // "/foo/" --> "/foo"
0N/A len--;
0N/A }
0N/A
0N/A if (start == 0 && len == (int)strlen(path)) {
0N/A return (char*)path;
0N/A } else {
0N/A char* p = (char*)malloc(len+1);
0N/A if (p != NULL) {
0N/A memcpy(p, path+start, len);
0N/A p[len] = '\0';
0N/A }
0N/A return p;
0N/A }
0N/A}