qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 2/4] added missing file commands (attributes, deleti


From: itamar . tal4
Subject: [Qemu-devel] [PATCH 2/4] added missing file commands (attributes, deletion)
Date: Tue, 31 Mar 2015 11:34:35 +0300

From: Itamar Tal <address@hidden>

This patch add support for retrieving file attributes and file deletion by
file name, to get a more complete file functionality over the guest agent.

---
 qga/commands-posix.c |  23 +++++++++
 qga/commands-win32.c | 139 +++++++++++++++++++++++++++++++++++++++++++++++++++
 qga/commands.c       |   8 +++
 qga/qapi-schema.json |  42 ++++++++++++++++
 4 files changed, 212 insertions(+)

diff --git a/qga/commands-posix.c b/qga/commands-posix.c
index ba8de62..028d533 100644
--- a/qga/commands-posix.c
+++ b/qga/commands-posix.c
@@ -7,6 +7,9 @@
  *  Michael Roth      <address@hidden>
  *  Michal Privoznik  <address@hidden>
  *
+ * Changes (address@hidden):
+ * - file attributes, removal, hashes
+ *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
  */
@@ -2456,3 +2459,23 @@ void ga_command_state_init(GAState *s, GACommandState 
*cs)
 #endif
     ga_command_state_add(cs, guest_file_init, NULL);
 }
+
+GuestFileAttributes *qmp_guest_file_attributes(const char *path, Error **errp)
+{
+    GuestFileAttributes *file_stat = g_malloc0(sizeof(GuestFileAttributes));
+    struct stat file_os_stat;
+
+    if (stat(path, &file_os_stat)) {
+        error_setg(errp, "Failed to get file attributes for '%s' (error %d)",
+                   path, errno);
+        return NULL;
+    }
+
+    file_stat->mode = file_os_stat.st_mode;
+    file_stat->size = file_os_stat.st_size;
+    file_stat->access_time = file_os_stat.st_atime;
+    file_stat->modification_time = file_os_stat.st_mtime;
+    file_stat->creation_time = 0; /* not all Linux FS store file BoD */
+
+    return file_stat;
+}
diff --git a/qga/commands-win32.c b/qga/commands-win32.c
index 3ef0549..aeb49c5 100644
--- a/qga/commands-win32.c
+++ b/qga/commands-win32.c
@@ -7,6 +7,9 @@
  *  Michael Roth      <address@hidden>
  *  Gal Hammer        <address@hidden>
  *
+ * Changes (address@hidden):
+ * - file attributes, removal, hashes
+ *
  * This work is licensed under the terms of the GNU GPL, version 2 or later.
  * See the COPYING file in the top-level directory.
  */
@@ -742,3 +745,139 @@ void ga_command_state_init(GAState *s, GACommandState *cs)
     }
     ga_command_state_add(cs, guest_file_init, NULL);
 }
+
+/* The CRT of Windows has a number of flaws wrt. its stat() implementation:
+   - time stamps are restricted to second resolution
+   - file modification times suffer from forth-and-back conversions between
+     UTC and local time
+   Therefore, we implement our own stat, based on the Win32 API directly.
+*/
+
+/* Seconds between 1.1.1601 and 1.1.1970 */
+static __int64 secs_between_epochs = 11644473600;
+
+static void
+FILE_TIME_to_time_t_nsec(FILETIME *in_ptr, time_t *time_out, int* nsec_out)
+{
+    /* XXX endianness. Shouldn't matter, as all Windows implementations are
+    little-endian */
+    /* Cannot simply cast and dereference in_ptr,
+       since it might not be aligned properly */
+    __int64 in;
+    memcpy(&in, in_ptr, sizeof(in));
+    *nsec_out = (int)(in % 10000000) * 100; /* FILETIME is in units of 100
+                                            nsec. */
+    *time_out = (time_t)((in / 10000000) - secs_between_epochs);
+}
+
+static int
+attributes_to_mode(DWORD attr)
+{
+    int m = 0;
+    if (0 != (attr & FILE_ATTRIBUTE_DIRECTORY)) {
+        m |= _S_IFDIR | 0111; /* IFEXEC for user,group,other */
+    } else {
+        m |= _S_IFREG;
+    }
+    if (0 != (attr & FILE_ATTRIBUTE_READONLY)) {
+        m |= 0444;
+    } else {
+        m |= 0666;
+    }
+    return m;
+}
+
+static int
+attribute_data_to_stat(WIN32_FILE_ATTRIBUTE_DATA *info,
+                       GuestFileAttributes *result)
+{
+    int nsec = 0;
+
+    memset(result, 0, sizeof(*result));
+    result->mode = attributes_to_mode(info->dwFileAttributes);
+    result->size = (((__int64)info->nFileSizeHigh)<<32) + info->nFileSizeLow;
+    FILE_TIME_to_time_t_nsec(&info->ftCreationTime,
+                             (time_t *)&result->creation_time, &nsec);
+    FILE_TIME_to_time_t_nsec(&info->ftLastWriteTime,
+                             (time_t *)&result->modification_time, &nsec);
+    FILE_TIME_to_time_t_nsec(&info->ftLastAccessTime,
+                             (time_t *)&result->access_time, &nsec);
+
+    return 0;
+}
+
+static BOOL
+attributes_from_dir(LPCSTR pszFile, LPWIN32_FILE_ATTRIBUTE_DATA pfad)
+{
+    HANDLE hFindFile;
+    WIN32_FIND_DATAA FileData;
+    hFindFile = FindFirstFileA(pszFile, &FileData);
+    if (hFindFile == INVALID_HANDLE_VALUE) {
+        return FALSE;
+    }
+    (void)FindClose(hFindFile);
+    pfad->dwFileAttributes = FileData.dwFileAttributes;
+    pfad->ftCreationTime   = FileData.ftCreationTime;
+    pfad->ftLastAccessTime = FileData.ftLastAccessTime;
+    pfad->ftLastWriteTime  = FileData.ftLastWriteTime;
+    pfad->nFileSizeHigh    = FileData.nFileSizeHigh;
+    pfad->nFileSizeLow     = FileData.nFileSizeLow;
+    return TRUE;
+}
+
+/* based upon Python implementation of windows file stat() */
+GuestFileAttributes *qmp_guest_file_attributes(const char *path, Error **errp)
+{
+    WIN32_FILE_ATTRIBUTE_DATA info;
+    int code;
+    char *dot = NULL;
+    GuestFileAttributes *result = NULL;
+
+    if (!GetFileAttributesExA(path, GetFileExInfoStandard, &info)) {
+        if (GetLastError() != ERROR_SHARING_VIOLATION) {
+            error_setg(errp, "Failed querying '%s' for attributes (error %d)",
+                       path, (int)GetLastError());
+            /* Protocol violation: we explicitly clear errno, instead of
+               setting it to a POSIX error. Callers should use GetLastError. */
+            errno = 0;
+            return NULL;
+        } else {
+            /* Could not get attributes on open file. Fall back to
+               reading the directory. */
+            if (!attributes_from_dir(path, &info)) {
+                error_setg(errp, "Error querying '%s' attributes (error %d)",
+                           path, (int)GetLastError());
+                /* Very strange. This should not fail now */
+                errno = 0;
+                return NULL;
+            }
+        }
+    }
+
+    result = g_malloc(sizeof(GuestFileAttributes));
+    if (NULL == result) {
+        error_setg(errp, "No memory for attributes result for '%s' (error %d)",
+                   path, errno);
+        return NULL;
+    }
+
+    code = attribute_data_to_stat(&info, result);
+    if (code != 0) {
+        g_free(result);
+        error_setg(errp, "Error converting attributes result '%s' (code %d)",
+                   path, code);
+        return NULL;
+    }
+    /* Set S_IFEXEC if it is an .exe, .bat, ... */
+    dot = strrchr(path, '.');
+    if (dot) {
+        if (stricmp(dot, ".bat") == 0 ||
+            stricmp(dot, ".cmd") == 0 ||
+            stricmp(dot, ".exe") == 0 ||
+            stricmp(dot, ".com") == 0) {
+            result->mode |= 0111;
+        }
+    }
+    return result;
+}
+
diff --git a/qga/commands.c b/qga/commands.c
index f9378f4..64404d6 100644
--- a/qga/commands.c
+++ b/qga/commands.c
@@ -113,3 +113,11 @@ char *qmp_guest_file_hash(const char *path, Error **errp)
 
     return g_strdup((char *)sha256_hexdigest);
 }
+
+void qmp_guest_file_remove(const char *path, Error **errp)
+{
+    if (unlink(path)) {
+        error_setg(errp, "Error deleting file '%s' (error %d)", path, errno);
+        errno = 0;
+    }
+}
diff --git a/qga/qapi-schema.json b/qga/qapi-schema.json
index 68b420d..cc670b2 100644
--- a/qga/qapi-schema.json
+++ b/qga/qapi-schema.json
@@ -904,3 +904,45 @@
 { 'command': 'guest-file-hash',
   'data': { 'path': 'str' },
   'returns': 'str' }
+
+##
+# @GuestFileAttributes
+#
+# @mode: file access permissions mode
+# @size: file size in bytes
+# @access-time: file last access time
+# @modification-time: file last modification time
+# @creation-time: file creation time (when possible)
+#
+# Since: 2.4
+##
+{ 'type': 'GuestFileAttributes',
+  'data': {'mode': 'int', 'size': 'uint64', 'access-time': 'int',
+           'modification-time': 'int', 'creation-time': 'int'
+          }}
+
+##
+# @guest-file-attributes:
+#
+# Get file attributes for a file in the guest's operating system
+# for a given file path
+#
+# Returns: file attributes structure (GuestFileAttributes type)
+#
+# Since 2.4
+##
+{ 'command': 'guest-file-attributes',
+  'data': { 'path': 'str' },
+  'returns': 'GuestFileAttributes'}
+
+##
+# @guest-file-remove:
+#
+# Remove a file in the guest's operating system for a given file path
+#
+# Returns:
+#
+# Since 2.4
+##
+{ 'command': 'guest-file-remove',
+  'data': { 'path': 'str' }}
-- 
2.3.4




reply via email to

[Prev in Thread] Current Thread [Next in Thread]