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

Re: unexpected behavior of cp and mv



Apparently there is something wrong with the debian stretch utimensat system call, or with its interaction with cifs. It works as expected when the destination file is on a ext4 file system, but it does not work when the destination file is on a SMB file system.

I wrote a simple C program, which I compiled with <gcc -g -o x2 x2.c>.

On my debian buster workstation, I run the program using a script, which is:

#!/bin/bash
NAME='/mnt/u1/rw/receipt/test2.txt'
rm -f "${NAME}"
ls -ls "${NAME}"
/mnt/1g/home/u1/data/cp-pi/x2 "${NAME}"
ls -ls "${NAME}"
sleep 1
ls -ls "${NAME}"

Note that the /mnt/u1/rw/receipt is a SMB folder. I got this result:

$ ./do2.sh
ls: cannot access '/mnt/u1/rw/receipt/test2.txt': No such file or directory
0 -rwxr-xr-x 1 u1 u1 10 Feb  5  2017 /mnt/u1/rw/receipt/test2.txt
1024 -rwxr-xr-x 1 u1 u1 10 Apr 30 12:20 /mnt/u1/rw/receipt/test2.txt

As you can see, the time stamp changes after one second.

This is the C code for x2.

#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/syscall.h>

static char *data = "test data\n";
static struct timespec timestamps [2] = {
    { 1588174263, 908624390 },
    { 1486350336, 481422339 }
};

int main (int argc, char **argv)
{
    int fd;

    if (argc > 1) {
        fd = openat (AT_FDCWD, argv [1], O_WRONLY|O_CREAT, 0666);
        if (fd >= 0) {
            write (fd, data, strlen (data));
            /* do not use glibc utimensat directly, it does not allow NULL as a second argument */
            syscall (SYS_utimensat, fd, NULL, timestamps, 0);
            close (fd);
            return 0;
        }
    }
    printf ("something went wrong\n");
    return 0;
}

About my buster workstation:
# cat /proc/version;dpkg -l |grep cifs
Linux version 4.19.0-8-amd64 (debian-kernel@lists.debian.org) (gcc version 8.3.0 (Debian 8.3.0-6)) #1 SMP Debian 4.19.98-1+deb10u1 (2020-04-27)
ii cifs-utils 2:6.8-2 amd64 Common Internet File System utilities

I run the same binary and script on my debian stretch workstation, and got this:

$ ./do2.sh
ls: cannot access '/mnt/u1/rw/receipt/test2.txt': No such file or directory
0 -rwxr-xr-x 1 u1 u1 10 Feb  5  2017 /mnt/u1/rw/receipt/test2.txt
4 -rwxr-xr-x 1 u1 u1 10 Feb  5  2017 /mnt/u1/rw/receipt/test2.txt

$ cat /proc/version
Linux version 4.9.0-12-amd64 (debian-kernel@lists.debian.org) (gcc version 6.3.0 20170516 (Debian 6.3.0-18+deb9u1) ) #1 SMP Debian 4.9.210-1 (2020-01-20)
# dpkg -l |grep cifs
ii  cifs-utils 2:6.7-1 amd64 Common Internet File System utilities

I run the C program above, using the same binary, and got two different behaviors.

Can anyone help me with this?

On 4/29/20 5:31 PM, Thomas Schmitt wrote:
Hi,

assumed that the success of "touch" indicates that utimensat(2) works
fine, i would pick the failed fsetxattr(2) as next suspect.

Does this set the timestamps despite failing ?

setfattr -n user.test_name -v test_value /mnt/u1/rw/receipt/u1.crontab

(I expect an "Operation not supported" error as in strace.
If it succeeds against our will, try -n "test_name", without prefix
"user.".)


Alberto Sentieri wrote:
So, the cp behavior on debian stretch and buster seems to be the same.
But the implementation of the system calls is not.


touch does the trick of dup2 and close, before calling utimensat.
Hm. To verify suchtheories you will have to create a C program which
uses the traced system calls and by which you can test variations.

Quite interesting would be to inquire the file timestamps immediately
after utimensat() in order to learn whether it gets into effect at
least for a short time.


Have a nice day :)

Thomas




Reply to: