Path: blob/master/src/java.instrument/windows/native/libinstrument/FileSystemSupport_md.c
41152 views
/*1* Copyright (c) 2004, 2020, Oracle and/or its affiliates. All rights reserved.2* DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.3*4* This code is free software; you can redistribute it and/or modify it5* under the terms of the GNU General Public License version 2 only, as6* published by the Free Software Foundation. Oracle designates this7* particular file as subject to the "Classpath" exception as provided8* by Oracle in the LICENSE file that accompanied this code.9*10* This code is distributed in the hope that it will be useful, but WITHOUT11* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or12* FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License13* version 2 for more details (a copy is included in the LICENSE file that14* accompanied this code).15*16* You should have received a copy of the GNU General Public License version17* 2 along with this work; if not, write to the Free Software Foundation,18* Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.19*20* Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA21* or visit www.oracle.com if you need additional information or have any22* questions.23*/2425#include <stdio.h>26#include <stdlib.h>27#include <string.h>28#include <malloc.h>2930#include "FileSystemSupport_md.h"3132/*33* Windows implementation of file system support functions34*/3536#define slash '\\'37#define altSlash '/'3839static int isSlash(char c) {40return (c == '\\') || (c == '/');41}4243static int isLetter(char c) {44return ((c >= 'a') && (c <= 'z')) || ((c >= 'A') && (c <= 'Z'));45}4647char* basePath(const char* path) {48char* pos = strchr(path, slash);49char* last = NULL;50while (pos != NULL) {51last = pos;52pos++;53pos = strchr(pos, slash);54}55if (last == NULL) {56return (char*)path;57} else {58int len = (int)(last - path);59char* str = (char*)malloc(len+1);60if (str == NULL) {61fprintf(stderr, "OOM error in native tmp buffer allocation");62return NULL;63}64if (len > 0) {65memcpy(str, path, len);66}67str[len] = '\0';68return str;69}70}71727374/* -- Normalization - src/windows/classes/java/io/Win32FileSystem.java */757677/* A normal Win32 pathname contains no duplicate slashes, except possibly78* for a UNC prefix, and does not end with a slash. It may be the empty79* string. Normalized Win32 pathnames have the convenient property that80* the length of the prefix almost uniquely identifies the type of the path81* and whether it is absolute or relative:82*83* 0 relative to both drive and directory84* 1 drive-relative (begins with '\\')85* 2 absolute UNC (if first char is '\\'),86* else directory-relative (has form "z:foo")87* 3 absolute local pathname (begins with "z:\\")88*/89static int normalizePrefix(const char* path, int len, char* sb, int* sbLen) {90char c;91int src = 0;92while ((src < len) && isSlash(path[src])) src++;93if ((len - src >= 2)94&& isLetter(c = path[src])95&& path[src + 1] == ':') {96/* Remove leading slashes if followed by drive specifier.97This hack is necessary to support file URLs containing drive98specifiers (e.g., "file://c:/path"). As a side effect,99"/c:/path" can be used as an alternative to "c:/path". */100sb[(*sbLen)++] = c;101sb[(*sbLen)++] = ':';102src += 2;103} else {104src = 0;105if ((len >= 2)106&& isSlash(path[0])107&& isSlash(path[1])) {108/* UNC pathname: Retain first slash; leave src pointed at109second slash so that further slashes will be collapsed110into the second slash. The result will be a pathname111beginning with "\\\\" followed (most likely) by a host112name. */113src = 1;114sb[(*sbLen)++] = slash;115}116}117return src;118}119120/*121* Normalize the given pathname, whose length is len, starting at the given122* offset; everything before this offset is already normal.123*/124static char* normalizePath(const char* path, int len, int off) {125int src;126char* sb;127int sbLen;128129if (len == 0) return (char*)path;130if (off < 3) off = 0; /* Avoid fencepost cases with UNC pathnames */131132sb = (char*)malloc(len+1);133if (sb == NULL) {134fprintf(stderr, "OOM error in native tmp buffer allocation");135return NULL;136}137sbLen = 0;138139if (off == 0) {140/* Complete normalization, including prefix */141src = normalizePrefix(path, len, sb, &sbLen);142} else {143/* Partial normalization */144src = off;145memcpy(sb+sbLen, path, off);146sbLen += off;147}148149/* Remove redundant slashes from the remainder of the path, forcing all150slashes into the preferred slash */151while (src < len) {152char c = path[src++];153if (isSlash(c)) {154while ((src < len) && isSlash(path[src])) src++;155if (src == len) {156/* Check for trailing separator */157if ((sbLen == 2) && (sb[1] == ':')) {158/* "z:\\" */159sb[sbLen++] = slash;160break;161}162if (sbLen == 0) {163/* "\\" */164sb[sbLen++] = slash;165break;166}167if ((sbLen == 1) && (isSlash(sb[0]))) {168/* "\\\\" is not collapsed to "\\" because "\\\\" marks169the beginning of a UNC pathname. Even though it is170not, by itself, a valid UNC pathname, we leave it as171is in order to be consistent with the win32 APIs,172which treat this case as an invalid UNC pathname173rather than as an alias for the root directory of174the current drive. */175sb[sbLen++] = slash;176break;177}178/* Path does not denote a root directory, so do not append179trailing slash */180break;181} else {182sb[sbLen++] = slash;183}184} else {185sb[sbLen++] = c;186}187}188189sb[sbLen] = '\0';190return sb;191}192193/*194* Check that the given pathname is normal. If not, invoke the real195* normalizer on the part of the pathname that requires normalization.196* This way we iterate through the whole pathname string only once.197*/198char* normalize(char* path) {199int n = (int)strlen(path);200int i;201char c = 0;202int prev = 0;203for (i = 0; i < n; i++) {204char c = path[i];205if (c == altSlash)206return normalizePath(path, n, (prev == slash) ? i - 1 : i);207if ((c == slash) && (prev == slash) && (i > 1))208return normalizePath(path, n, i - 1);209if ((c == ':') && (i > 1))210return normalizePath(path, n, 0);211prev = c;212}213if (prev == slash)214return normalizePath(path, n, n - 1);215return path;216}217218219/* -- Resolution - src/windows/classes/java/io/Win32FileSystem.java */220221222char* resolve(const char* parent, const char* child) {223char* c;224char* theChars;225int parentEnd, childStart, len;226227int pn = (int)strlen(parent);228int cn = (int)strlen(child);229230if (pn == 0) return (char*)child;231if (cn == 0) return (char*)parent;232233c = (char*)child;234childStart = 0;235parentEnd = pn;236237if ((cn > 1) && (c[0] == slash)) {238if (c[1] == slash) {239/* Drop prefix when child is a UNC pathname */240childStart = 2;241} else {242/* Drop prefix when child is drive-relative */243childStart = 1;244245}246if (cn == childStart) { // Child is double slash247if (parent[pn - 1] == slash) {248char* str = strdup(parent);249str[pn-1] = '\0';250return str;251}252return (char*)parent;253}254}255256if (parent[pn - 1] == slash)257parentEnd--;258259len = parentEnd + cn - childStart;260261if (child[childStart] == slash) {262theChars = (char*)malloc(len+1);263if (theChars == NULL) {264fprintf(stderr, "OOM error in native tmp buffer allocation");265return NULL;266}267memcpy(theChars, parent, parentEnd);268memcpy(theChars+parentEnd, child+childStart, (cn-childStart));269theChars[len] = '\0';270} else {271theChars = (char*)malloc(len+2);272if (theChars == NULL) {273fprintf(stderr, "OOM error in native tmp buffer allocation");274return NULL;275}276memcpy(theChars, parent, parentEnd);277theChars[parentEnd] = slash;278memcpy(theChars+parentEnd+1, child+childStart, (cn-childStart));279theChars[len+1] = '\0';280}281return theChars;282}283284285static int prefixLength(const char* path) {286char c0, c1;287288int n = (int)strlen(path);289if (n == 0) return 0;290c0 = path[0];291c1 = (n > 1) ? path[1] : 0;292if (c0 == slash) {293if (c1 == slash) return 2; /* Absolute UNC pathname "\\\\foo" */294return 1; /* Drive-relative "\\foo" */295}296if (isLetter(c0) && (c1 == ':')) {297if ((n > 2) && (path[2] == slash))298return 3; /* Absolute local pathname "z:\\foo" */299return 2; /* Directory-relative "z:foo" */300}301return 0; /* Completely relative */302}303304305int isAbsolute(const char* path) {306int pl = prefixLength(path);307return (((pl == 2) && (path[0] == slash)) || (pl == 3));308}309310311char* fromURIPath(const char* path) {312int start = 0;313int len = (int)strlen(path);314315if ((len > 2) && (path[2] == ':')) {316// "/c:/foo" --> "c:/foo"317start = 1;318// "c:/foo/" --> "c:/foo", but "c:/" --> "c:/"319if ((len > 3) && path[len-1] == '/')320len--;321} else if ((len > 1) && path[len-1] == '/') {322// "/foo/" --> "/foo"323len--;324}325326if (start == 0 && len == (int)strlen(path)) {327return (char*)path;328} else {329char* p = (char*)malloc(len+1);330if (p == NULL) {331fprintf(stderr, "OOM error in native tmp buffer allocation");332return NULL;333}334memcpy(p, path+start, len);335p[len] = '\0';336return p;337}338}339340341