Message ID | 1294829822-27938-4-git-send-email-mjt@msgid.tls.msk.ru |
---|---|
State | New |
Headers | show |
Am 12.01.2011 11:57, schrieb Michael Tokarev: > Currently the two routines tries to "understand" and skip <protocol>: > prefix in path arguments are path_combine() and path_is_absolute() > (the latter isn't used anywhere but in the former). This is wrong, > since notion of absolute path is, at least, protocol-specific. > > The implementation is more wrong on windows where even non-absolute > paths but with drive name (d:foo) should be treated as absolute, as > in, one can't combine, say, c:\bar with d:foo forming c:\foo as > path_combine() currently does. > > Introduce isslash() macro that works correctly on both windows and > unix, use it in is_windows_drive_prefix() (since any form of slash > can be used in constructs like //./), You're saying that \/.\ is a valid format for it? Wow... > remove path_is_absolute() and > hardcode the trivial (but right) condition in path_combine(), and > simplify path_combine() further by removing <protocol>: handling > and unifying shash searching. > > Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> > --- > block.c | 72 +++++++++++++++++++++----------------------------------------- > 1 files changed, 25 insertions(+), 47 deletions(-) > > diff --git a/block.c b/block.c > index 42d6ff1..31a821d 100644 > --- a/block.c > +++ b/block.c > @@ -71,6 +71,9 @@ static BlockDriverState *bs_snapshots; > static int use_bdrv_whitelist; > > #ifdef _WIN32 > + > +#define isslash(c) ((c) == '/' || (c) == '\\') > + > static int is_windows_drive_prefix(const char *filename) > { > return (((filename[0] >= 'a' && filename[0] <= 'z') || > @@ -83,11 +86,17 @@ int is_windows_drive(const char *filename) > if (is_windows_drive_prefix(filename) && > filename[2] == '\0') > return 1; > - if (strstart(filename, "\\\\.\\", NULL) || > - strstart(filename, "//./", NULL)) > - return 1; > + if (isslash(filename[0] && isslash(filename[1]) && Missing bracket, doesn't even compile. > + filename[2] == '.' && isslash(filename[3])) > + return 1; /* special case: windows device "//./" */ Please add curly braces. > return 0; > } > + > +#else > + > +#define isslash(c) ((c) == '/') > +#define is_windows_drive_prefix(filename) (0) Please make this a function, for consistency and type checking. The compiler is going to inline it anyway. > + > #endif > > /* check if the path starts with "<protocol>:" > @@ -115,61 +124,30 @@ static char *path_has_protocol(const char *path) > (char*)p : NULL; > } > > -int path_is_absolute(const char *path) > -{ > - const char *p; > -#ifdef _WIN32 > - /* specific case for names like: "\\.\d:" */ > - if (*path == '/' || *path == '\\') > - return 1; > -#endif > - p = strchr(path, ':'); > - if (p) > - p++; > - else > - p = path; > -#ifdef _WIN32 > - return (*p == '/' || *p == '\\'); > -#else > - return (*p == '/'); > -#endif > -} > - > /* if filename is absolute, just copy it to dest. Otherwise, build a > - path to it by considering it is relative to base_path. URL are > - supported. */ > + path to it by considering it is relative to base_path. > + This is really about filenames not URLs - we don't support > + <protocol>: prefix in filename since it makes no sense, especially > + if the protocol in base_path is not the same as in filename. > + */ > void path_combine(char *dest, int dest_size, > const char *base_path, > const char *filename) > { > - const char *p, *p1; > + const char *p; > int len; > > if (dest_size <= 0) > return; > - if (path_is_absolute(filename)) { > + /* on windows, d:filename should be treated as absolute too */ > + if (isslash(filename[0]) || is_windows_drive_prefix(filename)) { > pstrcpy(dest, dest_size, filename); > } else { > - p = strchr(base_path, ':'); > - if (p) > - p++; > - else > - p = base_path; > - p1 = strrchr(base_path, '/'); > -#ifdef _WIN32 > - { > - const char *p2; > - p2 = strrchr(base_path, '\\'); > - if (!p1 || p2 > p1) > - p1 = p2; > - } > -#endif > - if (p1) > - p1++; > - else > - p1 = base_path; > - if (p1 > p) > - p = p1; > + /* find last slash */ > + p = base_path + strlen(base_path); > + while(p >= base_path && !isslash(*p)) > + --p; > + p++; Please add braces. > len = p - base_path; > if (len > dest_size - 1) > len = dest_size - 1; This changes the semantics to throw away the protocol. For example fat:foo combined with bar would have resulted in fat:bar previously and results in bar now. Probably not a problem. path_combine gets even worse if filename has a protocol. It's completely unclear what it's supposed to do with protocols anyway. Kevin
diff --git a/block.c b/block.c index 42d6ff1..31a821d 100644 --- a/block.c +++ b/block.c @@ -71,6 +71,9 @@ static BlockDriverState *bs_snapshots; static int use_bdrv_whitelist; #ifdef _WIN32 + +#define isslash(c) ((c) == '/' || (c) == '\\') + static int is_windows_drive_prefix(const char *filename) { return (((filename[0] >= 'a' && filename[0] <= 'z') || @@ -83,11 +86,17 @@ int is_windows_drive(const char *filename) if (is_windows_drive_prefix(filename) && filename[2] == '\0') return 1; - if (strstart(filename, "\\\\.\\", NULL) || - strstart(filename, "//./", NULL)) - return 1; + if (isslash(filename[0] && isslash(filename[1]) && + filename[2] == '.' && isslash(filename[3])) + return 1; /* special case: windows device "//./" */ return 0; } + +#else + +#define isslash(c) ((c) == '/') +#define is_windows_drive_prefix(filename) (0) + #endif /* check if the path starts with "<protocol>:" @@ -115,61 +124,30 @@ static char *path_has_protocol(const char *path) (char*)p : NULL; } -int path_is_absolute(const char *path) -{ - const char *p; -#ifdef _WIN32 - /* specific case for names like: "\\.\d:" */ - if (*path == '/' || *path == '\\') - return 1; -#endif - p = strchr(path, ':'); - if (p) - p++; - else - p = path; -#ifdef _WIN32 - return (*p == '/' || *p == '\\'); -#else - return (*p == '/'); -#endif -} - /* if filename is absolute, just copy it to dest. Otherwise, build a - path to it by considering it is relative to base_path. URL are - supported. */ + path to it by considering it is relative to base_path. + This is really about filenames not URLs - we don't support + <protocol>: prefix in filename since it makes no sense, especially + if the protocol in base_path is not the same as in filename. + */ void path_combine(char *dest, int dest_size, const char *base_path, const char *filename) { - const char *p, *p1; + const char *p; int len; if (dest_size <= 0) return; - if (path_is_absolute(filename)) { + /* on windows, d:filename should be treated as absolute too */ + if (isslash(filename[0]) || is_windows_drive_prefix(filename)) { pstrcpy(dest, dest_size, filename); } else { - p = strchr(base_path, ':'); - if (p) - p++; - else - p = base_path; - p1 = strrchr(base_path, '/'); -#ifdef _WIN32 - { - const char *p2; - p2 = strrchr(base_path, '\\'); - if (!p1 || p2 > p1) - p1 = p2; - } -#endif - if (p1) - p1++; - else - p1 = base_path; - if (p1 > p) - p = p1; + /* find last slash */ + p = base_path + strlen(base_path); + while(p >= base_path && !isslash(*p)) + --p; + p++; len = p - base_path; if (len > dest_size - 1) len = dest_size - 1;
Currently the two routines tries to "understand" and skip <protocol>: prefix in path arguments are path_combine() and path_is_absolute() (the latter isn't used anywhere but in the former). This is wrong, since notion of absolute path is, at least, protocol-specific. The implementation is more wrong on windows where even non-absolute paths but with drive name (d:foo) should be treated as absolute, as in, one can't combine, say, c:\bar with d:foo forming c:\foo as path_combine() currently does. Introduce isslash() macro that works correctly on both windows and unix, use it in is_windows_drive_prefix() (since any form of slash can be used in constructs like //./), remove path_is_absolute() and hardcode the trivial (but right) condition in path_combine(), and simplify path_combine() further by removing <protocol>: handling and unifying shash searching. Signed-off-by: Michael Tokarev <mjt@tls.msk.ru> --- block.c | 72 +++++++++++++++++++++----------------------------------------- 1 files changed, 25 insertions(+), 47 deletions(-)